Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/npm/cli.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/npm-cli.js66
-rw-r--r--lib/utils/update-notifier.js57
-rw-r--r--tap-snapshots/test-lib-utils-update-notifier.js-TAP.test.js78
-rw-r--r--test/lib/utils/update-notifier.js121
4 files changed, 260 insertions, 62 deletions
diff --git a/bin/npm-cli.js b/bin/npm-cli.js
index d760e8cdb..7507ef40a 100755
--- a/bin/npm-cli.js
+++ b/bin/npm-cli.js
@@ -4,8 +4,7 @@ process.title = 'npm'
const {
checkForBrokenNode,
- checkForUnsupportedNode,
- checkVersion
+ checkForUnsupportedNode
} = require('../lib/utils/unsupported.js')
checkForBrokenNode()
@@ -49,71 +48,14 @@ log.info('using', 'node@%s', process.version)
process.on('uncaughtException', errorHandler)
process.on('unhandledRejection', errorHandler)
-const isGlobalNpmUpdate = npm => {
- return npm.config.get('global') &&
- ['install', 'update'].includes(npm.command) &&
- npm.argv.includes('npm')
-}
-
// now actually fire up npm and run the command.
// this is how to use npm programmatically:
conf._exit = true
+const updateNotifier = require('../lib/utils/update-notifier.js')
npm.load(conf, function (er) {
if (er) return errorHandler(er)
- if (
- !isGlobalNpmUpdate(npm) &&
- npm.config.get('update-notifier') &&
- !checkVersion(process.version).unsupported
- ) {
- // XXX move update notifier stuff into separate module
- const pkg = require('../package.json')
- let notifier = require('update-notifier')({pkg})
- // XXX should use @npmcli/ci-detect
- const isCI = require('ci-info').isCI
- if (
- notifier.update &&
- notifier.update.latest !== pkg.version &&
- !isCI
- ) {
- const color = require('ansicolors')
- const useColor = npm.color
- const useUnicode = npm.config.get('unicode')
- const old = notifier.update.current
- const latest = notifier.update.latest
- let type = notifier.update.type
- if (useColor) {
- switch (type) {
- case 'major':
- type = color.red(type)
- break
- case 'minor':
- type = color.yellow(type)
- break
- case 'patch':
- type = color.green(type)
- break
- }
- }
- const changelog = `https://github.com/npm/cli/releases/tag/v${latest}`
- notifier.notify({
- message: `New ${type} version of ${pkg.name} available! ${
- useColor ? color.red(old) : old
- } ${useUnicode ? '→' : '->'} ${
- useColor ? color.green(latest) : latest
- }\n` +
- `${
- useColor ? color.yellow('Changelog:') : 'Changelog:'
- } ${
- useColor ? color.cyan(changelog) : changelog
- }\n` +
- `Run ${
- useColor
- ? color.green(`npm install -g ${pkg.name}`)
- : `npm i -g ${pkg.name}`
- } to update!`
- })
- }
- }
+
+ updateNotifier(npm)
const cmd = npm.argv.shift()
const impl = npm.commands[cmd]
diff --git a/lib/utils/update-notifier.js b/lib/utils/update-notifier.js
new file mode 100644
index 000000000..a6abe948b
--- /dev/null
+++ b/lib/utils/update-notifier.js
@@ -0,0 +1,57 @@
+// print a banner telling the user to upgrade npm to latest
+// but not in CI, and not if we're doing that already.
+
+const isGlobalNpmUpdate = npm => {
+ return npm.config.get('global') &&
+ ['install', 'update'].includes(npm.command) &&
+ npm.argv.includes('npm')
+}
+
+const { checkVersion } = require('./unsupported.js')
+
+module.exports = (npm) => {
+ if (!npm.config.get('update-notifier') ||
+ isGlobalNpmUpdate(npm) ||
+ checkVersion(process.version).unsupported) {
+ return
+ }
+
+ const pkg = require('../../package.json')
+ const notifier = require('update-notifier')({pkg})
+ const ciDetect = require('@npmcli/ci-detect')
+ if (
+ notifier.update &&
+ notifier.update.latest !== pkg.version &&
+ !ciDetect()
+ ) {
+ const chalk = require('chalk')
+ const useColor = npm.color
+ const useUnicode = npm.config.get('unicode')
+ const old = notifier.update.current
+ const latest = notifier.update.latest
+ const type = notifier.update.type
+ const typec = !useColor ? type
+ : type === 'major' ? chalk.red(type)
+ : type === 'minor' ? chalk.yellow(type)
+ : chalk.green(type)
+
+ const changelog = `https://github.com/npm/cli/releases/tag/v${latest}`
+ notifier.notify({
+ message: `New ${typec} version of ${pkg.name} available! ${
+ useColor ? chalk.red(old) : old
+ } ${useUnicode ? '→' : '->'} ${
+ useColor ? chalk.green(latest) : latest
+ }\n` +
+ `${
+ useColor ? chalk.yellow('Changelog:') : 'Changelog:'
+ } ${
+ useColor ? chalk.cyan(changelog) : changelog
+ }\n` +
+ `Run ${
+ useColor
+ ? chalk.green(`npm install -g ${pkg.name}`)
+ : `npm i -g ${pkg.name}`
+ } to update!`
+ })
+ }
+}
diff --git a/tap-snapshots/test-lib-utils-update-notifier.js-TAP.test.js b/tap-snapshots/test-lib-utils-update-notifier.js-TAP.test.js
new file mode 100644
index 000000000..2bc52e1fe
--- /dev/null
+++ b/tap-snapshots/test-lib-utils-update-notifier.js-TAP.test.js
@@ -0,0 +1,78 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/lib/utils/update-notifier.js TAP notification situations color and unicode major > must match snapshot 1`] = `
+New major version of npm available! <<major>>-beta → 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm install -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations color and unicode minor > must match snapshot 1`] = `
+New minor version of npm available! <<minor>>-beta → 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm install -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations color and unicode minor > must match snapshot 2`] = `
+New patch version of npm available! <<patch>>-beta → 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm install -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations color, no unicode major > must match snapshot 1`] = `
+New major version of npm available! <<major>>-beta -> 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm install -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations color, no unicode minor > must match snapshot 1`] = `
+New minor version of npm available! <<minor>>-beta -> 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm install -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations color, no unicode minor > must match snapshot 2`] = `
+New patch version of npm available! <<patch>>-beta -> 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm install -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations no color, no unicode major > must match snapshot 1`] = `
+New major version of npm available! <<major>>-beta -> 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm i -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations no color, no unicode minor > must match snapshot 1`] = `
+New minor version of npm available! <<minor>>-beta -> 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm i -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations no color, no unicode minor > must match snapshot 2`] = `
+New patch version of npm available! <<patch>>-beta -> 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm i -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations unicode, no color major > must match snapshot 1`] = `
+New major version of npm available! <<major>>-beta → 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm i -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations unicode, no color minor > must match snapshot 1`] = `
+New minor version of npm available! <<minor>>-beta → 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm i -g npm to update!
+`
+
+exports[`test/lib/utils/update-notifier.js TAP notification situations unicode, no color minor > must match snapshot 2`] = `
+New patch version of npm available! <<patch>>-beta → 7.0.0
+Changelog: https://github.com/npm/cli/releases/tag/v7.0.0
+Run npm i -g npm to update!
+`
diff --git a/test/lib/utils/update-notifier.js b/test/lib/utils/update-notifier.js
new file mode 100644
index 000000000..c55a2c1d4
--- /dev/null
+++ b/test/lib/utils/update-notifier.js
@@ -0,0 +1,121 @@
+const t = require('tap')
+const requireInject = require('require-inject')
+const notifierMock = {}
+const unsupportedMock = {}
+const unsupported = () => unsupportedMock
+let ciMock = null
+const updateNotifier = requireInject.installGlobally('../../../lib/utils/update-notifier.js', {
+ 'update-notifier': () => notifierMock,
+ '../../../lib/utils/unsupported.js': { checkVersion: unsupported },
+ '@npmcli/ci-detect': () => ciMock
+})
+const { version } = require('../../../package.json')
+const semver = require('semver')
+
+t.test('situations in which we do not notify', t => {
+ t.test('nothing to do if notifier disabled', t => {
+ Object.assign(notifierMock, {
+ notify: () => { throw new Error('should not notify!') },
+ update: { latest: '99.99.99' },
+ })
+ updateNotifier({
+ config: { get: (k) => k === 'update-notifier' ? false : true },
+ })
+ t.end()
+ })
+
+ t.test('do not suggest update if already updating', t => {
+ Object.assign(notifierMock, {
+ notify: () => { throw new Error('should not notify!') },
+ update: { latest: '99.99.99' },
+ })
+ updateNotifier({
+ config: { get: (k) => true },
+ command: 'install',
+ argv: ['npm']
+ })
+ t.end()
+ })
+
+ t.test('do not suggest update if version if unsupported', t => {
+ t.teardown(() => { delete unsupportedMock.unsupported })
+ unsupportedMock.unsupported = true
+ Object.assign(notifierMock, {
+ notify: () => { throw new Error('should not notify!') },
+ update: { latest: '99.99.99' },
+ })
+ updateNotifier({
+ config: { get: (k) => k !== 'global' },
+ command: 'view',
+ argv: ['npm']
+ })
+ t.end()
+ })
+
+ t.test('do not update if nothing to update', t => {
+ Object.assign(notifierMock, {
+ notify: () => { throw new Error('should not notify!') },
+ update: { latest: version },
+ })
+ updateNotifier({
+ config: { get: (k) => k !== 'global' },
+ command: 'view',
+ argv: ['npm']
+ })
+ t.end()
+ })
+
+ t.test('do not update in CI', t => {
+ t.teardown(() => { ciMock = null })
+ ciMock = 'something'
+ Object.assign(notifierMock, {
+ notify: () => { throw new Error('should not notify!') },
+ update: { latest: '99.99.99' },
+ })
+ updateNotifier({
+ config: { get: (k) => k !== 'global' },
+ command: 'view',
+ argv: ['npm']
+ })
+ t.end()
+ })
+
+ t.end()
+})
+
+t.test('notification situations', t => {
+ const runTests = (config, t) => {
+ t.plan(3)
+ t.test('major', t => runTest(config, 'major', t))
+ t.test('minor', t => runTest(config, 'minor', t))
+ t.test('minor', t => runTest(config, 'patch', t))
+ }
+
+ const runTest = (config, type, t) => {
+ t.plan(1)
+ const latest = type === 'major' ? semver.inc(version, 'major')
+ : type === 'minor' ? semver.inc(version, 'minor')
+ : type === 'patch' ? semver.inc(version, 'patch')
+ : null
+
+ Object.assign(notifierMock, {
+ notify: ({ message }) => {
+ // swap this out so we don't have to regen snapshots each version bump
+ t.matchSnapshot(message.replace(latest, `<<${type}>>`))
+ },
+ update: { latest, type, current: version }
+ })
+ updateNotifier({
+ color: config.color,
+ config: { get: (k) => k === 'update-notifier' ? true : !!config[k] },
+ command: 'view',
+ argv: ['npm']
+ })
+ }
+
+ t.plan(4)
+ t.test('color and unicode', t => runTests({ unicode: true, color: true }, t))
+ t.test('color, no unicode', t => runTests({ color: true }, t))
+ t.test('unicode, no color', t => runTests({ unicode: true }, t))
+ t.test('no color, no unicode', t => runTests({}, t))
+})