diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa9debf..208c1a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,6 @@ jobs: - '18.20' os: - macos-latest - - ubuntu-latest - windows-latest runs-on: '${{ matrix.os }}' steps: diff --git a/package.json b/package.json index 16d83e0..58f792c 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,9 @@ "publishConfig": { "provenance": true }, - "dependencies": { - "github-url-to-object": "^4.0.4", - "ms": "^2.1.1" - }, "devDependencies": { "@eslint/js": "^9.15.0", - "@types/github-url-to-object": "^4.0.1", "@types/jest": "^29.5.14", - "@types/ms": "^0.7.31", "@types/node": "^22.10.1", "electron": "^35.7.5", "eslint": "^9.15.0", diff --git a/src/index.ts b/src/index.ts index 1ef2901..c251355 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,3 @@ -import ms from 'ms'; -import gh from 'github-url-to-object'; - import assert from 'node:assert'; import fs from 'node:fs'; import os from 'node:os'; @@ -91,10 +88,11 @@ export interface IUpdateElectronAppOptions { readonly host?: string; readonly updateSource?: IUpdateSource; /** - * @param {String} updateInterval How frequently to check for updates. Defaults to `10 minutes`. - * Minimum allowed interval is `5 minutes`. + * @param {Number} updateInterval How frequently to check for updates, in milliseconds. + * Defaults to `600000` (10 minutes). + * Minimum allowed interval is `300000` (5 minutes). */ - readonly updateInterval?: string; + readonly updateInterval?: number; /** * @param {Object} logger A custom logger object that defines a `log` function. * Defaults to `console`. See electron-log, a module @@ -245,7 +243,7 @@ function initUpdater(opts: ReturnType) { autoUpdater.checkForUpdates(); setInterval(() => { autoUpdater.checkForUpdates(); - }, ms(updateInterval)); + }, updateInterval); } /** @@ -286,16 +284,21 @@ export function makeUserNotifier(dialogProps?: IUpdateDialogStrings): (info: IUp function guessRepo() { const pkgBuf = fs.readFileSync(path.join(app.getAppPath(), 'package.json')); const pkg = JSON.parse(pkgBuf.toString()); - const repoString = pkg.repository?.url || pkg.repository; - const repoObject = gh(repoString); - assert(repoObject, "repo not found. Add repository string to your app's package.json file"); - return `${repoObject.user}/${repoObject.repo}`; + const repoString: string = pkg.repository?.url || pkg.repository; + assert(repoString, "repo not found. Add repository string to your app's package.json file"); + + // Matches owner/repo from GitHub URLs, git@ SSH URLs, or shorthand notation + const match = repoString.match( + /(?:github\.com[/:]|^github:|^)([\w-]+)\/([\w-.]+?)(?:\.git)?(?:[/#]|$)/, + ); + assert(match, "repo not found. Add repository string to your app's package.json file"); + return `${match[1]}/${match[2]}`; } function validateInput(opts: IUpdateElectronAppOptions) { const defaults = { host: 'https://update.electronjs.org', - updateInterval: '10 minutes', + updateInterval: 10 * 60 * 1000, logger: console, notifyUser: true, }; @@ -340,12 +343,12 @@ function validateInput(opts: IUpdateElectronAppOptions) { } assert( - typeof updateInterval === 'string' && updateInterval.match(/^\d+/), - 'updateInterval must be a human-friendly string interval like `20 minutes`', + typeof updateInterval === 'number' && updateInterval > 0, + 'updateInterval must be a positive number of milliseconds', ); - assert(ms(updateInterval) >= 5 * 60 * 1000, 'updateInterval must be `5 minutes` or more'); - assert(ms(updateInterval) < 2 ** 31, 'updateInterval must fit in a signed 32-bit integer'); + assert(updateInterval >= 5 * 60 * 1000, 'updateInterval must be `5 minutes` or more'); + assert(updateInterval < 2 ** 31, 'updateInterval must fit in a signed 32-bit integer'); assert(logger && typeof logger.log, 'function'); diff --git a/test/index.test.ts b/test/index.test.ts index f45de9b..b7fac8a 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -44,6 +44,34 @@ describe('updateElectronApp', () => { updateElectronApp(); }); + it.each([ + ['owner/repo', 'owner/repo'], + ['https://github.com/owner/repo', 'owner/repo'], + ['https://github.com/owner/repo.git', 'owner/repo'], + ['git+https://github.com/owner/repo.git', 'owner/repo'], + ['git@github.com:owner/repo.git', 'owner/repo'], + ['github:owner/repo', 'owner/repo'], + ['https://github.com/owner/my-repo.js', 'owner/my-repo.js'], + ['https://github.com/owner/my_repo', 'owner/my_repo'], + ])('parses repo from %s', (repository, expected) => { + fs.writeFileSync(packageJson, JSON.stringify({ repository })); + const logSpy = jest.spyOn(console, 'log').mockImplementation(); + updateElectronApp(); + expect(logSpy).toHaveBeenCalledWith('feedURL', expect.stringContaining(`/${expected}/`)); + logSpy.mockRestore(); + }); + + it.each([['https://github.com/owner/repo'], ['https://github.com/owner/repo.git']])( + 'parses repo from repository.url: %s', + (url) => { + fs.writeFileSync(packageJson, JSON.stringify({ repository: { url } })); + const logSpy = jest.spyOn(console, 'log').mockImplementation(); + updateElectronApp(); + expect(logSpy).toHaveBeenCalledWith('feedURL', expect.stringContaining('/owner/repo/')); + logSpy.mockRestore(); + }, + ); + afterAll(() => { fs.rmSync(packageJson); }); @@ -69,7 +97,7 @@ describe('updateElectronApp', () => { describe('updateInterval', () => { it('must be 5 minutes or more', () => { expect(() => { - updateElectronApp({ repo, updateInterval: '20 seconds' }); + updateElectronApp({ repo, updateInterval: 20_000 }); }).toThrow('updateInterval must be `5 minutes` or more'); }); }); diff --git a/yarn.lock b/yarn.lock index 8d34ac4..db06720 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1238,13 +1238,6 @@ __metadata: languageName: node linkType: hard -"@types/github-url-to-object@npm:^4.0.1": - version: 4.0.1 - resolution: "@types/github-url-to-object@npm:4.0.1" - checksum: 10c0/ee883cae1fac4594e6809e2c4220ce9d28103fcdc93176183e074b40e68dba4f265a95af738bd161fd7457926a173d5604dcf8398c7bdaa3ae663f2b38710fc0 - languageName: node - linkType: hard - "@types/graceful-fs@npm:^4.1.3": version: 4.1.5 resolution: "@types/graceful-fs@npm:4.1.5" @@ -1312,13 +1305,6 @@ __metadata: languageName: node linkType: hard -"@types/ms@npm:^0.7.31": - version: 0.7.31 - resolution: "@types/ms@npm:0.7.31" - checksum: 10c0/19fae4f587651e8761c76a0c72ba8af1700d37054476878d164b758edcc926f4420ed06037a1a7fdddc1dbea25265895d743c8b2ea44f3f3f7ac06c449b9221e - languageName: node - linkType: hard - "@types/node@npm:*, @types/node@npm:^22.10.1, @types/node@npm:^22.7.7": version: 22.18.0 resolution: "@types/node@npm:22.18.0" @@ -2805,15 +2791,6 @@ __metadata: languageName: node linkType: hard -"github-url-to-object@npm:^4.0.4": - version: 4.0.4 - resolution: "github-url-to-object@npm:4.0.4" - dependencies: - is-url: "npm:^1.1.0" - checksum: 10c0/1987e52dbc75e5d34dbf8e19104640d375b0dbf91e205aee95302256fe9c0ff4615e3b9ce3b6e7439bb1feb0463fd7605e5303b45f1c0e8c5faf2e5e5dab1393 - languageName: node - linkType: hard - "glob-parent@npm:^5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -3190,13 +3167,6 @@ __metadata: languageName: node linkType: hard -"is-url@npm:^1.1.0": - version: 1.2.4 - resolution: "is-url@npm:1.2.4" - checksum: 10c0/0157a79874f8f95fdd63540e3f38c8583c2ef572661cd0693cda80ae3e42dfe8e9a4a972ec1b827f861d9a9acf75b37f7d58a37f94a8a053259642912c252bc3 - languageName: node - linkType: hard - "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -4235,7 +4205,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:2.1.2, ms@npm:^2.1.1": +"ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc @@ -5389,19 +5359,15 @@ __metadata: resolution: "update-electron-app@workspace:." dependencies: "@eslint/js": "npm:^9.15.0" - "@types/github-url-to-object": "npm:^4.0.1" "@types/jest": "npm:^29.5.14" - "@types/ms": "npm:^0.7.31" "@types/node": "npm:^22.10.1" electron: "npm:^35.7.5" eslint: "npm:^9.15.0" eslint-config-prettier: "npm:^9.1.0" - github-url-to-object: "npm:^4.0.4" globals: "npm:^15.13.0" husky: "npm:^9.1.7" jest: "npm:^29.0.0" lint-staged: "npm:^16.4.0" - ms: "npm:^2.1.1" prettier: "npm:^3.0.3" ts-jest: "npm:^29.2.5" typescript: "npm:^5.7.2"