diff options
author | Ruy Adorno <ruyadorno@hotmail.com> | 2022-01-27 02:32:34 +0300 |
---|---|---|
committer | Ruy Adorno <ruyadorno@hotmail.com> | 2022-01-27 18:56:07 +0300 |
commit | b51b29c563fa97aa4fbf38250d1f04e879a8d961 (patch) | |
tree | d0fd183ae83518dc5e901650d022640f4f5db920 | |
parent | 8558527c7158b2c1c353f8ab9c31de2a66ab470e (diff) |
fix(arborist): update save exact
When updating dependencies we need an extra check when filtering nodes
to be updated that ensures we do not override semver ranges that are
pointing to an exact version. e.g: =1.0.0, 1.0.0
Fixes: https://github.com/npm/cli/issues/4329
6 files changed, 145 insertions, 0 deletions
diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index d5e703238..45ef93985 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -5,6 +5,7 @@ const pacote = require('pacote') const AuditReport = require('../audit-report.js') const { subset, intersects } = require('semver') const npa = require('npm-package-arg') +const semver = require('semver') const debug = require('../debug.js') const walkUp = require('walk-up-path') @@ -1273,6 +1274,21 @@ module.exports = cls => class Reifier extends cls { } } + // Returns true if any of the edges from this node has a semver + // range definition that is an exact match to the version installed + // e.g: should return true if for a given an installed version 1.0.0, + // range is either =1.0.0 or 1.0.0 + const exactVersion = node => { + for (const edge of node.edgesIn) { + try { + if (semver.subset(edge.spec, node.version)) { + return false + } + } catch {} + } + return true + } + // helper that retrieves an array of nodes that were // potentially updated during the reify process, in order // to limit the number of nodes to check and update, only @@ -1284,6 +1300,8 @@ module.exports = cls => class Reifier extends cls { const filterDirectDependencies = node => !node.isRoot && node.resolveParent.isRoot && (!names || names.includes(node.name)) + && exactVersion(node) // skip update for exact ranges + const directDeps = this.idealTree.inventory .filter(filterDirectDependencies) diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index d5fc166a5..caa15f59f 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -2572,5 +2572,34 @@ t.test('save package.json on update', t => { ) }) + t.test('should preserve exact ranges', async t => { + const path = fixture(t, 'update-exact-version') + + await reify(path, { update: true, save: true }) + + t.equal( + require(resolve(path, 'package.json')).dependencies.abbrev, + '1.0.4', + 'should save no top level dep update to root package.json' + ) + }) + + t.test('should preserve exact ranges, missing actual tree', async t => { + const path = t.testdir({ + 'package.json': JSON.stringify({ + dependencies: { + abbrev: '1.0.4', + }, + }), + }) + + await reify(path, { update: true, save: true }) + + t.equal( + require(resolve(path, 'package.json')).dependencies.abbrev, + '1.0.4', + 'should save no top level dep update to root package.json' + ) + }) t.end() }) diff --git a/workspaces/arborist/test/fixtures/reify-cases/update-exact-version.js b/workspaces/arborist/test/fixtures/reify-cases/update-exact-version.js new file mode 100644 index 000000000..d766d3bc9 --- /dev/null +++ b/workspaces/arborist/test/fixtures/reify-cases/update-exact-version.js @@ -0,0 +1,54 @@ +// generated from test/fixtures/update-exact-version +module.exports = t => { + const path = t.testdir({ + "node_modules": { + "abbrev": { + "package.json": JSON.stringify({ + "name": "abbrev", + "version": "1.0.4", + "description": "Like ruby's abbrev module, but in js", + "author": "Isaac Z. Schlueter <i@izs.me>", + "main": "./lib/abbrev.js", + "scripts": { + "test": "node lib/abbrev.js" + }, + "repository": "http://github.com/isaacs/abbrev-js", + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE" + } + }) + } + }, + "package-lock.json": JSON.stringify({ + "name": "update-exact-version", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "abbrev": "1.0.4" + } + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + }, + "dependencies": { + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + } + }), + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "1.0.4" + } + }) +}) + return path +} diff --git a/workspaces/arborist/test/fixtures/update-exact-version/node_modules/abbrev/package.json b/workspaces/arborist/test/fixtures/update-exact-version/node_modules/abbrev/package.json new file mode 100644 index 000000000..72042a5b9 --- /dev/null +++ b/workspaces/arborist/test/fixtures/update-exact-version/node_modules/abbrev/package.json @@ -0,0 +1,15 @@ +{ + "name": "abbrev", + "version": "1.0.4", + "description": "Like ruby's abbrev module, but in js", + "author": "Isaac Z. Schlueter <i@izs.me>", + "main": "./lib/abbrev.js", + "scripts": { + "test": "node lib/abbrev.js" + }, + "repository": "http://github.com/isaacs/abbrev-js", + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE" + } +} diff --git a/workspaces/arborist/test/fixtures/update-exact-version/package-lock.json b/workspaces/arborist/test/fixtures/update-exact-version/package-lock.json new file mode 100644 index 000000000..0d7b5f647 --- /dev/null +++ b/workspaces/arborist/test/fixtures/update-exact-version/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "update-exact-version", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "abbrev": "1.0.4" + } + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + }, + "dependencies": { + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + } +} diff --git a/workspaces/arborist/test/fixtures/update-exact-version/package.json b/workspaces/arborist/test/fixtures/update-exact-version/package.json new file mode 100644 index 000000000..4fa414793 --- /dev/null +++ b/workspaces/arborist/test/fixtures/update-exact-version/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "abbrev": "1.0.4" + } +} |