diff options
author | Ruy Adorno <ruyadorno@hotmail.com> | 2022-01-20 21:52:00 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-20 21:52:00 +0300 |
commit | cfd59b8c81078f842328b13a23a234150842cd58 (patch) | |
tree | 74fd15153445b59dda6b1d5ec4e8c64436115e94 /workspaces | |
parent | 510f0ecbc9970ed8c8993107cc03cf27b7b996dc (diff) |
fix: npm update --save (#4223)
Previously `npm update` was not respecting the `save` option, it
would be impossible for users to use `npm update` and automatically
update their `package.json` files.
This fixes it by adding extra steps on `Arborist.reify._saveIdealTree`
to read direct dependencies of any `package.json` and update them as
needed when reifying using the `update` and `save` options.
- Uses config.isDefault to set a different value for the `save` config
for both the update and dedupe commands
- Tweaks arborist to make sure saveIdealTree preserves the behavior of
skipping writing to package-lock.json on save=false for install while
still writing the lockfile for `npm update` with its new default value
of save=false.
- Updated and added some new tests on arborist to cover for these tweaks
- Added `npm update --save` smoke test on cli
Fixes: https://github.com/npm/cli/issues/708
Fixes: https://github.com/npm/cli/issues/2704
Relates to: https://github.com/npm/feedback/discussions/270
Diffstat (limited to 'workspaces')
10 files changed, 1044 insertions, 57 deletions
diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index dffcd546b..ff0cc3480 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -41,7 +41,7 @@ const _complete = Symbol('complete') const _depsSeen = Symbol('depsSeen') const _depsQueue = Symbol('depsQueue') const _currentDep = Symbol('currentDep') -const _updateAll = Symbol('updateAll') +const _updateAll = Symbol.for('updateAll') const _mutateTree = Symbol('mutateTree') const _flagsSuspect = Symbol.for('flagsSuspect') const _workspaces = Symbol.for('workspaces') diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 547e54ac3..d5e703238 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -58,6 +58,8 @@ const _bundleUnpacked = Symbol('bundleUnpacked') const _bundleMissing = Symbol('bundleMissing') const _reifyNode = Symbol.for('reifyNode') const _extractOrLink = Symbol('extractOrLink') +const _updateAll = Symbol.for('updateAll') +const _updateNames = Symbol.for('updateNames') // defined by rebuild mixin const _checkBins = Symbol.for('checkBins') const _symlink = Symbol('symlink') @@ -1140,21 +1142,33 @@ module.exports = cls => class Reifier extends cls { // for install failures. Those still end up in the shrinkwrap, so we // save it first, then prune out the optional trash, and then return it. - // support save=false option - if (options.save === false || this[_global] || this[_dryRun]) { + const save = !(options.save === false) + + // we check for updates in order to make sure we run save ideal tree + // even though save=false since we want `npm update` to be able to + // write to package-lock files by default + const hasUpdates = this[_updateAll] || this[_updateNames].length + + // we're going to completely skip save ideal tree in case of a global or + // dry-run install and also if the save option is set to false, EXCEPT for + // update since the expected behavior for npm7+ is for update to + // NOT save to package.json, we make that exception since we still want + // saveIdealTree to be able to write the lockfile by default. + const saveIdealTree = !( + (!save && !hasUpdates) + || this[_global] + || this[_dryRun] + ) + + if (!saveIdealTree) { return false } process.emit('time', 'reify:save') const updatedTrees = new Set() - - // resolvedAdd is the list of user add requests, but with names added - // to things like git repos and tarball file/urls. However, if the - // user requested 'foo@', and we have a foo@file:../foo, then we should - // end up saving the spec we actually used, not whatever they gave us. - if (this[_resolvedAdd].length) { - for (const { name, tree: addTree } of this[_resolvedAdd]) { + const updateNodes = nodes => { + for (const { name, tree: addTree } of nodes) { // addTree either the root, or a workspace const edge = addTree.edgesOut.get(name) const pkg = addTree.package @@ -1168,7 +1182,7 @@ module.exports = cls => class Reifier extends cls { // that we couldn't resolve, this MAY be missing. if we haven't // blown up by now, it's because it was not a problem, though, so // just move on. - if (!child) { + if (!child || !addTree.isTop) { continue } @@ -1259,6 +1273,63 @@ module.exports = cls => class Reifier extends cls { } } + // 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 + // select nodes from the inventory that are direct deps + // of a given package.json (project root or a workspace) + // and in ase of using a list of `names`, restrict nodes + // to only names that are found in this list + const retrieveUpdatedNodes = names => { + const filterDirectDependencies = node => + !node.isRoot && node.resolveParent.isRoot + && (!names || names.includes(node.name)) + const directDeps = this.idealTree.inventory + .filter(filterDirectDependencies) + + // traverses the list of direct dependencies and collect all nodes + // to be updated, since any of them might have changed during reify + const nodes = [] + for (const node of directDeps) { + for (const edgeIn of node.edgesIn) { + nodes.push({ + name: node.name, + tree: edgeIn.from.target, + }) + } + } + return nodes + } + + if (save) { + // when using update all alongside with save, we'll make + // sure to refresh every dependency of the root idealTree + if (this[_updateAll]) { + const nodes = retrieveUpdatedNodes() + updateNodes(nodes) + } else { + // resolvedAdd is the list of user add requests, but with names added + // to things like git repos and tarball file/urls. However, if the + // user requested 'foo@', and we have a foo@file:../foo, then we should + // end up saving the spec we actually used, not whatever they gave us. + if (this[_resolvedAdd].length) { + updateNodes(this[_resolvedAdd]) + } + + // if updating given dependencies by name, restrict the list of + // nodes to check to only those currently in _updateNames + if (this[_updateNames].length) { + const nodes = retrieveUpdatedNodes(this[_updateNames]) + updateNodes(nodes) + } + + // grab any from explicitRequests that had deps removed + for (const { from: tree } of this.explicitRequests) { + updatedTrees.add(tree) + } + } + } + // preserve indentation, if possible const { [Symbol.for('indent')]: indent, @@ -1291,15 +1362,12 @@ module.exports = cls => class Reifier extends cls { await pkgJson.save() } - // grab any from explicitRequests that had deps removed - for (const { from: tree } of this.explicitRequests) { - updatedTrees.add(tree) - } - - for (const tree of updatedTrees) { - // refresh the edges so they have the correct specs - tree.package = tree.package - promises.push(updatePackageJson(tree)) + if (save) { + for (const tree of updatedTrees) { + // refresh the edges so they have the correct specs + tree.package = tree.package + promises.push(updatePackageJson(tree)) + } } await Promise.all(promises) diff --git a/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs b/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs index 7a6a3e714..6d38d724d 100644 --- a/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs +++ b/workspaces/arborist/tap-snapshots/test/arborist/reify.js.test.cjs @@ -17113,7 +17113,7 @@ ArboristNode { } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-allinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-allinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-fail-allinstall" => EdgeOut { @@ -17125,14 +17125,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-false", "packageName": "optional-dep-allinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-install-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-allinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-fail-allinstall" => EdgeOut { + "name": "@isaacs/testing-fail-allinstall", + "spec": "^1.0.0", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-true", + "packageName": "optional-dep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-allinstall-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-install-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-fail-install" => EdgeOut { @@ -17144,14 +17163,70 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-false", "packageName": "optional-dep-install-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-install-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-fail-install" => EdgeOut { + "name": "@isaacs/testing-fail-install", + "spec": "^1.0.0", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-true", + "packageName": "optional-dep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-install-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-postinstall-fail save=false > expect resolving Promise 1`] = ` +ArboristNode { + "children": Map { + "@isaacs/testing-fail-postinstall" => ArboristNode { + "edgesIn": Set { + EdgeIn { + "from": "", + "name": "@isaacs/testing-fail-postinstall", + "spec": "^1.0.0", + "type": "optional", + }, + }, + "location": "node_modules/@isaacs/testing-fail-postinstall", + "name": "@isaacs/testing-fail-postinstall", + "optional": true, + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-false/node_modules/@isaacs/testing-fail-postinstall", + "resolved": "https://registry.npmjs.org/@isaacs/testing-fail-postinstall/-/testing-fail-postinstall-1.0.0.tgz", + "version": "1.0.0", + }, + }, + "edgesOut": Map { + "@isaacs/testing-fail-postinstall" => EdgeOut { + "name": "@isaacs/testing-fail-postinstall", + "spec": "^1.0.0", + "to": "node_modules/@isaacs/testing-fail-postinstall", + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-false", + "packageName": "optional-dep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-postinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-postinstall-fail save=true > expect resolving Promise 1`] = ` ArboristNode { "children": Map { "@isaacs/testing-fail-postinstall" => ArboristNode { @@ -17166,7 +17241,7 @@ ArboristNode { "location": "node_modules/@isaacs/testing-fail-postinstall", "name": "@isaacs/testing-fail-postinstall", "optional": true, - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail/node_modules/@isaacs/testing-fail-postinstall", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-true/node_modules/@isaacs/testing-fail-postinstall", "resolved": "https://registry.npmjs.org/@isaacs/testing-fail-postinstall/-/testing-fail-postinstall-1.0.0.tgz", "version": "1.0.0", }, @@ -17181,14 +17256,14 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-true", "packageName": "optional-dep-postinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-postinstall-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-preinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-preinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-fail-preinstall" => EdgeOut { @@ -17200,14 +17275,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-false", "packageName": "optional-dep-preinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-tgz-missing > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-preinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-fail-preinstall" => EdgeOut { + "name": "@isaacs/testing-fail-preinstall", + "spec": "^1.0.0", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-true", + "packageName": "optional-dep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-preinstall-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-tgz-missing save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-missing-tgz" => EdgeOut { @@ -17219,14 +17313,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-false", "packageName": "@isaacs/testing-optional-dep-tgz-missing", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-allinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-dep-tgz-missing save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-missing-tgz" => EdgeOut { + "name": "@isaacs/testing-missing-tgz", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-true", + "packageName": "@isaacs/testing-optional-dep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-dep-tgz-missing-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-allinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-allinstall-fail" => EdgeOut { @@ -17238,14 +17351,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-false", "packageName": "optional-metadep-allinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-install-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-allinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-allinstall-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-allinstall-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-true", + "packageName": "optional-metadep-allinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-allinstall-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-install-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-install-fail" => EdgeOut { @@ -17257,14 +17389,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-false", + "packageName": "optional-metadep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-install-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-install-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-install-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-true", "packageName": "optional-metadep-install-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-install-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-postinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-postinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-postinstall-fail" => EdgeOut { @@ -17276,14 +17427,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-false", + "packageName": "optional-metadep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-postinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-postinstall-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-postinstall-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-true", "packageName": "optional-metadep-postinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-postinstall-fail-save-true", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-preinstall-fail > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-preinstall-fail save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-preinstall-fail" => EdgeOut { @@ -17295,14 +17465,33 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-false", "packageName": "optional-metadep-preinstall-fail", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-false", "version": "1.0.0", } ` -exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-tgz-missing > expect resolving Promise 1`] = ` +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-preinstall-fail save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-preinstall-fail" => EdgeOut { + "name": "@isaacs/testing-prod-dep-preinstall-fail", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-true", + "packageName": "optional-metadep-preinstall-fail", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-preinstall-fail-save-true", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-tgz-missing save=false > expect resolving Promise 1`] = ` ArboristNode { "edgesOut": Map { "@isaacs/testing-prod-dep-tgz-missing" => EdgeOut { @@ -17314,9 +17503,28 @@ ArboristNode { }, "isProjectRoot": true, "location": "", - "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-false", + "packageName": "@isaacs/testing-optional-metadep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-false", + "version": "1.0.0", +} +` + +exports[`test/arborist/reify.js TAP optional dependency failures optional-metadep-tgz-missing save=true > expect resolving Promise 1`] = ` +ArboristNode { + "edgesOut": Map { + "@isaacs/testing-prod-dep-tgz-missing" => EdgeOut { + "name": "@isaacs/testing-prod-dep-tgz-missing", + "spec": "^1.0.1", + "to": null, + "type": "optional", + }, + }, + "isProjectRoot": true, + "location": "", + "name": "tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-true", "packageName": "@isaacs/testing-optional-metadep-tgz-missing", - "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing", + "path": "{CWD}/test/arborist/tap-testdir-reify-optional-dependency-failures-optional-metadep-tgz-missing-save-true", "version": "1.0.0", } ` @@ -32468,6 +32676,422 @@ exports[`test/arborist/reify.js TAP save complete lockfile on update-all > shoul ` +exports[`test/arborist/reify.js TAP save package.json on update should not save any with save=false and package-lock=false > should update lockfile with many deps updated package.json save=false 1`] = ` +{ + "name": "workspaces-need-update", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} +` + +exports[`test/arborist/reify.js TAP save package.json on update should not save many deps in multiple package.json when using save=false > should update lockfile with many deps updated package.json save=false 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-not-save-many-deps-in-multiple-package.json-when-using-save-false", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + +exports[`test/arborist/reify.js TAP save package.json on update should save many deps in multiple package.json when using save=true > should update lockfile with many deps updated package.json save=true 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-save-many-deps-in-multiple-package.json-when-using-save-true", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.1.1", + "once": "^1.4.0" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + +exports[`test/arborist/reify.js TAP save package.json on update should update named dep across multiple package.json using save=true > should update lockfile with many deps updated package.json save=true 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-update-named-dep-across-multiple-package.json-using-save-true", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.1.1", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.1.1" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + +exports[`test/arborist/reify.js TAP save package.json on update should update single named dep across multiple package.json using save=true > should update lockfile with single dep updated package.json save=true 1`] = ` +{ + "name": "tap-testdir-reify-save-package.json-on-update-should-update-single-named-dep-across-multiple-package.json-using-save-true", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.4.0" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + }, + "dependencies": { + "a": { + "version": "file:a", + "requires": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "b": { + "version": "file:b", + "requires": { + "abbrev": "^1.0.4" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} + +` + exports[`test/arborist/reify.js TAP save proper lockfile with bins when upgrading lockfile complete=false > should upgrade, with bins in place 1`] = ` { "name": "tap-testdir-reify-save-proper-lockfile-with-bins-when-upgrading-lockfile-complete-false", diff --git a/workspaces/arborist/test/arborist/deduper.js b/workspaces/arborist/test/arborist/deduper.js index 3ec37bd62..511ba87bf 100644 --- a/workspaces/arborist/test/arborist/deduper.js +++ b/workspaces/arborist/test/arborist/deduper.js @@ -18,7 +18,7 @@ const fixture = (t, p) => require('../fixtures/reify-cases/' + p)(t) const cache = t.testdir() const dedupeTree = (path, opt) => - new Arborist({ registry, path, cache, ...(opt || {}) }).dedupe(opt) + new Arborist({ registry, path, cache, save: false, ...(opt || {}) }).dedupe(opt) t.test('dedupes with actual tree', async t => { const path = fixture(t, 'dedupe-actual') diff --git a/workspaces/arborist/test/arborist/reify.js b/workspaces/arborist/test/arborist/reify.js index c8c4cb137..d5fc166a5 100644 --- a/workspaces/arborist/test/arborist/reify.js +++ b/workspaces/arborist/test/arborist/reify.js @@ -256,6 +256,7 @@ t.test('a workspace with a duplicated nested conflicted dep', t => t.test('testing-peer-deps nested with update', t => t.resolveMatchSnapshot(printReified(fixture(t, 'testing-peer-deps-nested'), { update: { names: ['@isaacs/testing-peer-deps'] }, + save: false, }))) t.test('update a bundling node without updating all of its deps', t => { @@ -392,7 +393,7 @@ t.test('multiple bundles at the same level', t => { t.test('update a node without updating its children', t => t.resolveMatchSnapshot(printReified(fixture(t, 'once-outdated'), - { update: { names: ['once'] } }))) + { update: { names: ['once'] }, save: false }))) t.test('do not add shrinkwrapped deps', t => t.resolveMatchSnapshot(printReified( @@ -508,6 +509,7 @@ t.test('update a node without updating a child that has bundle deps', t => { const path = fixture(t, 'testing-bundledeps-3') return t.resolveMatchSnapshot(printReified(path, { update: ['@isaacs/testing-bundledeps-parent'], + save: false, })) }) @@ -524,9 +526,16 @@ t.test('optional dependency failures', t => { 'optional-metadep-postinstall-fail', 'optional-metadep-allinstall-fail', ] - t.plan(cases.length) - cases.forEach(c => t.test(c, t => - t.resolveMatchSnapshot(printReified(fixture(t, c), { update: true })))) + t.plan(cases.length * 2) + let p = [...cases.map(c => t.test(`${c} save=false`, t => + t.resolveMatchSnapshot(printReified(fixture(t, c), + { update: true, save: false }))))] + + // npm update --save + p = [...cases.map(c => t.test(`${c} save=true`, t => + t.resolveMatchSnapshot(printReified(fixture(t, c), + { update: true, save: true }))))] + return p }) t.test('failure to fetch prod dep is failure', t => @@ -665,6 +674,7 @@ t.test('rollbacks', { buffered: false }, t => { return t.resolveMatchSnapshot(a.reify({ update: ['@isaacs/testing-bundledeps-parent'], + save: false, }).then(printTree)) }) @@ -845,6 +855,7 @@ t.test('rollbacks', { buffered: false }, t => { return t.resolveMatchSnapshot(a.reify({ update: ['@isaacs/testing-bundledeps-parent'], + save: false, }).then(tree => printTree(tree))).then(() => { const warnings = check() t.equal(warnings.length, 2) @@ -1367,7 +1378,7 @@ t.test('save complete lockfile on update-all', async t => { const lock = () => fs.readFileSync(`${path}/package-lock.json`, 'utf8') await reify(path, { add: ['abbrev@1.0.4'] }) t.matchSnapshot(lock(), 'should have abbrev 1.0.4') - await reify(path, { update: true }) + await reify(path, { update: true, save: false }) t.matchSnapshot(lock(), 'should update, but not drop root metadata') }) @@ -2432,3 +2443,134 @@ t.test('add local dep with existing dev + peer/optional', async t => { t.equal(tree.children.get('abbrev').resolved, 'file:../../dep', 'resolved') t.equal(tree.children.size, 1, 'children') }) + +t.test('save package.json on update', t => { + t.test('should save many deps in multiple package.json when using save=true', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: true, save: true }) + + t.same( + require(resolve(path, 'package.json')), + { dependencies: { abbrev: '^1.1.1' }, workspaces: ['a', 'b'] }, + 'should save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.1.1', once: '^1.4.0' } }, + 'should save workspace dep to its package.json file') + + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with many deps updated package.json save=true' + ) + }) + + t.test('should not save many deps in multiple package.json when using save=false', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: true, save: false }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.0.4' }, + workspaces: ['a', 'b'], + }, + 'should not save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.0.4', once: '^1.3.2' } }, + 'should not save workspace dep to its package.json file') + + // package-lock entries will still get updated: + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with many deps updated package.json save=false' + ) + }) + + t.test('should not save any with save=false and package-lock=false', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: true, save: false, packageLock: false }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.0.4' }, + workspaces: ['a', 'b'], + }, + 'should not save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.0.4', once: '^1.3.2' } }, + 'should not save workspace dep to its package.json file') + + // package-lock entries will still get updated: + t.matchSnapshot( + JSON.stringify(JSON.parse(fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8')), null, 2), + 'should update lockfile with many deps updated package.json save=false' + ) + }) + + t.test('should update named dep across multiple package.json using save=true', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: ['abbrev'], save: true }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.1.1' }, + workspaces: ['a', 'b'], + }, + 'should save top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.1.1', once: '^1.3.2' } }, + 'should save only workspace a updated dep to its package.json file') + t.same( + require(resolve(path, 'b', 'package.json')), + { dependencies: { abbrev: '^1.1.1' } }, + 'should save only workspace b updated dep to its package.json file') + + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with many deps updated package.json save=true' + ) + }) + + t.test('should update single named dep across multiple package.json using save=true', async t => { + const path = fixture(t, 'workspaces-need-update') + + await reify(path, { update: ['once'], save: true }) + + t.same( + require(resolve(path, 'package.json')), + { + dependencies: { abbrev: '^1.0.4' }, + workspaces: ['a', 'b'], + }, + 'should save no top level dep update to root package.json' + ) + t.same( + require(resolve(path, 'a', 'package.json')), + { dependencies: { abbrev: '^1.0.4', once: '^1.4.0' } }, + 'should save only workspace single updated dep to its package.json file') + t.same( + require(resolve(path, 'b', 'package.json')), + { dependencies: { abbrev: '^1.0.4' } }, + 'should not change workspace b package.json file') + + t.matchSnapshot( + fs.readFileSync(resolve(path, 'package-lock.json'), 'utf8'), + 'should update lockfile with single dep updated package.json save=true' + ) + }) + + t.end() +}) diff --git a/workspaces/arborist/test/fixtures/reify-cases/workspaces-need-update.js b/workspaces/arborist/test/fixtures/reify-cases/workspaces-need-update.js new file mode 100644 index 000000000..2d57f05a0 --- /dev/null +++ b/workspaces/arborist/test/fixtures/reify-cases/workspaces-need-update.js @@ -0,0 +1,83 @@ +// generated from test/fixtures/workspaces-need-update +module.exports = t => { + const path = t.testdir({ + "a": { + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }) + }, + "b": { + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "^1.0.4" + } + }) + }, + "package-lock.json": JSON.stringify({ + "name": "workspaces-need-update", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }), + "package.json": JSON.stringify({ + "dependencies": { + "abbrev": "^1.0.4" + }, + "workspaces": [ + "a", + "b" + ] + }) +}) + return path +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/a/package.json b/workspaces/arborist/test/fixtures/workspaces-need-update/a/package.json new file mode 100644 index 000000000..765847437 --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/a/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/b/package.json b/workspaces/arborist/test/fixtures/workspaces-need-update/b/package.json new file mode 100644 index 000000000..8af6070f2 --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "abbrev": "^1.0.4" + } +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/package-lock.json b/workspaces/arborist/test/fixtures/workspaces-need-update/package-lock.json new file mode 100644 index 000000000..43865795a --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/package-lock.json @@ -0,0 +1,53 @@ +{ + "name": "workspaces-need-update", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "workspaces": [ + "a", + "b" + ], + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "a": { + "dependencies": { + "abbrev": "^1.0.4", + "once": "^1.3.2" + } + }, + "b": { + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/a": { + "resolved": "a", + "link": true + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/b": { + "resolved": "b", + "link": true + }, + "node_modules/once": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", + "integrity": "sha1-2P7sqTsDnsHc3ud0HJK9rF4oCBs=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/workspaces/arborist/test/fixtures/workspaces-need-update/package.json b/workspaces/arborist/test/fixtures/workspaces-need-update/package.json new file mode 100644 index 000000000..ebdce120c --- /dev/null +++ b/workspaces/arborist/test/fixtures/workspaces-need-update/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "abbrev": "^1.0.4" + }, + "workspaces": ["a", "b"] +} |