From e4332d44dab7b4e77175e945da66a3bbd0a75892 Mon Sep 17 00:00:00 2001 From: Jurre Stender Date: Tue, 19 Jan 2021 13:15:14 +0100 Subject: [PATCH] Update subdependencies using npm7 --- .../npm7/remove-dependencies-from-lockfile.js | 22 ----- .../helpers/lib/npm7/subdependency-updater.js | 72 +++----------- .../subdependency-in-range/package-lock.json | 96 +++++++++++++++++++ .../subdependency-in-range/package.json | 14 +++ .../node_modules/.package-lock.json | 22 +++++ .../node_modules/extend/.npmignore | 1 + .../node_modules/extend/.travis.yml | 18 ++++ .../node_modules/extend/LICENSE | 23 +++++ .../node_modules/extend/README.md | 60 ++++++++++++ .../node_modules/extend/component.json | 31 ++++++ .../node_modules/extend/index.js | 80 ++++++++++++++++ .../node_modules/extend/package.json | 34 +++++++ .../test-old-npm-sub-dependency/README.md | 1 + .../test-old-npm-sub-dependency/package.json | 22 +++++ .../package-lock.json | 45 +++++++++ .../subdependency-out-of-range/package.json | 14 +++ .../test/npm7/subdependency-updater.test.js | 45 +++++++++ .../npm_and_yarn/file_updater_spec.rb | 33 ++++++- .../subdependency-in-range/package-lock.json | 96 +++++++++++++++++++ .../npm7/subdependency-in-range/package.json | 14 +++ 20 files changed, 662 insertions(+), 81 deletions(-) delete mode 100644 npm_and_yarn/helpers/lib/npm7/remove-dependencies-from-lockfile.js create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package-lock.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/.package-lock.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.npmignore create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.travis.yml create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/LICENSE create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/README.md create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/component.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/index.js create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/package.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/README.md create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/package.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package-lock.json create mode 100644 npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package.json create mode 100644 npm_and_yarn/helpers/test/npm7/subdependency-updater.test.js create mode 100644 npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package-lock.json create mode 100644 npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package.json diff --git a/npm_and_yarn/helpers/lib/npm7/remove-dependencies-from-lockfile.js b/npm_and_yarn/helpers/lib/npm7/remove-dependencies-from-lockfile.js deleted file mode 100644 index bfe65f3cb7..0000000000 --- a/npm_and_yarn/helpers/lib/npm7/remove-dependencies-from-lockfile.js +++ /dev/null @@ -1,22 +0,0 @@ -// Recursively removes all dependencies matching on name -function removeDependenciesFromLockfile(lockfile, dependencyNames) { - if (!lockfile.dependencies) return lockfile; - - const dependencies = Object.entries(lockfile.dependencies).reduce( - (acc, [depName, packageValue]) => { - if (!dependencyNames.includes(depName)) { - acc[depName] = removeDependenciesFromLockfile( - packageValue, - dependencyNames - ); - } - - return acc; - }, - {} - ); - - return Object.assign({}, lockfile, { dependencies }); -} - -module.exports = removeDependenciesFromLockfile; diff --git a/npm_and_yarn/helpers/lib/npm7/subdependency-updater.js b/npm_and_yarn/helpers/lib/npm7/subdependency-updater.js index 5882b2b0d7..5fed66bb89 100644 --- a/npm_and_yarn/helpers/lib/npm7/subdependency-updater.js +++ b/npm_and_yarn/helpers/lib/npm7/subdependency-updater.js @@ -1,74 +1,30 @@ const fs = require("fs"); const path = require("path"); -const npm = require("npm6"); -const installer = require("npm6/lib/install"); -const detectIndent = require("detect-indent"); -const removeDependenciesFromLockfile = require("./remove-dependencies-from-lockfile"); - -const { muteStderr, runAsync } = require("./helpers.js"); +const npm = require("npm7"); +const Arborist = require("@npmcli/arborist"); async function updateDependencyFile(directory, lockfileName, dependencies) { const readFile = (fileName) => fs.readFileSync(path.join(directory, fileName)).toString(); - const lockfile = readFile(lockfileName); - const indent = detectIndent(lockfile).indent || " "; - const lockfileObject = JSON.parse(lockfile); - // Remove the dependency we want to update from the lockfile and let - // npm find the latest resolvable version and fix the lockfile - const updatedLockfileObject = removeDependenciesFromLockfile( - lockfileObject, - dependencies.map((dep) => dep.name) - ); - fs.writeFileSync( - path.join(directory, lockfileName), - JSON.stringify(updatedLockfileObject, null, indent) - ); - - // `force: true` ignores checks for platform (os, cpu) and engines - // in npm/lib/install/validate-args.js - // Platform is checked and raised from (EBADPLATFORM): - // https://github.com/npm/npm-install-checks - // - // `'prefer-offline': true` sets fetch() cache key to `force-cache` - // https://github.com/npm/npm-registry-fetch - // - // `'ignore-scripts': true` used to disable prepare and prepack scripts - // which are run when installing git dependencies - await runAsync(npm, npm.load, [ - { - loglevel: "silent", - force: true, - audit: false, - "prefer-offline": true, - "ignore-scripts": true, - }, - ]); - - const dryRun = true; - const initialInstaller = new installer.Installer(directory, dryRun, [], { - packageLockOnly: true, + await new Promise((resolve) => { + npm.load(resolve); }); - // A bug in npm means the initial install will remove any git dependencies - // from the lockfile. A subsequent install with no arguments fixes this. - const cleanupInstaller = new installer.Installer(directory, dryRun, [], { + const arb = new Arborist({ + ...npm.flatOptions, + path: directory, packageLockOnly: true, + dryRun: false, + ignoreScripts: true, + force: true, + save: true, }); - // Skip printing the success message - initialInstaller.printInstalled = (cb) => cb(); - cleanupInstaller.printInstalled = (cb) => cb(); + const dependencyNames = dependencies.map((dep) => dep.name); + await arb.buildIdealTree({ update: { names: dependencyNames }}); - // There are some hard-to-prevent bits of output. - // This is horrible, but works. - const unmute = muteStderr(); - try { - await runAsync(initialInstaller, initialInstaller.run, []); - await runAsync(cleanupInstaller, cleanupInstaller.run, []); - } finally { - unmute(); - } + await arb.reify({}) const updatedLockfile = readFile(lockfileName); diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package-lock.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package-lock.json new file mode 100644 index 0000000000..4ada6687ab --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package-lock.json @@ -0,0 +1,96 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "test", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "polling-to-event": "^2.1.0" + } + }, + "node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=" + }, + "node_modules/extend": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.0.tgz", + "integrity": "sha512-ow3dLb5N2d4T9isTntdeu+DRixQZ1jMUfc30292ryrg6ch/9LP35PR36uvVt2+Xq7RvpTVjFw9R/txhgQZ7sIg==" + }, + "node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/pauseable": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/pauseable/-/pauseable-0.1.7.tgz", + "integrity": "sha1-hczXeQ5JoTr+O5A7NhYTC8AHTgc=" + }, + "node_modules/polling-to-event": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/polling-to-event/-/polling-to-event-2.1.0.tgz", + "integrity": "sha1-LorKGFZiQz8X/tL0z3RKKZPiJWw=", + "dependencies": { + "debug": "^3.0.1", + "deep-equal": "~0.2.1", + "extend": "~2.0.0", + "pauseable": "~0.1.5" + } + } + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=" + }, + "extend": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.0.tgz", + "integrity": "sha512-ow3dLb5N2d4T9isTntdeu+DRixQZ1jMUfc30292ryrg6ch/9LP35PR36uvVt2+Xq7RvpTVjFw9R/txhgQZ7sIg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "pauseable": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/pauseable/-/pauseable-0.1.7.tgz", + "integrity": "sha1-hczXeQ5JoTr+O5A7NhYTC8AHTgc=" + }, + "polling-to-event": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/polling-to-event/-/polling-to-event-2.1.0.tgz", + "integrity": "sha1-LorKGFZiQz8X/tL0z3RKKZPiJWw=", + "requires": { + "debug": "^3.0.1", + "deep-equal": "~0.2.1", + "extend": "~2.0.0", + "pauseable": "~0.1.5" + } + } + } +} diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package.json new file mode 100644 index 0000000000..eb40e209fd --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-in-range/package.json @@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "polling-to-event": "^2.1.0" + } +} diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/.package-lock.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/.package-lock.json new file mode 100644 index 0000000000..61a92ab18a --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/.package-lock.json @@ -0,0 +1,22 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "node_modules/extend": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-1.3.0.tgz", + "integrity": "sha1-0VFvsP9WJNLr+RI+odrFoZlABPg=" + }, + "node_modules/test-old-npm-sub-dependency": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/dependabot-fixtures/test-old-npm-sub-dependency.git#3022e23aa7dac4d134d176ad2feaed72457946b4", + "integrity": "sha512-6cmtO3jAxTe/1QlRKk678624tQQuhEP8wXxo93LyZLxkHAq8c+eXjmSKNoid5oOc2PeigSwZBeoFmUVQ6iBAsg==", + "license": "ISC", + "dependencies": { + "extend": "^1.2.0" + } + } + } +} diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.npmignore b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.npmignore new file mode 100644 index 0000000000..30d74d2584 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.npmignore @@ -0,0 +1 @@ +test \ No newline at end of file diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.travis.yml b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.travis.yml new file mode 100644 index 0000000000..912080aa1b --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/.travis.yml @@ -0,0 +1,18 @@ +language: node_js +node_js: + - "0.11" + - "0.10" + - "0.9" + - "0.8" + - "0.6" + - "0.4" +before_install: + - '[ "${TRAVIS_NODE_VERSION}" == "0.6" ] || npm install -g npm@~1.4.6' +matrix: + fast_finish: true + allow_failures: + - node_js: "0.11" + - node_js: "0.9" + - node_js: "0.6" + - node_js: "0.4" + diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/LICENSE b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/LICENSE new file mode 100644 index 0000000000..e16d6a56ca --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) 2014 Stefan Thomas + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/README.md b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/README.md new file mode 100644 index 0000000000..715f666e31 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/README.md @@ -0,0 +1,60 @@ +[![Build Status][1]][2] [![dependency status][9]][10] [![dev dependency status][11]][12] + +# extend() for Node.js [![Version Badge][8]][3] + +`node-extend` is a port of the classic extend() method from jQuery. It behaves as you expect. It is simple, tried and true. + +## Installation + +This package is available on [npm][3] as: `extend` + +``` sh +npm install extend +``` + +## Usage + +**Syntax:** extend **(** [`deep`], `target`, `object1`, [`objectN`] **)** + +*Extend one object with one or more others, returning the modified object.* + +Keep in mind that the target object will be modified, and will be returned from extend(). + +If a boolean true is specified as the first argument, extend performs a deep copy, recursively copying any objects it finds. Otherwise, the copy will share structure with the original object(s). +Undefined properties are not copied. However, properties inherited from the object's prototype will be copied over. +Warning: passing `false` as the first argument is not supported. + +### Arguments + +* `deep` *Boolean* (optional) +If set, the merge becomes recursive (i.e. deep copy). +* `target` *Object* +The object to extend. +* `object1` *Object* +The object that will be merged into the first. +* `objectN` *Object* (Optional) +More objects to merge into the first. + +## License + +`node-extend` is licensed under the [MIT License][4]. + +## Acknowledgements + +All credit to the jQuery authors for perfecting this amazing utility. + +Ported to Node.js by [Stefan Thomas][5] with contributions by [Jonathan Buchanan][6] and [Jordan Harband][7]. + +[1]: https://travis-ci.org/justmoon/node-extend.svg +[2]: https://travis-ci.org/justmoon/node-extend +[3]: https://npmjs.org/package/extend +[4]: http://opensource.org/licenses/MIT +[5]: https://github.com/justmoon +[6]: https://github.com/insin +[7]: https://github.com/ljharb +[8]: http://vb.teelaun.ch/justmoon/node-extend.svg +[9]: https://david-dm.org/justmoon/node-extend.svg +[10]: https://david-dm.org/justmoon/node-extend +[11]: https://david-dm.org/justmoon/node-extend/dev-status.svg +[12]: https://david-dm.org/justmoon/node-extend#info=devDependencies + diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/component.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/component.json new file mode 100644 index 0000000000..378c7f55cf --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/component.json @@ -0,0 +1,31 @@ +{ + "name": "extend", + "author": "Stefan Thomas (http://www.justmoon.net)", + "version": "1.3.0", + "description": "Port of jQuery.extend for node.js and the browser.", + "scripts": [ + "index.js" + ], + "contributors": [ + { + "name": "Jordan Harband", + "url": "https://github.com/ljharb" + } + ], + "keywords": [ + "extend", + "clone", + "merge" + ], + "repository" : { + "type": "git", + "url": "https://github.com/justmoon/node-extend.git" + }, + "dependencies": { + }, + "devDependencies": { + "tape" : "~2.12.3", + "covert": "~0.4.0" + } +} + diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/index.js b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/index.js new file mode 100644 index 0000000000..06f3c12025 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/index.js @@ -0,0 +1,80 @@ +var hasOwn = Object.prototype.hasOwnProperty; +var toString = Object.prototype.toString; +var undefined; + +var isPlainObject = function isPlainObject(obj) { + "use strict"; + if (!obj || toString.call(obj) !== '[object Object]' || obj.nodeType || obj.setInterval) { + return false; + } + + var has_own_constructor = hasOwn.call(obj, 'constructor'); + var has_is_property_of_method = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); + // Not own constructor property must be Object + if (obj.constructor && !has_own_constructor && !has_is_property_of_method) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + var key; + for (key in obj) {} + + return key === undefined || hasOwn.call(obj, key); +}; + +module.exports = function extend() { + "use strict"; + var options, name, src, copy, copyIsArray, clone, + target = arguments[0], + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if (typeof target === "boolean") { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } else if (typeof target !== "object" && typeof target !== "function" || target == undefined) { + target = {}; + } + + for (; i < length; ++i) { + // Only deal with non-null/undefined values + if ((options = arguments[i]) != null) { + // Extend the base object + for (name in options) { + src = target[name]; + copy = options[name]; + + // Prevent never-ending loop + if (target === copy) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { + if (copyIsArray) { + copyIsArray = false; + clone = src && Array.isArray(src) ? src : []; + } else { + clone = src && isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[name] = extend(deep, clone, copy); + + // Don't bring in undefined values + } else if (copy !== undefined) { + target[name] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/package.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/package.json new file mode 100644 index 0000000000..ddcee053e1 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/extend/package.json @@ -0,0 +1,34 @@ +{ + "name": "extend", + "author": "Stefan Thomas (http://www.justmoon.net)", + "version": "1.3.0", + "description": "Port of jQuery.extend for node.js and the browser", + "main": "index", + "scripts": { + "test": "node test/index.js", + "coverage": "covert test/index.js", + "coverage-quiet": "covert test/index.js --quiet" + }, + "contributors": [ + { + "name": "Jordan Harband", + "url": "https://github.com/ljharb" + } + ], + "keywords": [ + "extend", + "clone", + "merge" + ], + "repository" : { + "type": "git", + "url": "https://github.com/justmoon/node-extend.git" + }, + "dependencies": { + }, + "devDependencies": { + "tape" : "~2.13.2", + "covert": "~0.4.0" + } +} + diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/README.md b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/README.md new file mode 100644 index 0000000000..d938b83c05 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/README.md @@ -0,0 +1 @@ +# test-old-npm-sub-dependency diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/package.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/package.json new file mode 100644 index 0000000000..43397c019f --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/node_modules/test-old-npm-sub-dependency/package.json @@ -0,0 +1,22 @@ +{ + "name": "test-old-npm-sub-dependency", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dependabot-fixtures/test-old-npm-sub-dependency.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/dependabot-fixtures/test-old-npm-sub-dependency/issues" + }, + "homepage": "https://github.com/dependabot-fixtures/test-old-npm-sub-dependency#readme", + "dependencies": { + "extend": "^1.2.0" + } +} diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package-lock.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package-lock.json new file mode 100644 index 0000000000..e284cdacfb --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package-lock.json @@ -0,0 +1,45 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "test", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "test-old-npm-sub-dependency": "github:dependabot-fixtures/test-old-npm-sub-dependency#3022e23aa7dac4d134d176ad2feaed72457946b4" + } + }, + "node_modules/extend": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-1.3.0.tgz", + "integrity": "sha1-0VFvsP9WJNLr+RI+odrFoZlABPg=" + }, + "node_modules/test-old-npm-sub-dependency": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/dependabot-fixtures/test-old-npm-sub-dependency.git#3022e23aa7dac4d134d176ad2feaed72457946b4", + "integrity": "sha512-6cmtO3jAxTe/1QlRKk678624tQQuhEP8wXxo93LyZLxkHAq8c+eXjmSKNoid5oOc2PeigSwZBeoFmUVQ6iBAsg==", + "license": "ISC", + "dependencies": { + "extend": "^1.2.0" + } + } + }, + "dependencies": { + "extend": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-1.3.0.tgz", + "integrity": "sha1-0VFvsP9WJNLr+RI+odrFoZlABPg=" + }, + "test-old-npm-sub-dependency": { + "version": "git+ssh://git@github.com/dependabot-fixtures/test-old-npm-sub-dependency.git#3022e23aa7dac4d134d176ad2feaed72457946b4", + "integrity": "sha512-6cmtO3jAxTe/1QlRKk678624tQQuhEP8wXxo93LyZLxkHAq8c+eXjmSKNoid5oOc2PeigSwZBeoFmUVQ6iBAsg==", + "from": "test-old-npm-sub-dependency@github:dependabot-fixtures/test-old-npm-sub-dependency#3022e23aa7dac4d134d176ad2feaed72457946b4", + "requires": { + "extend": "^1.2.0" + } + } + } +} diff --git a/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package.json b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package.json new file mode 100644 index 0000000000..8abcb1b8c4 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/fixtures/subdependency-updater/subdependency-out-of-range/package.json @@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "test-old-npm-sub-dependency": "github:dependabot-fixtures/test-old-npm-sub-dependency#3022e23aa7dac4d134d176ad2feaed72457946b4" + } +} diff --git a/npm_and_yarn/helpers/test/npm7/subdependency-updater.test.js b/npm_and_yarn/helpers/test/npm7/subdependency-updater.test.js new file mode 100644 index 0000000000..957568e631 --- /dev/null +++ b/npm_and_yarn/helpers/test/npm7/subdependency-updater.test.js @@ -0,0 +1,45 @@ +const path = require("path"); +const os = require("os"); +const fs = require("fs"); +const rimraf = require("rimraf"); +const { updateDependencyFile } = require("../../lib/npm7/subdependency-updater"); +const helpers = require("./helpers"); + +describe("subdependency-updater", () => { + let tempDir; + beforeEach(() => { + tempDir = fs.mkdtempSync(os.tmpdir() + path.sep); + }); + afterEach(() => rimraf.sync(tempDir)); + + it("generates an updated package-lock.json", async () => { + helpers.copyDependencies("subdependency-updater/subdependency-in-range", tempDir); + + const result = await updateDependencyFile(tempDir, "package-lock.json", [ + { + name: "ms", + version: "2.1.3", + requirements: [{ file: "package.json", groups: ["dependencies"] }], + }, + ]); + + const lockfile = JSON.parse(result["package-lock.json"]); + expect(lockfile.dependencies.ms.version).toEqual("2.1.3") + expect(lockfile.packages["node_modules/ms"].version).toEqual("2.1.3") + }); + + it("does not update the dependency when the update would be out of range", async () => { + helpers.copyDependencies("subdependency-updater/subdependency-out-of-range", tempDir); + + const result = await updateDependencyFile(tempDir, "package-lock.json", [ + { + name: "extend", + version: "2.0.2", + requirements: [{ file: "package.json", groups: ["dependencies"] }], + }, + ]); + + const lockfile = JSON.parse(result["package-lock.json"]); + expect(lockfile.dependencies.extend.version).toEqual("1.3.0") + }); +}); diff --git a/npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater_spec.rb b/npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater_spec.rb index 54c81a3fc4..313f41d668 100644 --- a/npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater_spec.rb +++ b/npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater_spec.rb @@ -2545,6 +2545,37 @@ end end + describe "npm 7: updating subdependency with lockfile" do + let(:files) { project_dependency_files("npm7/subdependency-in-range") } + + let(:dependency_name) { "ms" } + let(:version) { "2.1.3" } + let(:previous_version) { "2.1.1" } + let(:requirements) do + [{ + file: "package.json", + requirement: "^2.1.1", + groups: ["dependencies"], + source: nil + }] + end + let(:previous_requirements) do + [{ + file: "package.json", + requirement: "^2.1.1", + groups: ["dependencies"], + source: nil + }] + end + + it "updates the files" do + expect(updated_files.count).to eq(1) + parsed_lockfile = JSON.parse(updated_npm_lock.content) + expect(parsed_lockfile["packages"]["node_modules/ms"]["version"]).to eq("2.1.3") + expect(parsed_lockfile["dependencies"]["ms"]["version"]).to eq("2.1.3") + end + end + ####################### # Yarn specific tests # ####################### @@ -2718,7 +2749,7 @@ Dependabot::DependencyFile.new( name: "other_package/package.json", content: - fixture("package_files", "other_package.json") + fixture("package_files", "other_package.json") ) end diff --git a/npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package-lock.json b/npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package-lock.json new file mode 100644 index 0000000000..4ada6687ab --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package-lock.json @@ -0,0 +1,96 @@ +{ + "name": "test", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "test", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "polling-to-event": "^2.1.0" + } + }, + "node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=" + }, + "node_modules/extend": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.0.tgz", + "integrity": "sha512-ow3dLb5N2d4T9isTntdeu+DRixQZ1jMUfc30292ryrg6ch/9LP35PR36uvVt2+Xq7RvpTVjFw9R/txhgQZ7sIg==" + }, + "node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/pauseable": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/pauseable/-/pauseable-0.1.7.tgz", + "integrity": "sha1-hczXeQ5JoTr+O5A7NhYTC8AHTgc=" + }, + "node_modules/polling-to-event": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/polling-to-event/-/polling-to-event-2.1.0.tgz", + "integrity": "sha1-LorKGFZiQz8X/tL0z3RKKZPiJWw=", + "dependencies": { + "debug": "^3.0.1", + "deep-equal": "~0.2.1", + "extend": "~2.0.0", + "pauseable": "~0.1.5" + } + } + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "deep-equal": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.2.2.tgz", + "integrity": "sha1-hLdFiW80xoTpjyzg5Cq69Du6AX0=" + }, + "extend": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.0.tgz", + "integrity": "sha512-ow3dLb5N2d4T9isTntdeu+DRixQZ1jMUfc30292ryrg6ch/9LP35PR36uvVt2+Xq7RvpTVjFw9R/txhgQZ7sIg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "pauseable": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/pauseable/-/pauseable-0.1.7.tgz", + "integrity": "sha1-hczXeQ5JoTr+O5A7NhYTC8AHTgc=" + }, + "polling-to-event": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/polling-to-event/-/polling-to-event-2.1.0.tgz", + "integrity": "sha1-LorKGFZiQz8X/tL0z3RKKZPiJWw=", + "requires": { + "debug": "^3.0.1", + "deep-equal": "~0.2.1", + "extend": "~2.0.0", + "pauseable": "~0.1.5" + } + } + } +} diff --git a/npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package.json b/npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package.json new file mode 100644 index 0000000000..eb40e209fd --- /dev/null +++ b/npm_and_yarn/spec/fixtures/projects/npm7/subdependency-in-range/package.json @@ -0,0 +1,14 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "polling-to-event": "^2.1.0" + } +}