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:
-rw-r--r--doc/misc/npm-config.md16
-rw-r--r--lib/config/defaults.js3
-rw-r--r--lib/install.js21
-rw-r--r--test/tap/install-before.js89
4 files changed, 127 insertions, 2 deletions
diff --git a/doc/misc/npm-config.md b/doc/misc/npm-config.md
index 8f04a7601..88d30b62c 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 259265953..f563357d4 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 34a02962c..d2f705e1d 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 000000000..c99b996c4
--- /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)
+})