From d8fa60160907662ca64feb75960cfbd7c3ff4384 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 24 Jan 2021 14:36:48 +0700 Subject: [PATCH 01/27] Rename `master` branch to `main` --- contributing.md | 2 +- readme.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contributing.md b/contributing.md index 0be6f2f..4c91d7b 100644 --- a/contributing.md +++ b/contributing.md @@ -1 +1 @@ -See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) +See the [contributing docs](https://github.com/yeoman/yeoman/blob/main/contributing.md) diff --git a/readme.md b/readme.md index afab894..2ff66a3 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# update-notifier [![Build Status](https://travis-ci.org/yeoman/update-notifier.svg?branch=master)](https://travis-ci.org/yeoman/update-notifier) +# update-notifier [![Build Status](https://travis-ci.org/yeoman/update-notifier.svg?branch=main)](https://travis-ci.org/yeoman/update-notifier) > Update notifications for your CLI app @@ -188,7 +188,7 @@ Options object that will be passed to [`boxen`](https://github.com/sindresorhus/ Users of your module have the ability to opt-out of the update notifier by changing the `optOut` property to `true` in `~/.config/configstore/update-notifier-[your-module-name].json`. The path is available in `notifier.config.path`. -Users can also opt-out by [setting the environment variable](https://github.com/sindresorhus/guides/blob/master/set-environment-variables.md) `NO_UPDATE_NOTIFIER` with any value or by using the `--no-update-notifier` flag on a per run basis. +Users can also opt-out by [setting the environment variable](https://github.com/sindresorhus/guides/blob/main/set-environment-variables.md) `NO_UPDATE_NOTIFIER` with any value or by using the `--no-update-notifier` flag on a per run basis. The check is also skipped automatically: - on CI @@ -204,7 +204,7 @@ There are a bunch projects using it: - [npm](https://github.com/npm/npm) - Package manager for JavaScript - [Yeoman](https://yeoman.io) - Modern workflows for modern webapps -- [AVA](https://ava.li) - Simple concurrent test runner +- [AVA](https://avajs.dev) - Simple concurrent test runner - [XO](https://github.com/xojs/xo) - JavaScript happiness style linter - [Node GH](https://github.com/node-gh/gh) - GitHub command line tool From 0a6027e707aec755ccc6e6e45b2933d884ac4c0a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 24 Jan 2021 18:00:24 +0700 Subject: [PATCH 02/27] Move to GitHub Actions --- .github/workflows/main.yml | 22 ++++++++++++++++++++++ .travis.yml | 5 ----- readme.md | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c1870cf --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,22 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + name: Node.js ${{ matrix.node-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + node-version: + - 14 + - 12 + - 10 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm install + - run: npm test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9d7745e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - '14' - - '12' - - '10' diff --git a/readme.md b/readme.md index 2ff66a3..140c987 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# update-notifier [![Build Status](https://travis-ci.org/yeoman/update-notifier.svg?branch=main)](https://travis-ci.org/yeoman/update-notifier) +# update-notifier > Update notifications for your CLI app From 73c391b9635a694feb2444d68a3d020f8915863f Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 31 Jan 2021 16:25:12 +0700 Subject: [PATCH 03/27] Upgrade dependencies Fixes #203 Fixes #202 --- package.json | 8 ++++---- test/update-notifier.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b7a183b..80035e3 100644 --- a/package.json +++ b/package.json @@ -34,18 +34,18 @@ "version" ], "dependencies": { - "boxen": "^4.2.0", + "boxen": "^5.0.0", "chalk": "^4.1.0", "configstore": "^5.0.1", "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.2", + "is-installed-globally": "^0.4.0", "is-npm": "^5.0.0", "is-yarn-global": "^0.3.0", "latest-version": "^5.1.0", "pupa": "^2.1.1", - "semver": "^7.3.2", + "semver": "^7.3.4", "semver-diff": "^3.1.1", "xdg-basedir": "^4.0.0" }, @@ -55,6 +55,6 @@ "fixture-stdout": "^0.2.1", "mock-require": "^3.0.3", "strip-ansi": "^6.0.0", - "xo": "^0.34.1" + "xo": "^0.37.1" } } diff --git a/test/update-notifier.js b/test/update-notifier.js index 08a284e..3065be8 100644 --- a/test/update-notifier.js +++ b/test/update-notifier.js @@ -4,7 +4,7 @@ import mockRequire from 'mock-require'; mockRequire('is-ci', false); -import updateNotifier from '..'; +import updateNotifier from '../index.js'; const generateSettings = (options = {}) => { return { From 3fdb21876aa391f9bc7dc35b7d81151677fb533d Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sun, 31 Jan 2021 16:29:10 +0700 Subject: [PATCH 04/27] 5.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 80035e3..fe646fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "5.0.1", + "version": "5.1.0", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From 91835415ca721fd4a87a9f822ce9a6c3a377c8d1 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 22 Jun 2022 20:13:17 +0200 Subject: [PATCH 05/27] Require Node.js 14 and move to ESM Fixes #218 Fixes #216 Fixes #214 --- .github/workflows/main.yml | 8 +- check.js | 14 ++- example.js | 10 +- index.js | 187 +---------------------------------- license | 10 +- package.json | 45 +++++---- readme.md | 18 ++-- test/fs-error.js | 19 ++-- test/notify.js | 43 +++++---- test/update-notifier.js | 26 +++-- update-notifier.js | 193 +++++++++++++++++++++++++++++++++++++ 11 files changed, 296 insertions(+), 277 deletions(-) create mode 100644 update-notifier.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c1870cf..d50ada6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,12 +10,12 @@ jobs: fail-fast: false matrix: node-version: + - 18 + - 16 - 14 - - 12 - - 10 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - run: npm install diff --git a/check.js b/check.js index fc0ee9c..75d2f8a 100644 --- a/check.js +++ b/check.js @@ -1,12 +1,10 @@ /* eslint-disable unicorn/no-process-exit */ -'use strict'; -let updateNotifier = require('.'); +import process from 'node:process'; +import UpdateNotifier from './update-notifier.js'; -const options = JSON.parse(process.argv[2]); +const updateNotifier = new UpdateNotifier(JSON.parse(process.argv[2])); -updateNotifier = new updateNotifier.UpdateNotifier(options); - -(async () => { +try { // Exit process when offline setTimeout(process.exit, 1000 * 30); @@ -22,7 +20,7 @@ updateNotifier = new updateNotifier.UpdateNotifier(options); // 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(error => { +} catch (error) { console.error(error); process.exit(1); -}); +} diff --git a/example.js b/example.js index c9ff4de..649ef88 100644 --- a/example.js +++ b/example.js @@ -1,5 +1,4 @@ -'use strict'; -const updateNotifier = require('.'); +import updateNotifier from './index.js'; // Run: $ node example @@ -10,7 +9,8 @@ const updateNotifier = require('.'); updateNotifier({ pkg: { name: 'public-ip', - version: '0.9.2' + version: '0.9.2', }, - updateCheckInterval: 0 -}).notify(); + updateCheckInterval: 0, +}) + .notify(); diff --git a/index.js b/index.js index 5e89216..e216e65 100644 --- a/index.js +++ b/index.js @@ -1,188 +1,7 @@ -'use strict'; -const {spawn} = require('child_process'); -const path = require('path'); -const {format} = require('util'); -const importLazy = require('import-lazy')(require); +import UpdateNotifier from './update-notifier.js'; -const configstore = importLazy('configstore'); -const chalk = importLazy('chalk'); -const semver = importLazy('semver'); -const semverDiff = importLazy('semver-diff'); -const latestVersion = importLazy('latest-version'); -const isNpm = importLazy('is-npm'); -const isInstalledGlobally = importLazy('is-installed-globally'); -const isYarnGlobal = importLazy('is-yarn-global'); -const hasYarn = importLazy('has-yarn'); -const boxen = importLazy('boxen'); -const xdgBasedir = importLazy('xdg-basedir'); -const isCi = importLazy('is-ci'); -const pupa = importLazy('pupa'); - -const ONE_DAY = 1000 * 60 * 60 * 24; - -class UpdateNotifier { - constructor(options = {}) { - this.options = options; - options.pkg = options.pkg || {}; - options.distTag = options.distTag || 'latest'; - - // Reduce pkg to the essential keys. with fallback to deprecated options - // TODO: Remove deprecated options at some point far into the future - options.pkg = { - name: options.pkg.name || options.packageName, - version: options.pkg.version || options.packageVersion - }; - - if (!options.pkg.name || !options.pkg.version) { - throw new Error('pkg.name and pkg.version required'); - } - - this.packageName = options.pkg.name; - this.packageVersion = options.pkg.version; - this.updateCheckInterval = typeof options.updateCheckInterval === 'number' ? options.updateCheckInterval : ONE_DAY; - this.disabled = 'NO_UPDATE_NOTIFIER' in process.env || - process.env.NODE_ENV === 'test' || - process.argv.includes('--no-update-notifier') || - isCi(); - this.shouldNotifyInNpmScript = options.shouldNotifyInNpmScript; - - if (!this.disabled) { - try { - const ConfigStore = configstore(); - this.config = new ConfigStore(`update-notifier-${this.packageName}`, { - optOut: false, - // Init with the current time so the first check is only - // after the set interval, so not to bother users right away - lastUpdateCheck: Date.now() - }); - } catch { - // Expecting error code EACCES or EPERM - 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(boxen()(message, {align: 'center'})); - }); - } - } - } - - check() { - if ( - !this.config || - this.config.get('optOut') || - this.disabled - ) { - return; - } - - this.update = this.config.get('update'); - - if (this.update) { - // Use the real latest version instead of the cached one - this.update.current = this.packageVersion; - - // Clear cached information - this.config.delete('update'); - } - - // Only check for updates on a set interval - if (Date.now() - this.config.get('lastUpdateCheck') < this.updateCheckInterval) { - return; - } - - // Spawn a detached process, passing the options as an environment property - spawn(process.execPath, [path.join(__dirname, 'check.js'), JSON.stringify(this.options)], { - detached: true, - stdio: 'ignore' - }).unref(); - } - - async fetchInfo() { - const {distTag} = this.options; - const latest = await latestVersion()(this.packageName, {version: distTag}); - - return { - latest, - current: this.packageVersion, - type: semverDiff()(this.packageVersion, latest) || distTag, - name: this.packageName - }; - } - - notify(options) { - const suppressForNpm = !this.shouldNotifyInNpmScript && isNpm().isNpmOrYarn; - if (!process.stdout.isTTY || suppressForNpm || !this.update || !semver().gt(this.update.latest, this.update.current)) { - return this; - } - - options = { - isGlobal: isInstalledGlobally(), - isYarnGlobal: isYarnGlobal()(), - ...options - }; - - let installCommand; - if (options.isYarnGlobal) { - installCommand = `yarn global add ${this.packageName}`; - } else if (options.isGlobal) { - installCommand = `npm i -g ${this.packageName}`; - } else if (hasYarn()()) { - installCommand = `yarn add ${this.packageName}`; - } else { - installCommand = `npm i ${this.packageName}`; - } - - const defaultTemplate = 'Update available ' + - chalk().dim('{currentVersion}') + - chalk().reset(' → ') + - chalk().green('{latestVersion}') + - ' \nRun ' + chalk().cyan('{updateCommand}') + ' to update'; - - const template = options.message || defaultTemplate; - - options.boxenOptions = options.boxenOptions || { - padding: 1, - margin: 1, - align: 'center', - borderColor: 'yellow', - borderStyle: 'round' - }; - - const message = boxen()( - pupa()(template, { - packageName: this.packageName, - currentVersion: this.update.current, - latestVersion: this.update.latest, - updateCommand: installCommand - }), - options.boxenOptions - ); - - if (options.defer === false) { - console.error(message); - } else { - process.on('exit', () => { - console.error(message); - }); - - process.on('SIGINT', () => { - console.error(''); - process.exit(); - }); - } - - return this; - } -} - -module.exports = options => { +export default function updateNotifier(options) { const updateNotifier = new UpdateNotifier(options); updateNotifier.check(); return updateNotifier; -}; - -module.exports.UpdateNotifier = UpdateNotifier; +} diff --git a/license b/license index cea5a35..fa7ceba 100644 --- a/license +++ b/license @@ -1,9 +1,9 @@ -Copyright Google +MIT License -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Copyright (c) Sindre Sorhus (https://sindresorhus.com) -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/package.json b/package.json index fe646fb..90295a5 100644 --- a/package.json +++ b/package.json @@ -10,14 +10,17 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "type": "module", + "exports": "./index.js", "engines": { - "node": ">=10" + "node": ">=14.16" }, "scripts": { - "test": "xo && ava --timeout=20s --serial" + "test": "xo && ava" }, "files": [ "index.js", + "update-notifier.js", "check.js" ], "keywords": [ @@ -34,27 +37,31 @@ "version" ], "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^6.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" }, "devDependencies": { - "ava": "^2.4.0", - "clear-module": "^4.1.1", + "ava": "^4.3.0", + "clear-module": "^4.1.2", "fixture-stdout": "^0.2.1", "mock-require": "^3.0.3", - "strip-ansi": "^6.0.0", - "xo": "^0.37.1" + "strip-ansi": "^7.0.1", + "xo": "^0.50.0" + }, + "ava": { + "timeout": "20s", + "serial": true } } diff --git a/readme.md b/readme.md index 140c987..f5a97b5 100644 --- a/readme.md +++ b/readme.md @@ -17,8 +17,8 @@ Inform users of your package of updates in a non-intrusive way. ## Install -``` -$ npm install update-notifier +```sh +npm install update-notifier ``` ## Usage @@ -26,20 +26,20 @@ $ npm install update-notifier ### Simple ```js -const updateNotifier = require('update-notifier'); -const pkg = require('./package.json'); +import updateNotifier from 'update-notifier'; +import packageJson from './package.json' assert {type: 'json'}; -updateNotifier({pkg}).notify(); +updateNotifier({pkg: packageJson}).notify(); ``` ### Comprehensive ```js -const updateNotifier = require('update-notifier'); -const pkg = require('./package.json'); +import updateNotifier from 'update-notifier'; +import packageJson from './package.json' assert {type: 'json'}; // Checks for available update and returns an instance -const notifier = updateNotifier({pkg}); +const notifier = updateNotifier({pkg: packageJson}); // Notify using the built-in convenience method notifier.notify(); @@ -180,7 +180,7 @@ Include the `-g` argument in the default message's `npm i` recommendation. You m ##### boxenOptions Type: `object`\ -Default: `{padding: 1, margin: 1, align: 'center', borderColor: 'yellow', borderStyle: 'round'}` *(See screenshot)* +Default: `{padding: 1, margin: 1, textAlignment: 'center', borderColor: 'yellow', borderStyle: 'round'}` *(See screenshot)* Options object that will be passed to [`boxen`](https://github.com/sindresorhus/boxen). diff --git a/test/fs-error.js b/test/fs-error.js index 40488e0..82f3e69 100644 --- a/test/fs-error.js +++ b/test/fs-error.js @@ -1,23 +1,20 @@ +import process from 'node:process'; import clearModule from 'clear-module'; import test from 'ava'; -let updateNotifier; +for (const name of ['..', 'configstore', 'xdg-basedir']) { + clearModule(name); +} -test.before(() => { - for (const name of ['..', 'configstore', 'xdg-basedir']) { - clearModule(name); - } - - // Set configstore.config to something that requires root access - process.env.XDG_CONFIG_HOME = '/usr'; - updateNotifier = require('..'); -}); +// Set configstore.config to something that requires root access +process.env.XDG_CONFIG_HOME = '/usr'; +const {default: updateNotifier} = await import('../index.js'); test('fail gracefully', t => { t.notThrows(() => { updateNotifier({ packageName: 'npme', - packageVersion: '3.7.0' + packageVersion: '3.7.0', }); }); }); diff --git a/test/notify.js b/test/notify.js index f0c7cca..91709ba 100644 --- a/test/notify.js +++ b/test/notify.js @@ -1,4 +1,5 @@ -import {inherits} from 'util'; +import process from 'node:process'; +import {inherits} from 'node:util'; import clearModule from 'clear-module'; import FixtureStdout from 'fixture-stdout'; import stripAnsi from 'strip-ansi'; @@ -6,33 +7,37 @@ import test from 'ava'; import mock from 'mock-require'; const stderr = new FixtureStdout({ - stream: process.stderr + stream: process.stderr, }); function Control(shouldNotifyInNpmScript) { - this.packageName = 'update-notifier-tester'; + this._packageName = 'update-notifier-tester'; this.update = { current: '0.0.2', - latest: '1.0.0' + latest: '1.0.0', }; - this.shouldNotifyInNpmScript = shouldNotifyInNpmScript; + this._shouldNotifyInNpmScript = shouldNotifyInNpmScript; } -const setupTest = isNpmReturnValue => { +const setupTest = async isNpmReturnValue => { for (const name of ['..', 'is-npm']) { clearModule(name); } process.stdout.isTTY = true; + + // TODO: Switch to https://github.com/iambumblehead/esmock mock('is-npm', {isNpmOrYarn: isNpmReturnValue || false}); - const updateNotifier = require('..'); - inherits(Control, updateNotifier.UpdateNotifier); + + const {default: UpdateNotifier} = await import('../update-notifier.js'); + inherits(Control, UpdateNotifier); }; let errorLogs = ''; -test.beforeEach(() => { - setupTest(); +test.beforeEach(async () => { + await setupTest(); + stderr.capture(s => { errorLogs += s; return false; @@ -45,10 +50,12 @@ test.afterEach(() => { errorLogs = ''; }); -test('use pretty boxen message by default', t => { +test.failing('use pretty boxen message by default', t => { const notifier = new Control(); notifier.notify({defer: false, isGlobal: true}); + console.log('d', errorLogs); + t.is(stripAnsi(errorLogs), ` ╭───────────────────────────────────────────────────╮ │ │ @@ -60,18 +67,18 @@ test('use pretty boxen message by default', t => { `); }); -test('supports custom message', t => { +test.failing('supports custom message', t => { const notifier = new Control(); notifier.notify({ defer: false, isGlobal: true, - message: 'custom message' + message: 'custom message', }); t.true(stripAnsi(errorLogs).includes('custom message')); }); -test('supports message with placeholders', t => { +test.failing('supports message with placeholders', t => { const notifier = new Control(); notifier.notify({ defer: false, @@ -80,8 +87,8 @@ test('supports message with placeholders', t => { 'Package Name: {packageName}', 'Current Version: {currentVersion}', 'Latest Version: {latestVersion}', - 'Update Command: {updateCommand}' - ].join('\n') + 'Update Command: {updateCommand}', + ].join('\n'), }); t.is(stripAnsi(errorLogs), ` @@ -97,13 +104,13 @@ test('supports message with placeholders', t => { `); }); -test('exclude -g argument when `isGlobal` option is `false`', t => { +test.failing('exclude -g argument when `isGlobal` option is `false`', t => { const notifier = new Control(); notifier.notify({defer: false, isGlobal: false}); t.not(stripAnsi(errorLogs).indexOf('Run npm i update-notifier-tester to update'), -1); }); -test('shouldNotifyInNpmScript should default to false', t => { +test.failing('shouldNotifyInNpmScript should default to false', t => { const notifier = new Control(); notifier.notify({defer: false}); t.not(stripAnsi(errorLogs).indexOf('Update available'), -1); diff --git a/test/update-notifier.js b/test/update-notifier.js index 3065be8..025e709 100644 --- a/test/update-notifier.js +++ b/test/update-notifier.js @@ -1,20 +1,18 @@ -import fs from 'fs'; +import process from 'node:process'; +import fs from 'node:fs'; import test from 'ava'; import mockRequire from 'mock-require'; +import updateNotifier from '../index.js'; mockRequire('is-ci', false); -import updateNotifier from '../index.js'; - -const generateSettings = (options = {}) => { - return { - pkg: { - name: 'update-notifier-tester', - version: '0.0.2' - }, - distTag: options.distTag - }; -}; +const generateSettings = (options = {}) => ({ + pkg: { + name: 'update-notifier-tester', + version: '0.0.2', + }, + distTag: options.distTag, +}); let argv; let configstorePath; @@ -23,7 +21,7 @@ test.beforeEach(() => { // Prevents NODE_ENV 'test' default behavior which disables `update-notifier` process.env.NODE_ENV = 'ava-test'; - argv = process.argv.slice(); + argv = [...process.argv]; configstorePath = updateNotifier(generateSettings()).config.path; }); @@ -32,7 +30,7 @@ test.afterEach(() => { process.argv = argv; setTimeout(() => { fs.unlinkSync(configstorePath); - }, 10000); + }, 10_000); }); test('fetch info', async t => { diff --git a/update-notifier.js b/update-notifier.js new file mode 100644 index 0000000..69abbd5 --- /dev/null +++ b/update-notifier.js @@ -0,0 +1,193 @@ +import process from 'node:process'; +import {spawn} from 'node:child_process'; +import {fileURLToPath} from 'node:url'; +import path from 'node:path'; +import {format} from 'node:util'; +import ConfigStore from 'configstore'; +import chalk from 'chalk'; +import semver from 'semver'; +import semverDiff from 'semver-diff'; +import latestVersion from 'latest-version'; +import {isNpmOrYarn} from 'is-npm'; +import isInstalledGlobally from 'is-installed-globally'; +import isYarnGlobal from 'is-yarn-global'; +import hasYarn from 'has-yarn'; +import boxen from 'boxen'; +import {xdgConfig} from 'xdg-basedir'; +import isCi from 'is-ci'; +import pupa from 'pupa'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const ONE_DAY = 1000 * 60 * 60 * 24; + +export default class UpdateNotifier { + // Public + config; + update; + + // Semi-private (used for tests) + _packageName; + _shouldNotifyInNpmScript; + + #options; + #packageVersion; + #updateCheckInterval; + #isDisabled; + + constructor(options = {}) { + this.#options = options; + options.pkg = options.pkg || {}; + options.distTag = options.distTag || 'latest'; + + // Reduce pkg to the essential keys. with fallback to deprecated options + // TODO: Remove deprecated options at some point far into the future + options.pkg = { + name: options.pkg.name || options.packageName, + version: options.pkg.version || options.packageVersion, + }; + + if (!options.pkg.name || !options.pkg.version) { + throw new Error('pkg.name and pkg.version required'); + } + + this._packageName = options.pkg.name; + this.#packageVersion = options.pkg.version; + this.#updateCheckInterval = typeof options.updateCheckInterval === 'number' ? options.updateCheckInterval : ONE_DAY; + this.#isDisabled = 'NO_UPDATE_NOTIFIER' in process.env + || process.env.NODE_ENV === 'test' + || process.argv.includes('--no-update-notifier') + || isCi; + this._shouldNotifyInNpmScript = options.shouldNotifyInNpmScript; + + if (!this.#isDisabled) { + try { + this.config = new ConfigStore(`update-notifier-${this._packageName}`, { + optOut: false, + // Init with the current time so the first check is only + // after the set interval, so not to bother users right away + lastUpdateCheck: Date.now(), + }); + } catch { + // Expecting error code EACCES or EPERM + 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 ', xdgConfig)); + + process.on('exit', () => { + console.error(boxen(message, {textAlignment: 'center'})); + }); + } + } + } + + check() { + if ( + !this.config + || this.config.get('optOut') + || this.#isDisabled + ) { + return; + } + + this.update = this.config.get('update'); + + if (this.update) { + // Use the real latest version instead of the cached one + this.update.current = this.#packageVersion; + + // Clear cached information + this.config.delete('update'); + } + + // Only check for updates on a set interval + if (Date.now() - this.config.get('lastUpdateCheck') < this.#updateCheckInterval) { + return; + } + + // Spawn a detached process, passing the options as an environment property + spawn(process.execPath, [path.join(__dirname, 'check.js'), JSON.stringify(this.#options)], { + detached: true, + stdio: 'ignore', + }).unref(); + } + + async fetchInfo() { + const {distTag} = this.#options; + const latest = await latestVersion(this._packageName, {version: distTag}); + + return { + latest, + current: this.#packageVersion, + type: semverDiff(this.#packageVersion, latest) || distTag, + name: this._packageName, + }; + } + + notify(options) { + const suppressForNpm = !this._shouldNotifyInNpmScript && isNpmOrYarn; + if (!process.stdout.isTTY || suppressForNpm || !this.update || !semver.gt(this.update.latest, this.update.current)) { + return this; + } + + options = { + isGlobal: isInstalledGlobally, + isYarnGlobal: isYarnGlobal(), + ...options, + }; + + let installCommand; + if (options.isYarnGlobal) { + installCommand = `yarn global add ${this._packageName}`; + } else if (options.isGlobal) { + installCommand = `npm i -g ${this._packageName}`; + } else if (hasYarn()) { + installCommand = `yarn add ${this._packageName}`; + } else { + installCommand = `npm i ${this._packageName}`; + } + + const defaultTemplate = 'Update available ' + + chalk.dim('{currentVersion}') + + chalk.reset(' → ') + + chalk.green('{latestVersion}') + + ' \nRun ' + chalk.cyan('{updateCommand}') + ' to update'; + + const template = options.message || defaultTemplate; + + options.boxenOptions = options.boxenOptions || { + padding: 1, + margin: 1, + textAlignment: 'center', + borderColor: 'yellow', + borderStyle: 'round', + }; + + const message = boxen( + pupa(template, { + packageName: this._packageName, + currentVersion: this.update.current, + latestVersion: this.update.latest, + updateCommand: installCommand, + }), + options.boxenOptions, + ); + + if (options.defer === false) { + console.error(message); + } else { + process.on('exit', () => { + console.error(message); + }); + + process.on('SIGINT', () => { + console.error(''); + process.exit(); + }); + } + + return this; + } +} From 311557ec77dbb35ea130530639b0da7bbb254897 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 23 Jun 2022 14:21:06 +0200 Subject: [PATCH 06/27] 6.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 90295a5..fcaad76 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "5.1.0", + "version": "6.0.0", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From 3f7c9f31fa7d581c942acf69b102a3cfe9c4a8f5 Mon Sep 17 00:00:00 2001 From: Vemund Santi Date: Fri, 24 Jun 2022 00:23:49 +0200 Subject: [PATCH 07/27] Update dependencies (#222) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fcaad76..f4edc0b 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "is-installed-globally": "^0.4.0", "is-npm": "^6.0.0", "is-yarn-global": "^0.4.0", - "latest-version": "^6.0.0", + "latest-version": "^7.0.0", "pupa": "^3.1.0", "semver": "^7.3.7", "semver-diff": "^4.0.0", From 020613ba9b3b1280b13e7c76e02f8919ce8d6b10 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 24 Jun 2022 00:24:44 +0200 Subject: [PATCH 08/27] 6.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4edc0b..4d80146 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "6.0.0", + "version": "6.0.1", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From d152f855888bbb6449318e61d1495bfd76f8fb4c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 24 Jun 2022 13:45:06 +0200 Subject: [PATCH 09/27] Fix license --- license | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/license b/license index fa7ceba..cea5a35 100644 --- a/license +++ b/license @@ -1,9 +1,9 @@ -MIT License +Copyright Google -Copyright (c) Sindre Sorhus (https://sindresorhus.com) +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From 3b6b9b18428aa3848960f02df53cb571a7620a51 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 24 Jun 2022 13:45:54 +0200 Subject: [PATCH 10/27] 6.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d80146..1ed9e9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "6.0.1", + "version": "6.0.2", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From 3046d0f61a57f8270291b6ab271f8a12df8421a6 Mon Sep 17 00:00:00 2001 From: iambumblehead Date: Tue, 19 Jul 2022 15:29:10 -0700 Subject: [PATCH 11/27] Switch to `esmock` for tests (#225) --- package.json | 4 ++-- test/notify.js | 40 +++++++++++++++++----------------------- test/update-notifier.js | 21 +++++++++++++-------- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 1ed9e9f..7d10f67 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "node": ">=14.16" }, "scripts": { - "test": "xo && ava" + "test": "xo && NODE_OPTIONS='--loader=esmock --no-warnings' ava" }, "files": [ "index.js", @@ -56,7 +56,7 @@ "ava": "^4.3.0", "clear-module": "^4.1.2", "fixture-stdout": "^0.2.1", - "mock-require": "^3.0.3", + "esmock": "^1.7.8", "strip-ansi": "^7.0.1", "xo": "^0.50.0" }, diff --git a/test/notify.js b/test/notify.js index 91709ba..d8740f7 100644 --- a/test/notify.js +++ b/test/notify.js @@ -1,10 +1,9 @@ import process from 'node:process'; import {inherits} from 'node:util'; -import clearModule from 'clear-module'; import FixtureStdout from 'fixture-stdout'; import stripAnsi from 'strip-ansi'; import test from 'ava'; -import mock from 'mock-require'; +import esmock from 'esmock'; const stderr = new FixtureStdout({ stream: process.stderr, @@ -20,16 +19,12 @@ function Control(shouldNotifyInNpmScript) { } const setupTest = async isNpmReturnValue => { - for (const name of ['..', 'is-npm']) { - clearModule(name); - } - process.stdout.isTTY = true; - // TODO: Switch to https://github.com/iambumblehead/esmock - mock('is-npm', {isNpmOrYarn: isNpmReturnValue || false}); + const UpdateNotifier = await esmock('../update-notifier.js', { + 'is-npm': {isNpmOrYarn: isNpmReturnValue || false}, + }); - const {default: UpdateNotifier} = await import('../update-notifier.js'); inherits(Control, UpdateNotifier); }; @@ -45,12 +40,11 @@ test.beforeEach(async () => { }); test.afterEach(() => { - mock.stopAll(); stderr.release(); errorLogs = ''; }); -test.failing('use pretty boxen message by default', t => { +test('use pretty boxen message by default', t => { const notifier = new Control(); notifier.notify({defer: false, isGlobal: true}); @@ -67,7 +61,7 @@ test.failing('use pretty boxen message by default', t => { `); }); -test.failing('supports custom message', t => { +test('supports custom message', t => { const notifier = new Control(); notifier.notify({ defer: false, @@ -78,7 +72,7 @@ test.failing('supports custom message', t => { t.true(stripAnsi(errorLogs).includes('custom message')); }); -test.failing('supports message with placeholders', t => { +test('supports message with placeholders', t => { const notifier = new Control(); notifier.notify({ defer: false, @@ -104,42 +98,42 @@ test.failing('supports message with placeholders', t => { `); }); -test.failing('exclude -g argument when `isGlobal` option is `false`', t => { +test('exclude -g argument when `isGlobal` option is `false`', t => { const notifier = new Control(); notifier.notify({defer: false, isGlobal: false}); t.not(stripAnsi(errorLogs).indexOf('Run npm i update-notifier-tester to update'), -1); }); -test.failing('shouldNotifyInNpmScript should default to false', t => { +test('shouldNotifyInNpmScript should default to false', t => { const notifier = new Control(); notifier.notify({defer: false}); t.not(stripAnsi(errorLogs).indexOf('Update available'), -1); }); -test('suppress output when running as npm script', t => { - setupTest(true); +test('suppress output when running as npm script', async t => { + await setupTest(true); const notifier = new Control(); notifier.notify({defer: false}); t.false(stripAnsi(errorLogs).includes('Update available')); }); -test('should output if running as npm script and shouldNotifyInNpmScript option set', t => { - setupTest(true); +test('should output if running as npm script and shouldNotifyInNpmScript option set', async t => { + await setupTest(true); const notifier = new Control(true); notifier.notify({defer: false}); t.true(stripAnsi(errorLogs).includes('Update available')); }); -test('should not output if current version is the latest', t => { - setupTest(true); +test('should not output if current version is the latest', async t => { + await setupTest(true); const notifier = new Control(true); notifier.update.current = '1.0.0'; notifier.notify({defer: false}); t.false(stripAnsi(errorLogs).includes('Update available')); }); -test('should not output if current version is more recent than the reported latest', t => { - setupTest(true); +test('should not output if current version is more recent than the reported latest', async t => { + await setupTest(true); const notifier = new Control(true); notifier.update.current = '1.0.1'; notifier.notify({defer: false}); diff --git a/test/update-notifier.js b/test/update-notifier.js index 025e709..f7e69af 100644 --- a/test/update-notifier.js +++ b/test/update-notifier.js @@ -1,10 +1,7 @@ import process from 'node:process'; import fs from 'node:fs'; import test from 'ava'; -import mockRequire from 'mock-require'; -import updateNotifier from '../index.js'; - -mockRequire('is-ci', false); +import esmock from 'esmock'; const generateSettings = (options = {}) => ({ pkg: { @@ -22,7 +19,6 @@ test.beforeEach(() => { process.env.NODE_ENV = 'ava-test'; argv = [...process.argv]; - configstorePath = updateNotifier(generateSettings()).config.path; }); test.afterEach(() => { @@ -34,30 +30,39 @@ test.afterEach(() => { }); test('fetch info', async t => { + const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + configstorePath = updateNotifier(generateSettings()).config.path; const update = await updateNotifier(generateSettings()).fetchInfo(); console.log(update); t.is(update.latest, '0.0.2'); }); test('fetch info with dist-tag', async t => { + const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + configstorePath = updateNotifier(generateSettings()).config.path; const update = await updateNotifier(generateSettings({distTag: '0.0.3-rc1'})).fetchInfo(); t.is(update.latest, '0.0.3-rc1'); }); -test('don\'t initialize configStore when NO_UPDATE_NOTIFIER is set', t => { +test('don\'t initialize configStore when NO_UPDATE_NOTIFIER is set', async t => { + const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + configstorePath = updateNotifier(generateSettings()).config.path; process.env.NO_UPDATE_NOTIFIER = '1'; const notifier = updateNotifier(generateSettings()); t.is(notifier.config, undefined); }); -test('don\'t initialize configStore when --no-update-notifier is set', t => { +test('don\'t initialize configStore when --no-update-notifier is set', async t => { + const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + configstorePath = updateNotifier(generateSettings()).config.path; process.argv.push('--no-update-notifier'); const notifier = updateNotifier(generateSettings()); t.is(notifier.config, undefined); }); -test('don\'t initialize configStore when NODE_ENV === "test"', t => { +test('don\'t initialize configStore when NODE_ENV === "test"', async t => { process.env.NODE_ENV = 'test'; + const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); const notifier = updateNotifier(generateSettings()); t.is(notifier.config, undefined); }); From a1d8d9d9150d00dbc908820dc3fe8b33bac3003a Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 27 Oct 2023 18:58:42 +0700 Subject: [PATCH 12/27] Drop Yarn install commands in update message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yarn users should know how to translate from npm commands already as most packages document npm commands only. It’s also unfair to other package managers, like `pnpm` and `bun` that we don’t include them and I don’t want to maintain install commands for all of them. --- package.json | 2 -- update-notifier.js | 14 +------------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/package.json b/package.json index 7d10f67..95a8d37 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,10 @@ "boxen": "^7.0.0", "chalk": "^5.0.1", "configstore": "^6.0.0", - "has-yarn": "^3.0.0", "import-lazy": "^4.0.0", "is-ci": "^3.0.1", "is-installed-globally": "^0.4.0", "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", "latest-version": "^7.0.0", "pupa": "^3.1.0", "semver": "^7.3.7", diff --git a/update-notifier.js b/update-notifier.js index 69abbd5..7d6c141 100644 --- a/update-notifier.js +++ b/update-notifier.js @@ -10,8 +10,6 @@ import semverDiff from 'semver-diff'; import latestVersion from 'latest-version'; import {isNpmOrYarn} from 'is-npm'; import isInstalledGlobally from 'is-installed-globally'; -import isYarnGlobal from 'is-yarn-global'; -import hasYarn from 'has-yarn'; import boxen from 'boxen'; import {xdgConfig} from 'xdg-basedir'; import isCi from 'is-ci'; @@ -134,20 +132,10 @@ export default class UpdateNotifier { options = { isGlobal: isInstalledGlobally, - isYarnGlobal: isYarnGlobal(), ...options, }; - let installCommand; - if (options.isYarnGlobal) { - installCommand = `yarn global add ${this._packageName}`; - } else if (options.isGlobal) { - installCommand = `npm i -g ${this._packageName}`; - } else if (hasYarn()) { - installCommand = `yarn add ${this._packageName}`; - } else { - installCommand = `npm i ${this._packageName}`; - } + const installCommand = options.isGlobal ? `npm i -g ${this._packageName}` : `npm i ${this._packageName}`; const defaultTemplate = 'Update available ' + chalk.dim('{currentVersion}') From 431dac46c693dad384db03bbb89734a56f21ea08 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 28 Oct 2023 01:39:41 +0700 Subject: [PATCH 13/27] Require Node.js 18 --- package.json | 18 +++++++++--------- readme.md | 24 ++++++------------------ test/update-notifier.js | 10 +++++----- update-notifier.js | 16 ++++++++-------- 4 files changed, 28 insertions(+), 40 deletions(-) diff --git a/package.json b/package.json index 95a8d37..6967d14 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "type": "module", "exports": "./index.js", "engines": { - "node": ">=14.16" + "node": ">=18" }, "scripts": { "test": "xo && NODE_OPTIONS='--loader=esmock --no-warnings' ava" @@ -37,26 +37,26 @@ "version" ], "dependencies": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", + "boxen": "^7.1.1", + "chalk": "^5.3.0", "configstore": "^6.0.0", "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", + "is-in-ci": "^0.1.0", "is-installed-globally": "^0.4.0", "is-npm": "^6.0.0", "latest-version": "^7.0.0", "pupa": "^3.1.0", - "semver": "^7.3.7", + "semver": "^7.5.4", "semver-diff": "^4.0.0", "xdg-basedir": "^5.1.0" }, "devDependencies": { - "ava": "^4.3.0", + "ava": "^5.3.1", "clear-module": "^4.1.2", + "esmock": "^2.5.8", "fixture-stdout": "^0.2.1", - "esmock": "^1.7.8", - "strip-ansi": "^7.0.1", - "xo": "^0.50.0" + "strip-ansi": "^7.1.0", + "xo": "^0.56.0" }, "ava": { "timeout": "20s", diff --git a/readme.md b/readme.md index f5a97b5..9f02f32 100644 --- a/readme.md +++ b/readme.md @@ -127,10 +127,10 @@ Check update information. Returns an `object` with: -- `latest` _(String)_ - Latest version. -- `current` _(String)_ - Current version. -- `type` _(String)_ - Type of current update. Possible values: `latest`, `major`, `minor`, `patch`, `prerelease`, `build`. -- `name` _(String)_ - Package name. +- `latest` *(string)* - Latest version. +- `current` *(string)* - Current version. +- `type` *(string)* - Type of current update. Possible values: `latest`, `major`, `minor`, `patch`, `prerelease`, `build`. +- `name` *(string)* - Package name. ### notifier.notify(options?) @@ -191,8 +191,8 @@ Users of your module have the ability to opt-out of the update notifier by chang Users can also opt-out by [setting the environment variable](https://github.com/sindresorhus/guides/blob/main/set-environment-variables.md) `NO_UPDATE_NOTIFIER` with any value or by using the `--no-update-notifier` flag on a per run basis. The check is also skipped automatically: - - on CI - - in unit tests (when the `NODE_ENV` environment variable is `test`) +- [in CI](https://github.com/sindresorhus/is-in-ci) +- in unit tests (when the `NODE_ENV` environment variable is `test`) ## About @@ -209,15 +209,3 @@ There are a bunch projects using it: - [Node GH](https://github.com/node-gh/gh) - GitHub command line tool [And 2700+ more…](https://www.npmjs.org/browse/depended/update-notifier) - ---- - -
- - Get professional support for this package with a Tidelift subscription - -
- - Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies. -
-
diff --git a/test/update-notifier.js b/test/update-notifier.js index f7e69af..8976f97 100644 --- a/test/update-notifier.js +++ b/test/update-notifier.js @@ -30,7 +30,7 @@ test.afterEach(() => { }); test('fetch info', async t => { - const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + const updateNotifier = await esmock('../index.js', undefined, {'is-in-ci': false}); configstorePath = updateNotifier(generateSettings()).config.path; const update = await updateNotifier(generateSettings()).fetchInfo(); console.log(update); @@ -38,14 +38,14 @@ test('fetch info', async t => { }); test('fetch info with dist-tag', async t => { - const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + const updateNotifier = await esmock('../index.js', undefined, {'is-in-ci': false}); configstorePath = updateNotifier(generateSettings()).config.path; const update = await updateNotifier(generateSettings({distTag: '0.0.3-rc1'})).fetchInfo(); t.is(update.latest, '0.0.3-rc1'); }); test('don\'t initialize configStore when NO_UPDATE_NOTIFIER is set', async t => { - const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + const updateNotifier = await esmock('../index.js', undefined, {'is-in-ci': false}); configstorePath = updateNotifier(generateSettings()).config.path; process.env.NO_UPDATE_NOTIFIER = '1'; const notifier = updateNotifier(generateSettings()); @@ -53,7 +53,7 @@ test('don\'t initialize configStore when NO_UPDATE_NOTIFIER is set', async t => }); test('don\'t initialize configStore when --no-update-notifier is set', async t => { - const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + const updateNotifier = await esmock('../index.js', undefined, {'is-in-ci': false}); configstorePath = updateNotifier(generateSettings()).config.path; process.argv.push('--no-update-notifier'); const notifier = updateNotifier(generateSettings()); @@ -62,7 +62,7 @@ test('don\'t initialize configStore when --no-update-notifier is set', async t = test('don\'t initialize configStore when NODE_ENV === "test"', async t => { process.env.NODE_ENV = 'test'; - const updateNotifier = await esmock('../index.js', undefined, {'is-ci': false}); + const updateNotifier = await esmock('../index.js', undefined, {'is-in-ci': false}); const notifier = updateNotifier(generateSettings()); t.is(notifier.config, undefined); }); diff --git a/update-notifier.js b/update-notifier.js index 7d6c141..0a9f539 100644 --- a/update-notifier.js +++ b/update-notifier.js @@ -12,7 +12,7 @@ import {isNpmOrYarn} from 'is-npm'; import isInstalledGlobally from 'is-installed-globally'; import boxen from 'boxen'; import {xdgConfig} from 'xdg-basedir'; -import isCi from 'is-ci'; +import isInCi from 'is-in-ci'; import pupa from 'pupa'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -35,14 +35,14 @@ export default class UpdateNotifier { constructor(options = {}) { this.#options = options; - options.pkg = options.pkg || {}; - options.distTag = options.distTag || 'latest'; + options.pkg = options.pkg ?? {}; + options.distTag = options.distTag ?? 'latest'; // Reduce pkg to the essential keys. with fallback to deprecated options // TODO: Remove deprecated options at some point far into the future options.pkg = { - name: options.pkg.name || options.packageName, - version: options.pkg.version || options.packageVersion, + name: options.pkg.name ?? options.packageName, + version: options.pkg.version ?? options.packageVersion, }; if (!options.pkg.name || !options.pkg.version) { @@ -55,7 +55,7 @@ export default class UpdateNotifier { this.#isDisabled = 'NO_UPDATE_NOTIFIER' in process.env || process.env.NODE_ENV === 'test' || process.argv.includes('--no-update-notifier') - || isCi; + || isInCi; this._shouldNotifyInNpmScript = options.shouldNotifyInNpmScript; if (!this.#isDisabled) { @@ -119,7 +119,7 @@ export default class UpdateNotifier { return { latest, current: this.#packageVersion, - type: semverDiff(this.#packageVersion, latest) || distTag, + type: semverDiff(this.#packageVersion, latest) ?? distTag, name: this._packageName, }; } @@ -145,7 +145,7 @@ export default class UpdateNotifier { const template = options.message || defaultTemplate; - options.boxenOptions = options.boxenOptions || { + options.boxenOptions ??= { padding: 1, margin: 1, textAlignment: 'center', From 12e11d6e536987da79f6982c4aa0f8fc082da0fc Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 28 Oct 2023 02:03:10 +0700 Subject: [PATCH 14/27] 7.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6967d14..a714bc8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "6.0.2", + "version": "7.0.0", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From b4840e5a4aa66b80233c095595708853d188520c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 28 Oct 2023 02:05:26 +0700 Subject: [PATCH 15/27] Fix CI --- .github/workflows/main.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d50ada6..346585c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,12 +10,11 @@ jobs: fail-fast: false matrix: node-version: + - 20 - 18 - - 16 - - 14 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - run: npm install From 2980d3396068300c70bc1aa8c0543cde2460d90f Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Fri, 12 Jul 2024 18:17:06 +0700 Subject: [PATCH 16/27] Update dependencies (#234) --- package.json | 10 +++++----- update-notifier.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index a714bc8..2be405f 100644 --- a/package.json +++ b/package.json @@ -42,21 +42,21 @@ "configstore": "^6.0.0", "import-lazy": "^4.0.0", "is-in-ci": "^0.1.0", - "is-installed-globally": "^0.4.0", + "is-installed-globally": "^1.0.0", "is-npm": "^6.0.0", - "latest-version": "^7.0.0", + "latest-version": "^9.0.0", "pupa": "^3.1.0", - "semver": "^7.5.4", + "semver": "^7.6.2", "semver-diff": "^4.0.0", "xdg-basedir": "^5.1.0" }, "devDependencies": { "ava": "^5.3.1", "clear-module": "^4.1.2", - "esmock": "^2.5.8", + "esmock": "^2.6.6", "fixture-stdout": "^0.2.1", "strip-ansi": "^7.1.0", - "xo": "^0.56.0" + "xo": "^0.58.0" }, "ava": { "timeout": "20s", diff --git a/update-notifier.js b/update-notifier.js index 0a9f539..619754a 100644 --- a/update-notifier.js +++ b/update-notifier.js @@ -35,8 +35,8 @@ export default class UpdateNotifier { constructor(options = {}) { this.#options = options; - options.pkg = options.pkg ?? {}; - options.distTag = options.distTag ?? 'latest'; + options.pkg ??= {}; + options.distTag ??= 'latest'; // Reduce pkg to the essential keys. with fallback to deprecated options // TODO: Remove deprecated options at some point far into the future From d7cc032b01259238445df4c669261801bcb9b2c4 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 12 Jul 2024 13:19:18 +0200 Subject: [PATCH 17/27] Meta tweaks --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 2be405f..b6744ea 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ }, "type": "module", "exports": "./index.js", + "sideEffects": false, "engines": { "node": ">=18" }, From 4c9ec84a42f4bedac5ac966715428eadc7d0a48e Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 12 Jul 2024 13:21:09 +0200 Subject: [PATCH 18/27] 7.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6744ea..eef9b8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "7.0.0", + "version": "7.1.0", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From ad0428823af0283e656579d117754f7fb4bf05c3 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 26 Jul 2024 13:34:14 +0200 Subject: [PATCH 19/27] Update dependencies --- package.json | 14 +++++++------- test/update-notifier.js | 5 ++++- update-notifier.js | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index eef9b8e..5f7d092 100644 --- a/package.json +++ b/package.json @@ -38,26 +38,26 @@ "version" ], "dependencies": { - "boxen": "^7.1.1", + "boxen": "^8.0.0", "chalk": "^5.3.0", - "configstore": "^6.0.0", + "configstore": "^7.0.0", "import-lazy": "^4.0.0", - "is-in-ci": "^0.1.0", + "is-in-ci": "^1.0.0", "is-installed-globally": "^1.0.0", "is-npm": "^6.0.0", "latest-version": "^9.0.0", "pupa": "^3.1.0", - "semver": "^7.6.2", + "semver": "^7.6.3", "semver-diff": "^4.0.0", "xdg-basedir": "^5.1.0" }, "devDependencies": { - "ava": "^5.3.1", + "ava": "^6.1.3", "clear-module": "^4.1.2", - "esmock": "^2.6.6", + "esmock": "^2.6.7", "fixture-stdout": "^0.2.1", "strip-ansi": "^7.1.0", - "xo": "^0.58.0" + "xo": "^0.59.2" }, "ava": { "timeout": "20s", diff --git a/test/update-notifier.js b/test/update-notifier.js index 8976f97..56bf398 100644 --- a/test/update-notifier.js +++ b/test/update-notifier.js @@ -24,8 +24,11 @@ test.beforeEach(() => { test.afterEach(() => { delete process.env.NO_UPDATE_NOTIFIER; process.argv = argv; + setTimeout(() => { - fs.unlinkSync(configstorePath); + try { + fs.unlinkSync(configstorePath); + } catch {} }, 10_000); }); diff --git a/update-notifier.js b/update-notifier.js index 619754a..b239c8d 100644 --- a/update-notifier.js +++ b/update-notifier.js @@ -25,10 +25,10 @@ export default class UpdateNotifier { update; // Semi-private (used for tests) - _packageName; + _packageName; // eslint-disable-line lines-between-class-members _shouldNotifyInNpmScript; - #options; + #options; // eslint-disable-line lines-between-class-members #packageVersion; #updateCheckInterval; #isDisabled; From 2f885b4f7a652000a80110d6a72aa2e8ae5106d2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Fri, 26 Jul 2024 13:38:05 +0200 Subject: [PATCH 20/27] 7.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5f7d092..79e0eea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "7.1.0", + "version": "7.2.0", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From cb073f070a8544fe89d0ab56963e43dd11d62208 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Wed, 31 Jul 2024 17:50:03 +0700 Subject: [PATCH 21/27] Drop unused dependency (#235) --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 79e0eea..619b239 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "boxen": "^8.0.0", "chalk": "^5.3.0", "configstore": "^7.0.0", - "import-lazy": "^4.0.0", "is-in-ci": "^1.0.0", "is-installed-globally": "^1.0.0", "is-npm": "^6.0.0", From 0b962bc61ea502b99f5844ad450a7b67133e34c7 Mon Sep 17 00:00:00 2001 From: Federico Brigante Date: Tue, 27 Aug 2024 14:16:25 +0700 Subject: [PATCH 22/27] Drop redundant dependency (#236) --- package.json | 1 - update-notifier.js | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 619b239..8c29c60 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "latest-version": "^9.0.0", "pupa": "^3.1.0", "semver": "^7.6.3", - "semver-diff": "^4.0.0", "xdg-basedir": "^5.1.0" }, "devDependencies": { diff --git a/update-notifier.js b/update-notifier.js index b239c8d..5ab5af0 100644 --- a/update-notifier.js +++ b/update-notifier.js @@ -5,8 +5,9 @@ import path from 'node:path'; import {format} from 'node:util'; import ConfigStore from 'configstore'; import chalk from 'chalk'; -import semver from 'semver'; -import semverDiff from 'semver-diff'; +// Only import what we need for performance +import semverDiff from 'semver/functions/diff.js'; +import semverGt from 'semver/functions/gt.js'; import latestVersion from 'latest-version'; import {isNpmOrYarn} from 'is-npm'; import isInstalledGlobally from 'is-installed-globally'; @@ -126,7 +127,7 @@ export default class UpdateNotifier { notify(options) { const suppressForNpm = !this._shouldNotifyInNpmScript && isNpmOrYarn; - if (!process.stdout.isTTY || suppressForNpm || !this.update || !semver.gt(this.update.latest, this.update.current)) { + if (!process.stdout.isTTY || suppressForNpm || !this.update || !semverGt(this.update.latest, this.update.current)) { return this; } From 739ec6f31c455ed3c3c562f0126ed53098a8bd96 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 27 Aug 2024 14:17:32 +0700 Subject: [PATCH 23/27] 7.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c29c60..a8210f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "7.2.0", + "version": "7.3.0", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From 4a62e5019be5f5c5444265312340cb53aafe8bf9 Mon Sep 17 00:00:00 2001 From: Northword <44738481+northword@users.noreply.github.com> Date: Tue, 10 Sep 2024 00:23:04 +0800 Subject: [PATCH 24/27] Remove unused SIGINT listener (#237) --- update-notifier.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/update-notifier.js b/update-notifier.js index 5ab5af0..300aa8e 100644 --- a/update-notifier.js +++ b/update-notifier.js @@ -170,11 +170,6 @@ export default class UpdateNotifier { process.on('exit', () => { console.error(message); }); - - process.on('SIGINT', () => { - console.error(''); - process.exit(); - }); } return this; From 0dbe072b6999ecc0ed7012df6450148bf6e14d7c Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 9 Sep 2024 23:30:37 +0700 Subject: [PATCH 25/27] Meta tweaks --- package.json | 4 ++-- readme.md | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index a8210f1..4fdb554 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "version" ], "dependencies": { - "boxen": "^8.0.0", + "boxen": "^8.0.1", "chalk": "^5.3.0", "configstore": "^7.0.0", "is-in-ci": "^1.0.0", @@ -55,7 +55,7 @@ "esmock": "^2.6.7", "fixture-stdout": "^0.2.1", "strip-ansi": "^7.1.0", - "xo": "^0.59.2" + "xo": "^0.59.3" }, "ava": { "timeout": "20s", diff --git a/readme.md b/readme.md index 9f02f32..17f27ed 100644 --- a/readme.md +++ b/readme.md @@ -4,7 +4,7 @@ ![](screenshot.png) -Inform users of your package of updates in a non-intrusive way. +Inform users of updates for your package in a non-intrusive way. #### Contents @@ -23,7 +23,7 @@ npm install update-notifier ## Usage -### Simple +### Basic ```js import updateNotifier from 'update-notifier'; @@ -32,7 +32,7 @@ import packageJson from './package.json' assert {type: 'json'}; updateNotifier({pkg: packageJson}).notify(); ``` -### Comprehensive +### Advanced ```js import updateNotifier from 'update-notifier'; @@ -69,10 +69,10 @@ if (notifier.update) { } ``` -## How +## How it works Whenever you initiate the update notifier and it's not within the interval threshold, it will asynchronously check with npm in the background for available updates, then persist the result. The next time the notifier is initiated, the result will be loaded into the `.update` property. This prevents any impact on your package startup performance. -The update check is done in a unref'ed [child process](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options). This means that if you call `process.exit`, the check will still be performed in its own process. +The update check is done in an unref'ed [child process](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options). This means that if you call `process.exit`, the check will still be performed in its own process. The first time the user runs your app, it will check for an update, and even if an update is available, it will wait the specified `updateCheckInterval` before notifying the user. This is done to not be annoying to the user, but might surprise you as an implementer if you're testing whether it works. Check out [`example.js`](example.js) to quickly test out `update-notifier` and see how you can test that it works in your app. @@ -129,7 +129,7 @@ Returns an `object` with: - `latest` *(string)* - Latest version. - `current` *(string)* - Current version. -- `type` *(string)* - Type of current update. Possible values: `latest`, `major`, `minor`, `patch`, `prerelease`, `build`. +- `type` *(string)* - Type of the current update. Possible values: `latest`, `major`, `minor`, `patch`, `prerelease`, `build`. - `name` *(string)* - Package name. ### notifier.notify(options?) @@ -147,7 +147,7 @@ Type: `object` Type: `boolean`\ Default: `true` -Defer showing the notification to after the process has exited. +Defer showing the notification until after the process has exited. ##### message @@ -200,7 +200,7 @@ The idea for this module came from the desire to apply the browser update strate ## Users -There are a bunch projects using it: +There are a bunch of projects using it: - [npm](https://github.com/npm/npm) - Package manager for JavaScript - [Yeoman](https://yeoman.io) - Modern workflows for modern webapps @@ -208,4 +208,4 @@ There are a bunch projects using it: - [XO](https://github.com/xojs/xo) - JavaScript happiness style linter - [Node GH](https://github.com/node-gh/gh) - GitHub command line tool -[And 2700+ more…](https://www.npmjs.org/browse/depended/update-notifier) +[And 5000+ more…](https://www.npmjs.org/browse/depended/update-notifier) From cfa174a85844653bb5808c6d19076101b75e93df Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Mon, 9 Sep 2024 23:36:06 +0700 Subject: [PATCH 26/27] 7.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4fdb554..62880c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "update-notifier", - "version": "7.3.0", + "version": "7.3.1", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", "repository": "yeoman/update-notifier", From fbe4d6748b76da4e0b955ed39b7911e8804e58eb Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 7 Dec 2024 18:32:26 +0100 Subject: [PATCH 27/27] Update link --- .github/funding.yml | 2 -- contributing.md | 1 - package.json | 4 ++-- readme.md | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) delete mode 100644 .github/funding.yml delete mode 100644 contributing.md diff --git a/.github/funding.yml b/.github/funding.yml deleted file mode 100644 index c202b4b..0000000 --- a/.github/funding.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: sindresorhus -tidelift: npm/update-notifier diff --git a/contributing.md b/contributing.md deleted file mode 100644 index 4c91d7b..0000000 --- a/contributing.md +++ /dev/null @@ -1 +0,0 @@ -See the [contributing docs](https://github.com/yeoman/yeoman/blob/main/contributing.md) diff --git a/package.json b/package.json index 62880c6..d1dd489 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "version": "7.3.1", "description": "Update notifications for your CLI app", "license": "BSD-2-Clause", - "repository": "yeoman/update-notifier", - "funding": "https://github.com/yeoman/update-notifier?sponsor=1", + "repository": "sindresorhus/update-notifier", + "funding": "https://github.com/sponsors/sindresorhus", "author": { "name": "Sindre Sorhus", "email": "sindresorhus@gmail.com", diff --git a/readme.md b/readme.md index 17f27ed..ef814b2 100644 --- a/readme.md +++ b/readme.md @@ -152,7 +152,7 @@ Defer showing the notification until after the process has exited. ##### message Type: `string`\ -Default: [See above screenshot](https://github.com/yeoman/update-notifier#update-notifier-) +Default: [See above screenshot](#update-notifier-) Message that will be shown when an update is available.