From e135c2bb360dcf00ecee34a95985afec21ba3655 Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Tue, 2 Oct 2018 20:23:34 +0200 Subject: [PATCH 1/4] update: re-enable updating local packages PR #11584 removed the possibility of updating local packages (linked with symlinks) with `npm update`. Reason was that this functionality didn't work in v3.6.0. However, the system behind local dependencies has since changed, and I can't reproduce the original error anymore. Reverts 59e5056a2129cb2951f4ff3b657ada20657f01a7 Fixes: https://npm.community/t/1725?u=larsgw PR-URL: https://github.com/npm/cli/pull/73 Credit: @larsgw Reviewed-By: @iarna Reviewed-By: @zkat --- lib/outdated.js | 2 +- lib/update.js | 2 +- test/tap/outdated-symlink.js | 133 +++++++++++++++++++++++++++++++++++ test/tap/update-symlink.js | 109 ++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 test/tap/outdated-symlink.js create mode 100644 test/tap/update-symlink.js diff --git a/lib/outdated.js b/lib/outdated.js index ebd67fb6b37d5..baeb5e7179df4 100644 --- a/lib/outdated.js +++ b/lib/outdated.js @@ -157,7 +157,7 @@ function makePretty (p, opts) { } if (opts.color) { - columns[0] = color[has === want || want === 'linked' ? 'yellow' : 'red'](columns[0]) // dep + columns[0] = color[has === want ? 'yellow' : 'red'](columns[0]) // dep columns[2] = color.green(columns[2]) // want columns[3] = color.magenta(columns[3]) // latest } diff --git a/lib/update.js b/lib/update.js index 9b1345f9dfbfb..fdb934fac6730 100644 --- a/lib/update.js +++ b/lib/update.js @@ -46,7 +46,7 @@ function update_ (args) { "because it's currently at the maximum version that matches its specified semver range" ) } - return ww.current !== ww.wanted && ww.latest !== 'linked' + return ww.current !== ww.wanted }) if (wanted.length === 0) return diff --git a/test/tap/outdated-symlink.js b/test/tap/outdated-symlink.js new file mode 100644 index 0000000000000..96d6f660e2100 --- /dev/null +++ b/test/tap/outdated-symlink.js @@ -0,0 +1,133 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const File = Tacks.File +const Symlink = Tacks.Symlink +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: path.join(testdir, 'main'), + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +let server +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + broken: Dir({ + 'package.json': File({ + name: 'broken', + version: '1.0.0' + }) + }), + main: Dir({ + node_modules: Dir({ + unbroken: Symlink('/testdir/unbroken') + }), + 'package-lock.json': File({ + name: 'main', + version: '1.0.0', + lockfileVersion: 1, + requires: true, + dependencies: { + broken: { + version: 'file:../broken' + }, + unbroken: { + version: 'file:../unbroken' + } + } + }), + 'package.json': File({ + name: 'main', + version: '1.0.0', + dependencies: { + broken: 'file:../broken', + unbroken: 'file:../unbroken' + } + }) + }), + unbroken: Dir({ + 'package.json': File({ + name: 'unbroken', + version: '1.0.0' + }) + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + t.done() + }) +}) + +test('outdated sees broken links', function (t) { + common.npm(['outdated', '--json'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 1, 'command ran not ok') + t.comment(stderr.trim()) + t.comment(stdout.trim()) + t.same(JSON.parse(stdout), { + broken: { + wanted: 'linked', + latest: 'linked', + location: '' + } + }) + t.done() + }) +}) + +test('outdated with long output sees broken links', function (t) { + common.npm(['outdated', '--long', '--json'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 1, 'command ran not ok') + t.comment(stderr.trim()) + t.comment(stdout.trim()) + t.same(JSON.parse(stdout), { + broken: { + wanted: 'linked', + latest: 'linked', + type: 'dependencies', + location: '' + } + }) + t.done() + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +}) diff --git a/test/tap/update-symlink.js b/test/tap/update-symlink.js new file mode 100644 index 0000000000000..79139d306f5fd --- /dev/null +++ b/test/tap/update-symlink.js @@ -0,0 +1,109 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const File = Tacks.File +const Symlink = Tacks.Symlink +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: path.join(testdir, 'main'), + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +let server +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + broken: Dir({ + 'package.json': File({ + name: 'broken', + version: '1.0.0' + }) + }), + main: Dir({ + node_modules: Dir({ + unbroken: Symlink('/testdir/unbroken') + }), + 'package-lock.json': File({ + name: 'main', + version: '1.0.0', + lockfileVersion: 1, + requires: true, + dependencies: { + broken: { + version: 'file:../broken' + }, + unbroken: { + version: 'file:../unbroken' + } + } + }), + 'package.json': File({ + name: 'main', + version: '1.0.0', + dependencies: { + broken: 'file:../broken', + unbroken: 'file:../unbroken' + } + }) + }), + unbroken: Dir({ + 'package.json': File({ + name: 'unbroken', + version: '1.0.0' + }) + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + t.done() + }) +}) + +test('update fixes broken links', function (t) { + common.npm(['update'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 0, 'command ran ok') + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.match(stdout, '+ broken@1.0.0') + t.done() + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +}) From 2ce23baf53b1ce7d11b8efb80c598ddaf9cef9e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Mon, 18 Feb 2019 14:58:47 -0800 Subject: [PATCH 2/4] lock-verify@2.1.0 Adds support for package aliases --- node_modules/lock-verify/index.js | 14 ++++++++--- node_modules/lock-verify/package.json | 35 +++++++++++++-------------- package-lock.json | 8 +++--- package.json | 2 +- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/node_modules/lock-verify/index.js b/node_modules/lock-verify/index.js index 22721329134d7..cf673888faf01 100644 --- a/node_modules/lock-verify/index.js +++ b/node_modules/lock-verify/index.js @@ -36,9 +36,17 @@ function lockVerify(check) { if (spec.registry) { // Can't match tags to package-lock w/o network if (spec.type === 'tag') return - if (!semver.satisfies(lock.version, spec.fetchSpec)) { - errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.fetchSpec) - return + if (spec.type === 'alias') { + const lockSpec = npa.resolve(name, lock.version) + if (!semver.satisfies(lockSpec.subSpec.fetchSpec, spec.subSpec.fetchSpec)) { + errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.rawSpec) + return + } + } else { + if (!semver.satisfies(lock.version, spec.fetchSpec)) { + errors.push("Invalid: lock file's " + name + '@' + lock.version + ' does not satisfy ' + name + '@' + spec.fetchSpec) + return + } } } else if (spec.type === 'git') { // can't verify git w/o network diff --git a/node_modules/lock-verify/package.json b/node_modules/lock-verify/package.json index 0f2002f549e5a..621c12fb76e87 100644 --- a/node_modules/lock-verify/package.json +++ b/node_modules/lock-verify/package.json @@ -1,33 +1,30 @@ { - "_args": [ - [ - "lock-verify@2.0.2", - "/Users/rebecca/code/npm" - ] - ], - "_from": "lock-verify@2.0.2", - "_id": "lock-verify@2.0.2", + "_from": "lock-verify@2.1.0", + "_id": "lock-verify@2.1.0", "_inBundle": false, - "_integrity": "sha512-QNVwK0EGZBS4R3YQ7F1Ox8p41Po9VGl2QG/2GsuvTbkJZYSsPeWHKMbbH6iZMCHWSMww5nrJroZYnGzI4cePuw==", + "_integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", "_location": "/lock-verify", "_phantomChildren": {}, "_requested": { "type": "version", "registry": true, - "raw": "lock-verify@2.0.2", + "raw": "lock-verify@2.1.0", "name": "lock-verify", "escapedName": "lock-verify", - "rawSpec": "2.0.2", + "rawSpec": "2.1.0", "saveSpec": null, - "fetchSpec": "2.0.2" + "fetchSpec": "2.1.0" }, "_requiredBy": [ + "#USER", "/", - "/libcipm" + "/libcipm", + "/libnpm" ], - "_resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.0.2.tgz", - "_spec": "2.0.2", - "_where": "/Users/rebecca/code/npm", + "_resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", + "_shasum": "fff4c918b8db9497af0c5fa7f6d71555de3ceb47", + "_spec": "lock-verify@2.1.0", + "_where": "/Users/zkat/Documents/code/work/npm", "author": { "name": "Rebecca Turner", "email": "me@re-becca.org", @@ -36,10 +33,12 @@ "bugs": { "url": "https://github.com/iarna/lock-verify/issues" }, + "bundleDependencies": false, "dependencies": { - "npm-package-arg": "^5.1.2 || 6", + "npm-package-arg": "^6.1.0", "semver": "^5.4.1" }, + "deprecated": false, "description": "Report if your package.json is out of sync with your package-lock.json.", "devDependencies": { "@iarna/cli": "^1.2.0" @@ -59,5 +58,5 @@ "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, - "version": "2.0.2" + "version": "2.1.0" } diff --git a/package-lock.json b/package-lock.json index eefd8067bbce2..11cefb7f720ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2812,11 +2812,11 @@ } }, "lock-verify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.0.2.tgz", - "integrity": "sha512-QNVwK0EGZBS4R3YQ7F1Ox8p41Po9VGl2QG/2GsuvTbkJZYSsPeWHKMbbH6iZMCHWSMww5nrJroZYnGzI4cePuw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", + "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", "requires": { - "npm-package-arg": "^5.1.2 || 6", + "npm-package-arg": "^6.1.0", "semver": "^5.4.1" } }, diff --git a/package.json b/package.json index d08661a8e8f0e..6920c329af406 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "libnpm": "^2.0.1", "libnpmhook": "^5.0.2", "libnpx": "^10.2.0", - "lock-verify": "^2.0.2", + "lock-verify": "^2.1.0", "lockfile": "^1.0.4", "lodash._baseuniq": "~4.6.0", "lodash.clonedeep": "~4.5.0", From 82aedcbcd8df68a91c5bb599ea65de68136484b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Mon, 18 Feb 2019 15:24:06 -0800 Subject: [PATCH 3/4] pacote@9.5.0 Adds opts.before support --- node_modules/pacote/CHANGELOG.md | 10 ++++++++++ node_modules/pacote/README.md | 2 +- node_modules/pacote/lib/util/opt-check.js | 1 + node_modules/pacote/package.json | 24 +++++++++++------------ package-lock.json | 6 +++--- package.json | 2 +- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/node_modules/pacote/CHANGELOG.md b/node_modules/pacote/CHANGELOG.md index a7784d9bb1193..1c8feb9a79377 100644 --- a/node_modules/pacote/CHANGELOG.md +++ b/node_modules/pacote/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +# [9.5.0](https://github.com/zkat/pacote/compare/v9.4.1...v9.5.0) (2019-02-18) + + +### Features + +* **enjoy-by:** add `before` as an alias to enjoy-by ([75d62b7](https://github.com/zkat/pacote/commit/75d62b7)) + + + ## [9.4.1](https://github.com/zkat/pacote/compare/v9.4.0...v9.4.1) (2019-01-24) diff --git a/node_modules/pacote/README.md b/node_modules/pacote/README.md index 8d160b7cb73ed..bf2e5f4f61e9f 100644 --- a/node_modules/pacote/README.md +++ b/node_modules/pacote/README.md @@ -231,7 +231,7 @@ even though npm itself does. ##### `opts.enjoy-by` -* Alias: `opts.enjoyBy` +* Alias: `opts.enjoyBy`, `opts.before` * Type: Date-able * Default: undefined diff --git a/node_modules/pacote/lib/util/opt-check.js b/node_modules/pacote/lib/util/opt-check.js index e6afc21c849c4..8b6b472f850eb 100644 --- a/node_modules/pacote/lib/util/opt-check.js +++ b/node_modules/pacote/lib/util/opt-check.js @@ -13,6 +13,7 @@ module.exports = figgyPudding({ dmode: {}, 'enjoy-by': 'enjoyBy', enjoyBy: {}, + before: 'enjoyBy', fmode: {}, 'fetch-retries': { default: 2 }, 'fetch-retry-factor': { default: 10 }, diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 96ae38bd682a6..896afe5a77dd2 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,21 +1,21 @@ { - "_from": "pacote@9.4.1", - "_id": "pacote@9.4.1", + "_from": "pacote@latest", + "_id": "pacote@9.5.0", "_inBundle": false, - "_integrity": "sha512-YKSRsQqmeHxgra0KCdWA2FtVxDPUlBiCdmew+mSe44pzlx5t1ViRMWiQg18T+DREA+vSqYfKzynaToFR4hcKHw==", + "_integrity": "sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg==", "_location": "/pacote", "_phantomChildren": { "safe-buffer": "5.1.2" }, "_requested": { - "type": "version", + "type": "tag", "registry": true, - "raw": "pacote@9.4.1", + "raw": "pacote@latest", "name": "pacote", "escapedName": "pacote", - "rawSpec": "9.4.1", + "rawSpec": "latest", "saveSpec": null, - "fetchSpec": "9.4.1" + "fetchSpec": "latest" }, "_requiredBy": [ "#USER", @@ -23,10 +23,10 @@ "/libcipm", "/libnpm" ], - "_resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.1.tgz", - "_shasum": "f0af2a52d241bce523d39280ac810c671db62279", - "_spec": "pacote@9.4.1", - "_where": "/Users/aeschright/code/npm-release", + "_resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.0.tgz", + "_shasum": "85f3013a3f6dd51c108b0ccabd3de8102ddfaeda", + "_spec": "pacote@latest", + "_where": "/Users/zkat/Documents/code/work/npm", "author": { "name": "Kat Marchán", "email": "kzm@sykosomatic.org" @@ -116,5 +116,5 @@ "update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" }, - "version": "9.4.1" + "version": "9.5.0" } diff --git a/package-lock.json b/package-lock.json index 11cefb7f720ab..508fd3d8baf0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6190,9 +6190,9 @@ } }, "pacote": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.1.tgz", - "integrity": "sha512-YKSRsQqmeHxgra0KCdWA2FtVxDPUlBiCdmew+mSe44pzlx5t1ViRMWiQg18T+DREA+vSqYfKzynaToFR4hcKHw==", + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.0.tgz", + "integrity": "sha512-aUplXozRbzhaJO48FaaeClmN+2Mwt741MC6M3bevIGZwdCaP7frXzbUOfOWa91FPHoLITzG0hYaKY363lxO3bg==", "requires": { "bluebird": "^3.5.3", "cacache": "^11.3.2", diff --git a/package.json b/package.json index 6920c329af406..79815b394ca69 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "once": "~1.4.0", "opener": "^1.5.1", "osenv": "^0.1.5", - "pacote": "^9.4.1", + "pacote": "^9.5.0", "path-is-inside": "~1.0.2", "promise-inflight": "~1.0.1", "qrcode-terminal": "^0.12.0", From 047ca9edd78f881b3185646119b96ec4f33ea1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kat=20March=C3=A1n?= Date: Tue, 30 Oct 2018 20:14:03 -0700 Subject: [PATCH 4/4] install: add --before date support for time traveling~ --- doc/misc/npm-config.md | 16 +++++++ lib/config/defaults.js | 3 ++ lib/install.js | 21 ++++++++- test/tap/install-before.js | 89 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 test/tap/install-before.js diff --git a/doc/misc/npm-config.md b/doc/misc/npm-config.md index 8f04a76010c1a..88d30b62ca252 100644 --- a/doc/misc/npm-config.md +++ b/doc/misc/npm-config.md @@ -179,6 +179,22 @@ a non-zero exit code. What authentication strategy to use with `adduser`/`login`. +### before + +* Alias: enjoy-by +* Default: null +* Type: Date + +If passed to `npm install`, will rebuild the npm tree such that only versions +that were available **on or before** the `--before` time get installed. +If there's no versions available for the current set of direct dependencies, the +command will error. + +If the requested version is a `dist-tag` and the given tag does not pass the +`--before` filter, the most recent version less than or equal to that tag will +be used. For example, `foo@latest` might install `foo@1.2` even though `latest` +is `2.0`. + ### bin-links * Default: `true` diff --git a/lib/config/defaults.js b/lib/config/defaults.js index 2592659539120..f563357d4cba3 100644 --- a/lib/config/defaults.js +++ b/lib/config/defaults.js @@ -113,6 +113,7 @@ Object.defineProperty(exports, 'defaults', {get: function () { 'audit-level': 'low', 'auth-type': 'legacy', + 'before': null, 'bin-links': true, browser: null, @@ -260,6 +261,7 @@ exports.types = { audit: Boolean, 'audit-level': ['low', 'moderate', 'high', 'critical'], 'auth-type': ['legacy', 'sso', 'saml', 'oauth'], + 'before': [null, Date], 'bin-links': Boolean, browser: [null, String], ca: [null, String, Array], @@ -394,6 +396,7 @@ function getLocalAddresses () { } exports.shorthands = { + before: ['--enjoy-by'], s: ['--loglevel', 'silent'], d: ['--loglevel', 'info'], dd: ['--loglevel', 'verbose'], diff --git a/lib/install.js b/lib/install.js index e15bc47919100..49418b8294832 100644 --- a/lib/install.js +++ b/lib/install.js @@ -703,8 +703,25 @@ Installer.prototype.cloneCurrentTreeToIdealTree = function (cb) { validate('F', arguments) log.silly('install', 'cloneCurrentTreeToIdealTree') - this.idealTree = copyTree(this.currentTree) - this.idealTree.warnings = [] + if (npm.config.get('before')) { + this.idealTree = { + package: this.currentTree.package, + path: this.currentTree.path, + realpath: this.currentTree.realpath, + children: [], + requires: [], + missingDeps: {}, + missingDevDeps: {}, + requiredBy: [], + error: this.currentTree.error, + warnings: [], + isTop: true + } + } else { + this.idealTree = copyTree(this.currentTree) + this.idealTree.warnings = [] + } + cb() } diff --git a/test/tap/install-before.js b/test/tap/install-before.js new file mode 100644 index 0000000000000..c99b996c43029 --- /dev/null +++ b/test/tap/install-before.js @@ -0,0 +1,89 @@ +'use strict' + +const BB = require('bluebird') + +const common = require('../common-tap.js') +const mockTar = require('../util/mock-tarball.js') +const mr = common.fakeRegistry.compat +const path = require('path') +const rimraf = BB.promisify(require('rimraf')) +const Tacks = require('tacks') +const { test } = require('tap') + +const { Dir, File } = Tacks + +const testDir = path.join(__dirname, path.basename(__filename, '.js')) + +let server +test('setup', t => { + mr({}, (err, s) => { + t.ifError(err, 'registry mocked successfully') + server = s + t.end() + }) +}) + +test('installs an npm package before a certain date', t => { + const fixture = new Tacks(Dir({ + 'package.json': File({}) + })) + fixture.create(testDir) + const packument = { + name: 'foo', + 'dist-tags': { latest: '1.2.4' }, + versions: { + '1.2.3': { + name: 'foo', + version: '1.2.3', + dist: { + tarball: `${server.registry}/foo/-/foo-1.2.3.tgz` + } + }, + '1.2.4': { + name: 'foo', + version: '1.2.4', + dist: { + tarball: `${server.registry}/foo/-/foo-1.2.4.tgz` + } + } + }, + time: { + created: '2017-01-01T00:00:01.000Z', + modified: '2018-01-01T00:00:01.000Z', + '1.2.3': '2017-01-01T00:00:01.000Z', + '1.2.4': '2018-01-01T00:00:01.000Z' + } + } + server.get('/foo').reply(200, packument) + return mockTar({ + 'package.json': JSON.stringify({ + name: 'foo', + version: '1.2.3' + }) + }).then(tarball => { + server.get('/foo/-/foo-1.2.3.tgz').reply(200, tarball) + server.get('/foo/-/foo-1.2.4.tgz').reply(500) + return common.npm([ + 'install', 'foo', + '--before', '2018', + '--json', + '--cache', path.join(testDir, 'npmcache'), + '--registry', server.registry + ], { cwd: testDir }) + }).then(([code, stdout, stderr]) => { + t.comment(stdout) + t.comment(stderr) + t.like(JSON.parse(stdout), { + added: [{ + action: 'add', + name: 'foo', + version: '1.2.3' + }] + }, 'installed the 2017 version of the package') + }) +}) + +test('cleanup', t => { + server.close() + return rimraf(testDir) +})