diff --git a/.gitattributes b/.gitattributes index 391f0a4..6313b56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -* text=auto -*.js text eol=lf +* text=auto eol=lf diff --git a/.travis.yml b/.travis.yml index 97519af..f3fa8cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ language: node_js node_js: - - '6' - - '4' + - '10' + - '8' diff --git a/check.js b/check.js index 521f84a..1d0eee8 100644 --- a/check.js +++ b/check.js @@ -6,7 +6,9 @@ const options = JSON.parse(process.argv[2]); updateNotifier = new updateNotifier.UpdateNotifier(options); -updateNotifier.checkNpm().then(update => { +(async () => { + const update = await updateNotifier.checkNpm(); + // Only update the last update check time on success updateNotifier.config.set('lastUpdateCheck', Date.now()); @@ -14,9 +16,10 @@ updateNotifier.checkNpm().then(update => { updateNotifier.config.set('update', update); } - // Call process exit explicitly to terminate the child process - // Otherwise the child process will run forever, according to the Node.js docs + // Call process exit explicitly to terminate the child process, + // otherwise the child process will run forever, according to the Node.js docs process.exit(); -}).catch(() => { +})().catch(error => { + console.error(error); process.exit(1); }); diff --git a/index.js b/index.js index 38ff01e..95075e4 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ 'use strict'; -const spawn = require('child_process').spawn; +const {spawn} = require('child_process'); const path = require('path'); -const format = require('util').format; +const {format} = require('util'); const importLazy = require('import-lazy')(require); const configstore = importLazy('configstore'); @@ -13,11 +13,11 @@ const isInstalledGlobally = importLazy('is-installed-globally'); const boxen = importLazy('boxen'); const xdgBasedir = importLazy('xdg-basedir'); const isCi = importLazy('is-ci'); + const ONE_DAY = 1000 * 60 * 60 * 24; class UpdateNotifier { - constructor(options) { - options = options || {}; + constructor(options = {}) { this.options = options; options.pkg = options.pkg || {}; @@ -38,7 +38,7 @@ class UpdateNotifier { this.hasCallback = typeof options.callback === 'function'; this.callback = options.callback || (() => {}); this.disabled = 'NO_UPDATE_NOTIFIER' in process.env || - process.argv.indexOf('--no-update-notifier') !== -1 || + process.argv.includes('--no-update-notifier') || isCi(); this.shouldNotifyInNpmScript = options.shouldNotifyInNpmScript; @@ -51,25 +51,31 @@ class UpdateNotifier { // after the set interval, so not to bother users right away lastUpdateCheck: Date.now() }); - } catch (err) { + } catch (error) { // Expecting error code EACCES or EPERM - const msg = + const message = chalk().yellow(format(' %s update check failed ', options.pkg.name)) + format('\n Try running with %s or get access ', chalk().cyan('sudo')) + '\n to the local update config store via \n' + chalk().cyan(format(' sudo chown -R $USER:$(id -gn $USER) %s ', xdgBasedir().config)); process.on('exit', () => { - console.error('\n' + boxen()(msg, {align: 'center'})); + console.error('\n' + boxen()(message, {align: 'center'})); }); } } } + check() { if (this.hasCallback) { - this.checkNpm() - .then(update => this.callback(null, update)) - .catch(err => this.callback(err)); + (async () => { + try { + this.callback(null, await this.checkNpm()); + } catch (error) { + this.callback(error); + } + })(); + return; } @@ -98,28 +104,33 @@ class UpdateNotifier { stdio: 'ignore' }).unref(); } - checkNpm() { - return latestVersion()(this.packageName).then(latestVersion => { - return { - latest: latestVersion, - current: this.packageVersion, - type: semverDiff()(this.packageVersion, latestVersion) || 'latest', - name: this.packageName - }; - }); + + async checkNpm() { + const latest = await latestVersion()(this.packageName); + + return { + latest, + current: this.packageVersion, + type: semverDiff()(this.packageVersion, latest) || 'latest', + name: this.packageName + }; } - notify(opts) { - const suppressForNpm = !this.shouldNotifyInNpmScript && isNpm(); + + notify(options) { + const suppressForNpm = !this.shouldNotifyInNpmScript && isNpm().isNpm; if (!process.stdout.isTTY || suppressForNpm || !this.update) { return this; } - opts = Object.assign({isGlobal: isInstalledGlobally()}, opts); + options = { + isGlobal: isInstalledGlobally(), + ...options + }; - opts.message = opts.message || 'Update available ' + chalk().dim(this.update.current) + chalk().reset(' → ') + - chalk().green(this.update.latest) + ' \nRun ' + chalk().cyan('npm i ' + (opts.isGlobal ? '-g ' : '') + this.packageName) + ' to update'; + options.message = options.message || 'Update available ' + chalk().dim(this.update.current) + chalk().reset(' → ') + + chalk().green(this.update.latest) + ' \nRun ' + chalk().cyan('npm i ' + (options.isGlobal ? '-g ' : '') + this.packageName) + ' to update'; - opts.boxenOpts = opts.boxenOpts || { + options.boxenOpts = options.boxenOpts || { padding: 1, margin: 1, align: 'center', @@ -127,9 +138,9 @@ class UpdateNotifier { borderStyle: 'round' }; - const message = '\n' + boxen()(opts.message, opts.boxenOpts); + const message = '\n' + boxen()(options.message, options.boxenOpts); - if (opts.defer === false) { + if (options.defer === false) { console.error(message); } else { process.on('exit', () => { diff --git a/package.json b/package.json index dc820a3..36433f5 100644 --- a/package.json +++ b/package.json @@ -1,55 +1,55 @@ { - "name": "update-notifier", - "version": "2.5.0", - "description": "Update notifications for your CLI app", - "license": "BSD-2-Clause", - "repository": "yeoman/update-notifier", - "author": { - "name": "Sindre Sorhus", - "email": "sindresorhus@gmail.com", - "url": "https://sindresorhus.com" - }, - "engines": { - "node": ">=4" - }, - "scripts": { - "test": "xo && ava --timeout=20s" - }, - "files": [ - "index.js", - "check.js" - ], - "keywords": [ - "npm", - "update", - "updater", - "notify", - "notifier", - "check", - "checker", - "cli", - "module", - "package", - "version" - ], - "dependencies": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "devDependencies": { - "ava": "*", - "clear-module": "^2.1.0", - "fixture-stdout": "^0.2.1", - "mock-require": "^2.0.2", - "strip-ansi": "^4.0.0", - "xo": "^0.18.2" - } + "name": "update-notifier", + "version": "2.5.0", + "description": "Update notifications for your CLI app", + "license": "BSD-2-Clause", + "repository": "yeoman/update-notifier", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "https://sindresorhus.com" + }, + "engines": { + "node": ">=8" + }, + "scripts": { + "test": "xo && ava --timeout=20s" + }, + "files": [ + "index.js", + "check.js" + ], + "keywords": [ + "npm", + "update", + "updater", + "notify", + "notifier", + "check", + "checker", + "cli", + "module", + "package", + "version" + ], + "dependencies": { + "boxen": "^3.0.0", + "chalk": "^2.0.1", + "configstore": "^4.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^3.0.0", + "latest-version": "^5.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "devDependencies": { + "ava": "^1.3.1", + "clear-module": "^3.1.0", + "fixture-stdout": "^0.2.1", + "mock-require": "^3.0.3", + "strip-ansi": "^5.2.0", + "xo": "^0.24.0" + } } diff --git a/readme.md b/readme.md index 55800fc..62f9b9e 100644 --- a/readme.md +++ b/readme.md @@ -99,7 +99,7 @@ The first time the user runs your app, it will check for an update, and even if ### notifier = updateNotifier(options) -Checks if there is an available update. Accepts options defined below. Returns an instance with an `.update` property there is an available update, otherwise `undefined`. +Checks if there is an available update. Accepts options defined below. Returns an instance with an `.update` property if there is an available update, otherwise `undefined`. ### options @@ -201,7 +201,7 @@ There are a bunch projects using it: - [Pageres](https://github.com/sindresorhus/pageres) - Capture website screenshots - [Node GH](http://nodegh.io) - GitHub command line tool -[And 1600+ more…](https://www.npmjs.org/browse/depended/update-notifier) +[And 2700+ more…](https://www.npmjs.org/browse/depended/update-notifier) ## Security diff --git a/test/fs-error.js b/test/fs-error.js index 1d0d4cd..d6d920c 100644 --- a/test/fs-error.js +++ b/test/fs-error.js @@ -4,9 +4,8 @@ import test from 'ava'; let updateNotifier; test.before(() => { - ['.', 'configstore', 'xdg-basedir'].forEach(clearModule); - // Set configstore.config to something - // that requires root access + ['..', 'configstore', 'xdg-basedir'].forEach(clearModule); + // Set configstore.config to something that requires root access process.env.XDG_CONFIG_HOME = '/usr'; updateNotifier = require('..'); }); diff --git a/test/notify.js b/test/notify.js index 609bb79..3f9efde 100644 --- a/test/notify.js +++ b/test/notify.js @@ -19,7 +19,7 @@ function Control(shouldNotifyInNpmScript) { } const setupTest = isNpmReturnValue => { - ['.', 'is-npm'].forEach(clearModule); + ['..', 'is-npm'].forEach(clearModule); process.stdout.isTTY = true; mock('is-npm', isNpmReturnValue || false); const updateNotifier = require('..'); @@ -74,12 +74,12 @@ test('suppress output when running as npm script', t => { setupTest(true); const notifier = new Control(); notifier.notify({defer: false}); - t.is(stripAnsi(errorLogs).indexOf('Update available'), -1); + t.false(stripAnsi(errorLogs).includes('Update available')); }); test('should ouput if running as npm script and shouldNotifyInNpmScript option set', t => { setupTest(true); const notifier = new Control(true); notifier.notify({defer: false}); - t.not(stripAnsi(errorLogs).indexOf('Update available'), -1); + t.true(stripAnsi(errorLogs).includes('Update available')); }); diff --git a/test/update-notifier.js b/test/update-notifier.js index 9e51f82..d70f03b 100644 --- a/test/update-notifier.js +++ b/test/update-notifier.js @@ -7,14 +7,13 @@ mockRequire('is-ci', false); // eslint-disable-next-line import/first import updateNotifier from '..'; -const generateSettings = options => { - options = options || {}; +const generateSettings = (options = {}) => { return { pkg: { name: 'update-notifier-tester', version: '0.0.2' }, - callback: options.callback || null + callback: options.callback }; };