-
Notifications
You must be signed in to change notification settings - Fork 360
feat: web-ext automatically checks for updates #676
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f3d017f
40f2e64
95e2921
6380103
6f22604
9c903f1
1316d7d
0ba8c14
5973f28
7602131
4088d49
79cf3be
09da85a
336d0b6
fe962f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,10 +9,14 @@ import defaultCommands from './cmd'; | |
import {UsageError} from './errors'; | ||
import {createLogger, consoleStream as defaultLogStream} from './util/logger'; | ||
import {coerceCLICustomPreference} from './firefox/preferences'; | ||
import {checkForUpdates as defaultUpdateChecker} from './util/updates'; | ||
|
||
const log = createLogger(__filename); | ||
const envPrefix = 'WEB_EXT'; | ||
|
||
type ProgramOptions = {| | ||
absolutePackageDir?: string, | ||
|} | ||
|
||
/* | ||
* The command line program. | ||
|
@@ -24,7 +28,9 @@ export class Program { | |
|
||
constructor( | ||
argv: ?Array<string>, | ||
{absolutePackageDir = process.cwd()}: {absolutePackageDir?: string} = {} | ||
{ | ||
absolutePackageDir = process.cwd(), | ||
}: ProgramOptions = {} | ||
) { | ||
// This allows us to override the process argv which is useful for | ||
// testing. | ||
|
@@ -84,8 +90,9 @@ export class Program { | |
async execute( | ||
absolutePackageDir: string, | ||
{ | ||
systemProcess = process, logStream = defaultLogStream, | ||
getVersion = defaultVersionGetter, shouldExitProgram = true, | ||
checkForUpdates = defaultUpdateChecker, systemProcess = process, | ||
logStream = defaultLogStream, getVersion = defaultVersionGetter, | ||
shouldExitProgram = true, globalEnv = WEBEXT_BUILD_ENV, | ||
}: Object = {} | ||
): Promise<void> { | ||
|
||
|
@@ -112,7 +119,14 @@ export class Program { | |
if (!runCommand) { | ||
throw new UsageError(`Unknown command: ${cmd}`); | ||
} | ||
if (globalEnv === 'production') { | ||
checkForUpdates ({ | ||
version: getVersion(absolutePackageDir), | ||
}); | ||
} | ||
|
||
await runCommand(argv); | ||
|
||
} catch (error) { | ||
const prefix = cmd ? `${cmd}: ` : ''; | ||
if (!(error instanceof UsageError) || argv.verbose) { | ||
|
@@ -138,14 +152,14 @@ declare var WEBEXT_BUILD_ENV: string; | |
|
||
//A defintion of type of argument for defaultVersionGetter | ||
type versionGetterOptions = { | ||
localEnv?: string, | ||
globalEnv?: string, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks :) |
||
}; | ||
|
||
export function defaultVersionGetter( | ||
absolutePackageDir: string, | ||
{localEnv = WEBEXT_BUILD_ENV}: versionGetterOptions = {} | ||
{globalEnv = WEBEXT_BUILD_ENV}: versionGetterOptions = {} | ||
): string { | ||
if (localEnv === 'production') { | ||
if (globalEnv === 'production') { | ||
log.debug('Getting the version from package.json'); | ||
const packageData: any = readFileSync( | ||
path.join(absolutePackageDir, 'package.json')); | ||
|
@@ -164,7 +178,9 @@ export function main( | |
runOptions = {}, | ||
}: Object = {} | ||
): Promise<any> { | ||
|
||
const program = new Program(argv, {absolutePackageDir}); | ||
|
||
// yargs uses magic camel case expansion to expose options on the | ||
// final argv object. For example, the 'artifacts-dir' option is alternatively | ||
// available as argv.artifactsDir. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* @flow */ | ||
import defaultUpdateNotifier from 'update-notifier'; | ||
|
||
type checkForUpdatesParams = {| | ||
version: string, | ||
updateNotifier?: typeof defaultUpdateNotifier, | ||
|}; | ||
|
||
export function checkForUpdates( | ||
{ | ||
version, | ||
updateNotifier = defaultUpdateNotifier, | ||
}: checkForUpdatesParams | ||
) { | ||
const pkg = {name: 'web-ext', version}; | ||
|
||
updateNotifier({ | ||
pkg, | ||
updateCheckInterval: 1000 * 60 * 60 * 24 * 3, // 3 days, | ||
}).notify(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* @flow */ | ||
import {it, describe} from 'mocha'; | ||
import {assert} from 'chai'; | ||
import sinon from 'sinon'; | ||
|
||
import {checkForUpdates} from '../../../src/util/updates'; | ||
|
||
describe('util/updates', () => { | ||
describe('checkForUpdates()', () => { | ||
it('calls the notifier with the correct parameters', () => { | ||
const updateNotifierStub = sinon.spy(() => { | ||
return { | ||
notify: sinon.spy(), | ||
}; | ||
}); | ||
|
||
checkForUpdates({ | ||
version: '1.0.0', | ||
updateNotifier: updateNotifierStub, | ||
}); | ||
assert.equal(updateNotifierStub.called, true); | ||
assert.equal(updateNotifierStub.firstCall.args[0].pkg.name, 'web-ext'); | ||
assert.equal(updateNotifierStub.firstCall.args[0].pkg.version, '1.0.0'); | ||
assert.isNumber(updateNotifierStub.firstCall.args[0].updateCheckInterval); | ||
assert.equal(updateNotifierStub.firstCall.args[0].updateCheckInterval, | ||
1000 * 60 * 60 * 24 * 3); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ describe('program.Program', () => { | |
const absolutePackageDir = path.join(__dirname, '..', '..'); | ||
return program.execute( | ||
absolutePackageDir, { | ||
getVersion: () => spy(), | ||
checkForUpdates: spy(), | ||
systemProcess: fakeProcess, | ||
shouldExitProgram: false, | ||
...options, | ||
|
@@ -176,7 +178,10 @@ describe('program.Program', () => { | |
}); | ||
program.command('thing', 'does a thing', () => {}); | ||
|
||
return execProgram(program, {getVersion: spy(), logStream}) | ||
return execProgram(program, { | ||
getVersion: spy(), | ||
logStream, | ||
}) | ||
.then(() => { | ||
assert.equal(logStream.makeVerbose.called, true); | ||
}); | ||
|
@@ -241,13 +246,50 @@ describe('program.Program', () => { | |
}); | ||
}); | ||
|
||
it('checks for updates automatically', () => { | ||
const handler = spy(); | ||
const getVersion = () => 'some-package-version'; | ||
const checkForUpdates = sinon.stub(); | ||
const program = new Program(['run']) | ||
.command('run', 'some command', handler); | ||
return execProgram(program, { | ||
checkForUpdates, | ||
getVersion, | ||
globalEnv: 'production', | ||
}) | ||
.then(() => { | ||
assert.equal(checkForUpdates.firstCall.args[0].version, | ||
'some-package-version'); | ||
}); | ||
}); | ||
|
||
it('does not check for updates during development', () => { | ||
const handler = spy(); | ||
const getVersion = () => 'some-package-version'; | ||
const checkForUpdates = sinon.stub(); | ||
const program = new Program(['run']) | ||
.command('run', 'some command', handler); | ||
return execProgram(program, { | ||
checkForUpdates, | ||
getVersion, | ||
globalEnv: 'development', | ||
}) | ||
.then(() => { | ||
assert.equal(checkForUpdates.called, false); | ||
}); | ||
}); | ||
}); | ||
|
||
|
||
describe('program.main', () => { | ||
|
||
function execProgram(argv, {projectRoot = '', ...mainOptions}: Object = {}) { | ||
const runOptions = {shouldExitProgram: false, systemProcess: fake(process)}; | ||
const runOptions = { | ||
getVersion: () => 'not-a-real-version', | ||
checkForUpdates: spy(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since no assertions are made in these tests, you could just assign it as a |
||
shouldExitProgram: false, | ||
systemProcess: fake(process), | ||
}; | ||
return main(projectRoot, {argv, runOptions, ...mainOptions}); | ||
} | ||
|
||
|
@@ -351,15 +393,15 @@ describe('program.defaultVersionGetter', () => { | |
const pkgFile = path.join(root, 'package.json'); | ||
return fs.readFile(pkgFile) | ||
.then((pkgData) => { | ||
const testBuildEnv = {localEnv: 'production'}; | ||
const testBuildEnv = {globalEnv: 'production'}; | ||
assert.equal(defaultVersionGetter(root, testBuildEnv), | ||
JSON.parse(pkgData).version); | ||
}); | ||
}); | ||
|
||
it('returns git commit information in development', () => { | ||
const commit = `${git.branch()}-${git.long()}`; | ||
const testBuildEnv = {localEnv: 'development'}; | ||
const testBuildEnv = {globalEnv: 'development'}; | ||
assert.equal(defaultVersionGetter(root, testBuildEnv), | ||
commit); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
similarly, this module / class should be set up for dependency injection so that you can replace the update utility with a stub for testing:
The test can then use a stub: