diff --git a/.npmignore b/.npmignore index 1b32b033e23a7..12efef27852da 100644 --- a/.npmignore +++ b/.npmignore @@ -4,7 +4,7 @@ npm-debug.log /.github /test node_modules/marked -node_modules/ronn +node_modules/marked-man node_modules/tap node_modules/.bin node_modules/npm-registry-mock diff --git a/AUTHORS b/AUTHORS index a011b51d6a036..705b7c5c80339 100644 --- a/AUTHORS +++ b/AUTHORS @@ -619,3 +619,6 @@ Beni von Cheni Frédéric Harper Johannes Würbach ƇʘƁ̆ąƇ́ +Eli Doran +Tobias Koppers +Grey Baker diff --git a/CHANGELOG.md b/CHANGELOG.md index 794ae1060441e..3811a970b0cfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,66 @@ +## v6.8.0 (2019-01-31): + +This release includes an implementation of [RFC #10](https://github.com/npm/rfcs/blob/latest/accepted/0010-monorepo-subdirectory-declaration.md), documenting an optional field that can be used to specify +the directory path for a package within a monorepo. + +### NEW FEATURES + +* [`3663cdef2`](https://github.com/npm/cli/commit/3663cdef205fa9ba2c2830e5ef7ceeb31c30298c) + [#140](https://github.com/npm/cli/pull/140) + Update package.json docs to include repository.directory details. + ([@greysteil](https://github.com/greysteil)) + +### BUGFIXES + +* [`550bf703a`](https://github.com/npm/cli/commit/550bf703ae3e31ba6a300658ae95b6937f67b68f) + Add @types to ignore list to fix git clean -fd. + ([@zkat](https://github.com/zkat)) +* [`cdb059293`](https://github.com/npm/cli/commit/cdb0592939d6256c80f7ec5a2b6251131a512a2a) + [#144](https://github.com/npm/cli/pull/144) + Fix common.npm callback arguments. + ([@larsgw](https://github.com/larsgw)) +* [`91314e77b`](https://github.com/npm/cli/commit/91314e77be09a50a275f59ccda314f7cfe269069) + [npm.community#4794](https://npm.community/t/packages-with-peerdependencies-are-incorrectly-hoisted/4794) + Fix hoisting of packages with peerDeps. + ([@sokra](https://github.com/sokra)) +* [`25573e9b9`](https://github.com/npm/cli/commit/25573e9b9d5d26261c68d453f06db5b3b1cd6789) + [npm.community#4770](https://npm.community/t/https://npm.community/t/4770) + Show installed but unmet peer deps. + ([@larsgw](https://github.com/larsgw)) +* [`ce2c4bd1a`](https://github.com/npm/cli/commit/ce2c4bd1a2ce7ac1727a4ca9a350b743a2e27b2a) + [#149](https://github.com/npm/cli/pull/149) + Use figgy-config to make sure extra opts are there. + ([@zkat](https://github.com/zkat)) + +### DEPENDENCY BUMPS + +* [`d72141080`](https://github.com/npm/cli/commit/d72141080ec8fcf35bcc5650245efbe649de053e) + `npm-registry-couchapp@2.7.1` + ([@zkat](https://github.com/zkat)) +* [`671cad1b1`](https://github.com/npm/cli/commit/671cad1b18239d540da246d6f78de45d9f784396) + `npm-registry-fetch@3.9.0`: + Make sure publishing with legacy username:password `_auth` works again. + ([@zkat](https://github.com/zkat)) +* [`95ca1aef4`](https://github.com/npm/cli/commit/95ca1aef4077c8e68d9f4dce37f6ba49b591c4ca) + `pacote@9.4.1` + ([@aeschright](https://github.com/aeschright)) + +### MISC + +* [`89b23a5f7`](https://github.com/npm/cli/commit/89b23a5f7b0ccdcdda1d7d4d3eafb6903156d186) + [#120](https://github.com/npm/cli/pull/120) + Use `const` in lib/fetch-package-metadata.md. + ([@watilde](https://github.com/watilde)) +* [`4970d553c`](https://github.com/npm/cli/commit/4970d553c0ea66128931d118469fd31c87cc7986) + [#126](https://github.com/npm/cli/pull/126) + Replace ronn with marked-man in `.npmignore`. + ([@watilde](https://github.com/watilde)) +* [`d9b6090dc`](https://github.com/npm/cli/commit/d9b6090dc26cd0fded18b4f80248cff3e51bb185) + [#138](https://github.com/npm/cli/pull/138) + Reduce work to test if executable ends with a 'g'. + ([@elidoran](https://github.com/elidoran)) + ([@larsgw](https://github.com/larsgw)) + ## v6.7.0 (2019-01-23): Hey y'all! This is a quick hotfix release that includes some important fixes to diff --git a/bin/npm-cli.js b/bin/npm-cli.js index 6f76b23828531..705aa472e7e55 100755 --- a/bin/npm-cli.js +++ b/bin/npm-cli.js @@ -25,7 +25,6 @@ unsupported.checkForUnsupportedNode() - var path = require('path') var npm = require('../lib/npm.js') var npmconf = require('../lib/config/core.js') var errorHandler = require('../lib/utils/error-handler.js') @@ -37,7 +36,7 @@ // if npm is called as "npmg" or "npm_g", then // run in global mode. - if (path.basename(process.argv[1]).slice(-1) === 'g') { + if (process.argv[1][process.argv[1].length - 1] === 'g') { process.argv.splice(1, 1, 'npm', '-g') } diff --git a/doc/files/package.json.md b/doc/files/package.json.md index dd6492af08430..95e77d34c5f9f 100644 --- a/doc/files/package.json.md +++ b/doc/files/package.json.md @@ -393,6 +393,15 @@ shortcut syntax you use for `npm install`: "repository": "gitlab:user/repo" +If the `package.json` for your package is not in the root directory (for example +if it is part of a monorepo), you can specify the directory in which it lives: + + "repository": { + "type" : "git", + "url" : "https://github.com/facebook/react.git", + "directory": "packages/react-dom" + } + ## scripts The "scripts" property is a dictionary containing script commands that are run diff --git a/lib/access.js b/lib/access.js index 4bb93fda1d0ee..6657f4b0717a1 100644 --- a/lib/access.js +++ b/lib/access.js @@ -154,7 +154,7 @@ access['ls-packages'] = access.lsPackages = ([owner], opts) => { } access['ls-collaborators'] = access.lsCollaborators = ([pkg, usr], opts) => { - return getPackage(pkg).then(pkgName => + return getPackage(pkg, false).then(pkgName => libaccess.lsCollaborators(pkgName, usr, opts) ).then(collabs => { // TODO - print these out nicely (breaking change) diff --git a/lib/dedupe.js b/lib/dedupe.js index 325faeaabcd43..fae409fea572d 100644 --- a/lib/dedupe.js +++ b/lib/dedupe.js @@ -142,8 +142,9 @@ function hoistChildren_ (tree, diff, seen, next) { [andComputeMetadata(tree)] ], done) } - var hoistTo = earliestInstallable(tree, tree.parent, child.package, log) - if (hoistTo) { + // find a location where it's installable + var hoistTo = earliestInstallable(tree, tree, child.package, log, child) + if (hoistTo && hoistTo !== tree) { move(child, hoistTo, diff) chain([ [andComputeMetadata(hoistTo)], diff --git a/lib/fetch-package-metadata.md b/lib/fetch-package-metadata.md index 6fe4beac6eeed..7b4562341b1cb 100644 --- a/lib/fetch-package-metadata.md +++ b/lib/fetch-package-metadata.md @@ -1,7 +1,7 @@ fetch-package-metadata ---------------------- - var fetchPackageMetadata = require("npm/lib/fetch-package-metadata") + const fetchPackageMetadata = require("npm/lib/fetch-package-metadata") fetchPackageMetadata(spec, contextdir, callback) This will get package metadata (and if possible, ONLY package metadata) for diff --git a/lib/install/deps.js b/lib/install/deps.js index c36265093b090..1cf4de15dc3f1 100644 --- a/lib/install/deps.js +++ b/lib/install/deps.js @@ -650,7 +650,7 @@ function resolveWithNewModule (pkg, tree, log, next) { return isInstallable(pkg, (err) => { let installable = !err addBundled(pkg, (bundleErr) => { - var parent = earliestInstallable(tree, tree, pkg, log) || tree + var parent = earliestInstallable(tree, tree, pkg, log, null) || tree var isLink = pkg._requested.type === 'directory' var child = createChild({ package: pkg, @@ -755,11 +755,11 @@ function preserveSymlinks () { // Find the highest level in the tree that we can install this module in. // If the module isn't installed above us yet, that'd be the very top. // If it is, then it's the level below where its installed. -var earliestInstallable = exports.earliestInstallable = function (requiredBy, tree, pkg, log) { - validate('OOOO', arguments) +var earliestInstallable = exports.earliestInstallable = function (requiredBy, tree, pkg, log, ignoreChild) { + validate('OOOOZ|OOOOO', arguments) function undeletedModuleMatches (child) { - return !child.removed && moduleName(child) === pkg.name + return child !== ignoreChild && !child.removed && moduleName(child) === pkg.name } const undeletedMatches = tree.children.filter(undeletedModuleMatches) if (undeletedMatches.length) { @@ -778,7 +778,7 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr // If any of the children of this tree have conflicting // binaries then we need to decline to install this package here. var binaryMatches = pkg.bin && tree.children.some(function (child) { - if (child.removed || !child.package.bin) return false + if (child === ignoreChild || child.removed || !child.package.bin) return false return Object.keys(child.package.bin).some(function (bin) { return pkg.bin[bin] }) @@ -804,6 +804,23 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr if (tree.phantomChildren && tree.phantomChildren[pkg.name]) return null + // if any of the peer dependencies is a dependency of the current + // tree locations, we place the package here. This is a safe location + // where we don't violate the peer dependencies contract. + // It may not be the perfect location in some cases, but we don't know + // if dependencies are hoisted to another location yet, as they + // may not be loaded into the tree yet. + // We can ignore dev deps here as they are only installed on top-level + // and we can't hoist further than that anyway. + var peerDeps = pkg.peerDependencies + if (peerDeps) { + if (Object.keys(peerDeps).some(function (name) { + return deps[name] + })) { + return tree + } + } + if (tree.isTop) return tree if (tree.isGlobal) return tree @@ -812,5 +829,5 @@ var earliestInstallable = exports.earliestInstallable = function (requiredBy, tr if (!preserveSymlinks() && /^[.][.][\\/]/.test(path.relative(tree.parent.realpath, tree.realpath))) return tree - return (earliestInstallable(requiredBy, tree.parent, pkg, log) || tree) + return (earliestInstallable(requiredBy, tree.parent, pkg, log, ignoreChild) || tree) } diff --git a/lib/ls.js b/lib/ls.js index bb5e433f78fde..8653fc718ae4a 100644 --- a/lib/ls.js +++ b/lib/ls.js @@ -305,7 +305,7 @@ function filterFound (root, args) { if (!markDeps) continue Object.keys(markDeps).forEach(function (depName) { var dep = markDeps[depName] - if (dep.peerMissing) return + if (dep.peerMissing && !dep._from) return dep._parent = markPkg for (var ii = 0; ii < args.length; ii++) { var argName = args[ii][0] diff --git a/lib/outdated.js b/lib/outdated.js index ebd67fb6b37d5..baeb5e7179df4 100644 --- a/lib/outdated.js +++ b/lib/outdated.js @@ -157,7 +157,7 @@ function makePretty (p, opts) { } if (opts.color) { - columns[0] = color[has === want || want === 'linked' ? 'yellow' : 'red'](columns[0]) // dep + columns[0] = color[has === want ? 'yellow' : 'red'](columns[0]) // dep columns[2] = color.green(columns[2]) // want columns[3] = color.magenta(columns[3]) // latest } diff --git a/lib/token.js b/lib/token.js index cccbba2f9ad75..326f98ec7ef87 100644 --- a/lib/token.js +++ b/lib/token.js @@ -1,6 +1,9 @@ 'use strict' + const profile = require('libnpm/profile') const npm = require('./npm.js') +const figgyPudding = require('figgy-pudding') +const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const Table = require('cli-table3') const Bluebird = require('bluebird') @@ -76,22 +79,43 @@ function generateTokenIds (tokens, minLength) { return byId } +const TokenConfig = figgyPudding({ + registry: {}, + otp: {}, + cidr: {}, + 'read-only': {}, + json: {}, + parseable: {} +}) + function config () { - const conf = { - json: npm.config.get('json'), - parseable: npm.config.get('parseable'), - registry: npm.config.get('registry'), - otp: npm.config.get('otp') - } + let conf = TokenConfig(npmConfig()) const creds = npm.config.getCredentialsByURI(conf.registry) if (creds.token) { - conf.auth = {token: creds.token} + conf = conf.concat({ + auth: { token: creds.token } + }) } else if (creds.username) { - conf.auth = {basic: {username: creds.username, password: creds.password}} + conf = conf.concat({ + auth: { + basic: { + username: creds.username, + password: creds.password + } + } + }) } else if (creds.auth) { const auth = Buffer.from(creds.auth, 'base64').toString().split(':', 2) - conf.auth = {basic: {username: auth[0], password: auth[1]}} + conf = conf.concat({ + auth: { + basic: { + username: auth[0], + password: auth[1] + } + } + }) } else { + conf = conf.concat({ auth: {} }) conf.auth = {} } if (conf.otp) conf.auth.otp = conf.otp @@ -183,8 +207,8 @@ function rm (args) { function create (args) { const conf = config() - const cidr = npm.config.get('cidr') - const readonly = npm.config.get('read-only') + const cidr = conf.cidr + const readonly = conf['read-only'] const validCIDR = validateCIDRList(cidr) return readUserInfo.password().then((password) => { diff --git a/lib/update.js b/lib/update.js index 9b1345f9dfbfb..fdb934fac6730 100644 --- a/lib/update.js +++ b/lib/update.js @@ -46,7 +46,7 @@ function update_ (args) { "because it's currently at the maximum version that matches its specified semver range" ) } - return ww.current !== ww.wanted && ww.latest !== 'linked' + return ww.current !== ww.wanted }) if (wanted.length === 0) return diff --git a/node_modules/.gitignore b/node_modules/.gitignore index 06e52612ce876..ac8c182e8fdc7 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -1,5 +1,4 @@ ## Automatically generated dev dependency ignores -/@types /@types/caseless /@types/form-data /@types/node diff --git a/node_modules/npm-registry-fetch/CHANGELOG.md b/node_modules/npm-registry-fetch/CHANGELOG.md index 71232eff75c0e..56d849a773037 100644 --- a/node_modules/npm-registry-fetch/CHANGELOG.md +++ b/node_modules/npm-registry-fetch/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +# [3.9.0](https://github.com/npm/registry-fetch/compare/v3.8.0...v3.9.0) (2019-01-24) + + +### Features + +* **auth:** support username:password encoded legacy _auth ([a91f90c](https://github.com/npm/registry-fetch/commit/a91f90c)) + + + # [3.8.0](https://github.com/npm/registry-fetch/compare/v3.7.0...v3.8.0) (2018-08-23) diff --git a/node_modules/npm-registry-fetch/auth.js b/node_modules/npm-registry-fetch/auth.js index fa696b97ddee5..d583982d0a8b2 100644 --- a/node_modules/npm-registry-fetch/auth.js +++ b/node_modules/npm-registry-fetch/auth.js @@ -25,6 +25,12 @@ function getAuth (registry, opts) { if (AUTH.password) { AUTH.password = Buffer.from(AUTH.password, 'base64').toString('utf8') } + if (AUTH._auth && !(AUTH.username && AUTH.password)) { + let auth = Buffer.from(AUTH._auth, 'base64').toString() + auth = auth.split(':') + AUTH.username = auth.shift() + AUTH.password = auth.join(':') + } AUTH.alwaysAuth = AUTH.alwaysAuth === 'false' ? false : !!AUTH.alwaysAuth return AUTH } diff --git a/node_modules/npm-registry-fetch/package.json b/node_modules/npm-registry-fetch/package.json index 81a00978e2e4e..0ffa9a8b9e823 100644 --- a/node_modules/npm-registry-fetch/package.json +++ b/node_modules/npm-registry-fetch/package.json @@ -1,8 +1,8 @@ { "_from": "npm-registry-fetch@latest", - "_id": "npm-registry-fetch@3.8.0", + "_id": "npm-registry-fetch@3.9.0", "_inBundle": false, - "_integrity": "sha512-hrw8UMD+Nob3Kl3h8Z/YjmKamb1gf7D1ZZch2otrIXM3uFLB5vjEY6DhMlq80z/zZet6eETLbOXcuQudCB3Zpw==", + "_integrity": "sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==", "_location": "/npm-registry-fetch", "_phantomChildren": {}, "_requested": { @@ -18,12 +18,18 @@ "_requiredBy": [ "#USER", "/", + "/libnpm", "/libnpmaccess", "/libnpmhook", + "/libnpmorg", + "/libnpmpublish", + "/libnpmsearch", + "/libnpmteam", + "/npm-profile", "/pacote" ], - "_resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz", - "_shasum": "aa7d9a7c92aff94f48dba0984bdef4bd131c88cc", + "_resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz", + "_shasum": "44d841780e2833f06accb34488f8c7450d1a6856", "_spec": "npm-registry-fetch@latest", "_where": "/Users/zkat/Documents/code/work/npm", "author": { @@ -92,5 +98,5 @@ "update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" }, - "version": "3.8.0" + "version": "3.9.0" } diff --git a/node_modules/pacote/CHANGELOG.md b/node_modules/pacote/CHANGELOG.md index 50a0dbde402cb..a7784d9bb1193 100644 --- a/node_modules/pacote/CHANGELOG.md +++ b/node_modules/pacote/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## [9.4.1](https://github.com/zkat/pacote/compare/v9.4.0...v9.4.1) (2019-01-24) + + +### Bug Fixes + +* **directory, finalize-manifest:** strip byte order marker from JSON ([723ad63](https://github.com/zkat/pacote/commit/723ad63)) + + + # [9.4.0](https://github.com/zkat/pacote/compare/v9.3.0...v9.4.0) (2019-01-14) diff --git a/node_modules/pacote/lib/fetchers/directory.js b/node_modules/pacote/lib/fetchers/directory.js index 83f3d7d558cb1..3d4ec24c83f27 100644 --- a/node_modules/pacote/lib/fetchers/directory.js +++ b/node_modules/pacote/lib/fetchers/directory.js @@ -5,6 +5,7 @@ const BB = require('bluebird') const Fetcher = require('../fetch') const glob = BB.promisify(require('glob')) const packDir = require('../util/pack-dir') +const readJson = require('../util/read-json') const path = require('path') const pipe = BB.promisify(require('mississippi').pipe) const through = require('mississippi').through @@ -34,11 +35,11 @@ Fetcher.impl(fetchDirectory, { const pkgPath = path.join(spec.fetchSpec, 'package.json') const srPath = path.join(spec.fetchSpec, 'npm-shrinkwrap.json') return BB.join( - readFileAsync(pkgPath).then(JSON.parse).catch({ code: 'ENOENT' }, err => { + readFileAsync(pkgPath).then(readJson).catch({ code: 'ENOENT' }, err => { err.code = 'ENOPACKAGEJSON' throw err }), - readFileAsync(srPath).then(JSON.parse).catch({ code: 'ENOENT' }, () => null), + readFileAsync(srPath).then(readJson).catch({ code: 'ENOENT' }, () => null), (pkg, sr) => { pkg._shrinkwrap = sr pkg._hasShrinkwrap = !!sr diff --git a/node_modules/pacote/lib/finalize-manifest.js b/node_modules/pacote/lib/finalize-manifest.js index 80b379898fe4c..f047517945192 100644 --- a/node_modules/pacote/lib/finalize-manifest.js +++ b/node_modules/pacote/lib/finalize-manifest.js @@ -13,6 +13,7 @@ const path = require('path') const pipe = BB.promisify(require('mississippi').pipe) const ssri = require('ssri') const tar = require('tar') +const readJson = require('./util/read-json') // `finalizeManifest` takes as input the various kinds of manifests that // manifest handlers ('lib/fetchers/*.js#manifest()') return, and makes sure @@ -212,7 +213,7 @@ function jsonFromStream (filename, dataStream) { entry.on('error', cb) finished(entry).then(() => { try { - cb(null, JSON.parse(data)) + cb(null, readJson(data)) } catch (err) { cb(err) } diff --git a/node_modules/pacote/lib/util/read-json.js b/node_modules/pacote/lib/util/read-json.js new file mode 100644 index 0000000000000..32fffbc53746b --- /dev/null +++ b/node_modules/pacote/lib/util/read-json.js @@ -0,0 +1,15 @@ +'use strict' + +module.exports = function (content) { + // Code also yanked from read-package-json. + function stripBOM (content) { + content = content.toString() + // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) + // because the buffer-to-string conversion in `fs.readFileSync()` + // translates it to FEFF, the UTF-16 BOM. + if (content.charCodeAt(0) === 0xFEFF) return content.slice(1) + return content + } + + return JSON.parse(stripBOM(content)) +} diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 32e8a07b094e1..96ae38bd682a6 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,8 +1,8 @@ { - "_from": "pacote@9.4.0", - "_id": "pacote@9.4.0", + "_from": "pacote@9.4.1", + "_id": "pacote@9.4.1", "_inBundle": false, - "_integrity": "sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w==", + "_integrity": "sha512-YKSRsQqmeHxgra0KCdWA2FtVxDPUlBiCdmew+mSe44pzlx5t1ViRMWiQg18T+DREA+vSqYfKzynaToFR4hcKHw==", "_location": "/pacote", "_phantomChildren": { "safe-buffer": "5.1.2" @@ -10,12 +10,12 @@ "_requested": { "type": "version", "registry": true, - "raw": "pacote@9.4.0", + "raw": "pacote@9.4.1", "name": "pacote", "escapedName": "pacote", - "rawSpec": "9.4.0", + "rawSpec": "9.4.1", "saveSpec": null, - "fetchSpec": "9.4.0" + "fetchSpec": "9.4.1" }, "_requiredBy": [ "#USER", @@ -23,10 +23,10 @@ "/libcipm", "/libnpm" ], - "_resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.0.tgz", - "_shasum": "af979abdeb175cd347c3e33be3241af1ed254807", - "_spec": "pacote@9.4.0", - "_where": "/Users/aeschright/code/cli", + "_resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.1.tgz", + "_shasum": "f0af2a52d241bce523d39280ac810c671db62279", + "_spec": "pacote@9.4.1", + "_where": "/Users/aeschright/code/npm-release", "author": { "name": "Kat Marchán", "email": "kzm@sykosomatic.org" @@ -116,5 +116,5 @@ "update-coc": "weallbehave -o . && git add CODE_OF_CONDUCT.md && git commit -m 'docs(coc): updated CODE_OF_CONDUCT.md'", "update-contrib": "weallcontribute -o . && git add CONTRIBUTING.md && git commit -m 'docs(contributing): updated CONTRIBUTING.md'" }, - "version": "9.4.0" + "version": "9.4.1" } diff --git a/package-lock.json b/package-lock.json index a2f2fd4a3c079..a2201108d4c2c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "npm", - "version": "6.7.0", + "version": "6.8.0-next.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3296,9 +3296,9 @@ } }, "npm-registry-fetch": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.8.0.tgz", - "integrity": "sha512-hrw8UMD+Nob3Kl3h8Z/YjmKamb1gf7D1ZZch2otrIXM3uFLB5vjEY6DhMlq80z/zZet6eETLbOXcuQudCB3Zpw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-3.9.0.tgz", + "integrity": "sha512-srwmt8YhNajAoSAaDWndmZgx89lJwIZ1GWxOuckH4Coek4uHv5S+o/l9FLQe/awA+JwTnj4FJHldxhlXdZEBmw==", "requires": { "JSONStream": "^1.3.4", "bluebird": "^3.5.1", @@ -6145,9 +6145,9 @@ } }, "pacote": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.0.tgz", - "integrity": "sha512-WQ1KL/phGMkedYEQx9ODsjj7xvwLSpdFJJdEXrLyw5SILMxcTNt5DTxT2Z93fXuLFYJBlZJdnwdalrQdB/rX5w==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.4.1.tgz", + "integrity": "sha512-YKSRsQqmeHxgra0KCdWA2FtVxDPUlBiCdmew+mSe44pzlx5t1ViRMWiQg18T+DREA+vSqYfKzynaToFR4hcKHw==", "requires": { "bluebird": "^3.5.3", "cacache": "^11.3.2", diff --git a/package.json b/package.json index 0b795b363e15c..0244769929dae 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "6.7.0", + "version": "6.8.0-next.0", "name": "npm", "description": "a package manager for JavaScript", "keywords": [ @@ -98,13 +98,13 @@ "npm-package-arg": "^6.1.0", "npm-packlist": "^1.2.0", "npm-pick-manifest": "^2.2.3", - "npm-registry-fetch": "^3.8.0", + "npm-registry-fetch": "^3.9.0", "npm-user-validate": "~1.0.0", "npmlog": "~4.1.2", "once": "~1.4.0", "opener": "^1.5.1", "osenv": "^0.1.5", - "pacote": "^9.4.0", + "pacote": "^9.4.1", "path-is-inside": "~1.0.2", "promise-inflight": "~1.0.1", "qrcode-terminal": "^0.12.0", diff --git a/scripts/maketest b/scripts/maketest index bf0c2c5f655db..4ef1e9266fb04 100755 --- a/scripts/maketest +++ b/scripts/maketest @@ -69,7 +69,7 @@ test('setup', t => { }) test('example', t => { - return common.npm(['install'], conf).then((code, stdout, stderr) => { + return common.npm(['install'], conf).then(([code, stdout, stderr]) => { t.is(code, 0, 'command ran ok') t.comment(stdout.trim()) t.comment(stderr.trim()) diff --git a/test/tap/access.js b/test/tap/access.js index 6a21ccc8fb3ef..d400b4d33b134 100644 --- a/test/tap/access.js +++ b/test/tap/access.js @@ -469,6 +469,34 @@ test('npm access ls-collaborators on package', function (t) { ) }) +test('npm access ls-collaborators on unscoped', function (t) { + var serverCollaborators = { + 'myorg:myteam': 'write', + 'myorg:anotherteam': 'read' + } + var clientCollaborators = { + 'myorg:myteam': 'read-write', + 'myorg:anotherteam': 'read-only' + } + server.get( + '/-/package/pkg/collaborators?format=cli' + ).reply(200, serverCollaborators) + common.npm( + [ + 'access', + 'ls-collaborators', + 'pkg', + '--registry', common.registry + ], + { cwd: pkg }, + function (er, code, stdout, stderr) { + t.ifError(er, 'npm access ls-collaborators') + t.same(JSON.parse(stdout), clientCollaborators) + t.end() + } + ) +}) + test('npm access ls-collaborators on current w/user filter', function (t) { var serverCollaborators = { 'myorg:myteam': 'write', diff --git a/test/tap/hoist-peer-dependencies.js b/test/tap/hoist-peer-dependencies.js new file mode 100644 index 0000000000000..75d7d3e778ada --- /dev/null +++ b/test/tap/hoist-peer-dependencies.js @@ -0,0 +1,130 @@ +'use strict' +const path = require('path') +const fs = require('fs') +const test = require('tap').test +const Tacks = require('tacks') +const File = Tacks.File +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: testdir, + env: common.newEnv().extend({ + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + package: Dir({ + 'package.json': File({ + name: 'package', + version: '1.0.0', + dependencies: { + 'base-dep': '../packages/base-dep-1.0.0.tgz', + 'plugin-dep': '../packages/plugin-dep-1.0.0.tgz' + } + }) + }), + 'package.json': File({ + version: '1.0.0', + dependencies: { + package: 'file:./package', + 'base-dep': './packages/base-dep-2.0.0.tgz' + } + }), + // file: dependencies do not work as they are symlinked and behave + // differently. Instead installation from tgz files is used. + packages: Dir({ + 'base-dep-1.0.0.tgz': File(Buffer.from( + '1f8b080000000000000a2b484cce4e4c4fd52f80d07a59c5f9790c540606' + + '06066666660ad8c4c1c0d45c81c1d8d4ccc0d0d0ccccc0448101c8303505' + + 'd1d4760836505a5c925804740aa5e640bca200a78708a8e6525050ca4bcc' + + '4d55b252504a4a2c4ed54d492d50d2018996a5161567e6e781240cf50cf4' + + '0c94b86ab906dab9a360148c8251300aa80400a44d97d100080000', + 'hex' + )), + 'base-dep-2.0.0.tgz': File(Buffer.from( + '1f8b080000000000000a2b484cce4e4c4fd52f80d07a59c5f9790c540606' + + '06066666660ad8c4c1c0d45c81c1d8d4ccc0d0d0ccccc0448101c8303505' + + 'd1d4760836505a5c925804740aa5e640bca200a78708a8e6525050ca4bcc' + + '4d55b252504a4a2c4ed54d492d50d2018996a5161567e6e781248cf40cf4' + + '0c94b86ab906dab9a360148c8251300aa80400aebbeeba00080000', + 'hex' + )), + 'plugin-dep-1.0.0.tgz': File(Buffer.from( + '1f8b080000000000000aed8f3d0e83300c8599394594b904476d3274e622' + + '295888fe8488408756dcbd0e513bb115a9aa946f79ce7bb1653b535f4c8b' + + 'a58b2acebeb7d9c60080d69aadf90119b2bdd220a98203cba8504a916ebd' + + 'c81a931fcd40ab7c3b27dec23efa273c73c6b83537e447c6dd756a3b5b34' + + 'e8f82ef8771c7cd7db10490102a2eb10870a1dda066ddda1a7384ca1e464' + + '3c2eddd42044f97e164bb318db07a77f733ee7bfbe3a914824122f4e04e9' + + '2e00080000', + 'hex' + )) + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', t => { + setup() + return common.fakeRegistry.listen() +}) + +test('example', t => { + return common.npm(['install'], conf).then(([code, stdout, stderr]) => { + t.is(code, 0, 'command ran ok') + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.ok(fs.existsSync(path.join(testdir, 'node_modules')), 'did install') + var packageLock = JSON.parse(fs.readFileSync(path.join(testdir, 'package-lock.json'), 'utf8')) + t.similar(packageLock, { + dependencies: { + 'base-dep': { + version: 'file:packages/base-dep-2.0.0.tgz' + }, + 'package': { + version: 'file:package', + dependencies: { + 'base-dep': { + version: 'file:packages/base-dep-1.0.0.tgz' + }, + // plugin-dep must not placed on top-level + 'plugin-dep': { + version: 'file:packages/plugin-dep-1.0.0.tgz' + } + } + } + } + }, 'locks dependencies as unhoisted') + t.similar(Object.keys(packageLock.dependencies), ['base-dep', 'package'], 'has correct packages on top-level') + }) +}) + +test('cleanup', t => { + common.fakeRegistry.close() + cleanup() + t.done() +}) diff --git a/test/tap/ls-peer.js b/test/tap/ls-peer.js new file mode 100644 index 0000000000000..826380932a147 --- /dev/null +++ b/test/tap/ls-peer.js @@ -0,0 +1,123 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const Tacks = require('tacks') +const File = Tacks.File +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: testdir, + env: common.newEnv().extend({ + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + 'package.json': File({ + name: 'fixture', + version: '1.0.0', + dependencies: { + dep: 'file:dep-1.0.0.tgz', + 'peer-dep': 'file:peer-dep-2.0.0.tgz' + } + }), + // Source dir + // dep: Dir({ + // 'package.json': File({ + // name: 'dep', + // version: '1.0.0', + // peerDependencies: { + // 'peer-dep': 'file:peer-dep-1.0.0.tgz' + // } + // }) + // }), + 'dep-1.0.0.tgz': File(Buffer.from( + '1f8b0800000000000003ed8f3d0ec2300c853be71451661a1cd166e8cc45' + + 'a2d654e1278d92c200eadd491a60ea462584946fb1f5fc9e655bd59e548f' + + '5b9b2a3ffac1142b0300b2aae8921e1152d062574b10424a08bed0d4d10f' + + '6b1fb2c4d58fca8553bedd937ea19ffa273c08a5cca80bb286b20e2ddb44' + + 'e186ceebc1444d70e090548be8f668d174685a8d3e8c63fc3529633a040e' + + 'fa8ccd5b28e7381ffb3b0bce894ce4d70f6732994c66e60975aec5690008' + + '0000', + 'hex' + )), + // Source dir + // 'peer-dep': Dir({ + // 'package.json': File({ + // name: 'peer-dep', + // version: '2.0.0' + // }) + // }), + 'peer-dep-1.0.0.tgz': File(Buffer.from( + '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' + + '06066626260ad8c4c1c0d45c81c1d8d4ccc0d0d0cccc00a80ec830353500' + + 'd2d4760836505a5c925804740aa5e640bca200a78708a8e6525050ca4bcc' + + '4d55b252502a484d2dd24d492d50d2018996a5161567e6e781240cf50cf4' + + '0c94b86ab906dab9a360148c8251300aa80400c1c67f6300080000', + 'hex' + )), + 'peer-dep-2.0.0.tgz': File(Buffer.from( + '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' + + '06066626260ad8c4c1c0d45c81c1d8d4ccc0d0d0cccc00a80ec830353500' + + 'd2d4760836505a5c925804740aa5e640bca200a78708a8e6525050ca4bcc' + + '4d55b252502a484d2dd24d492d50d2018996a5161567e6e781248cf40cf4' + + '0c94b86ab906dab9a360148c8251300aa80400cb30060800080000', + 'hex' + )) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', t => { + setup() + return common.fakeRegistry.listen().then(() => common.npm(['install'], conf)) +}) + +test('list warns about unmet peer dependency', t => { + return common.npm(['ls'], conf).then(([code, stdout, stderr]) => { + t.is(code, 1, 'command ran not ok') + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.match(stdout, 'UNMET PEER DEPENDENCY peer-dep@2.0.0') + t.match(stderr, 'npm ERR! peer dep missing: peer-dep@file:peer-dep-1.0.0.tgz, required by dep@1.0.0') + }) +}) + +test('list shows installed but unmet peer dependency', t => { + return common.npm(['ls', 'peer-dep'], conf).then(([code, stdout, stderr]) => { + t.is(code, 1, 'command ran not ok') + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.match(stdout, 'UNMET PEER DEPENDENCY peer-dep@2.0.0') + t.match(stderr, 'npm ERR! peer dep missing: peer-dep@file:peer-dep-1.0.0.tgz, required by dep@1.0.0') + }) +}) + +test('cleanup', t => { + common.fakeRegistry.close() + cleanup() + t.done() +}) diff --git a/test/tap/outdated-symlink.js b/test/tap/outdated-symlink.js new file mode 100644 index 0000000000000..96d6f660e2100 --- /dev/null +++ b/test/tap/outdated-symlink.js @@ -0,0 +1,133 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const File = Tacks.File +const Symlink = Tacks.Symlink +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: path.join(testdir, 'main'), + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +let server +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + broken: Dir({ + 'package.json': File({ + name: 'broken', + version: '1.0.0' + }) + }), + main: Dir({ + node_modules: Dir({ + unbroken: Symlink('/testdir/unbroken') + }), + 'package-lock.json': File({ + name: 'main', + version: '1.0.0', + lockfileVersion: 1, + requires: true, + dependencies: { + broken: { + version: 'file:../broken' + }, + unbroken: { + version: 'file:../unbroken' + } + } + }), + 'package.json': File({ + name: 'main', + version: '1.0.0', + dependencies: { + broken: 'file:../broken', + unbroken: 'file:../unbroken' + } + }) + }), + unbroken: Dir({ + 'package.json': File({ + name: 'unbroken', + version: '1.0.0' + }) + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + t.done() + }) +}) + +test('outdated sees broken links', function (t) { + common.npm(['outdated', '--json'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 1, 'command ran not ok') + t.comment(stderr.trim()) + t.comment(stdout.trim()) + t.same(JSON.parse(stdout), { + broken: { + wanted: 'linked', + latest: 'linked', + location: '' + } + }) + t.done() + }) +}) + +test('outdated with long output sees broken links', function (t) { + common.npm(['outdated', '--long', '--json'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 1, 'command ran not ok') + t.comment(stderr.trim()) + t.comment(stdout.trim()) + t.same(JSON.parse(stdout), { + broken: { + wanted: 'linked', + latest: 'linked', + type: 'dependencies', + location: '' + } + }) + t.done() + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +}) diff --git a/test/tap/unit-deps-earliestInstallable.js b/test/tap/unit-deps-earliestInstallable.js index 47d1ab4119b1e..136e6478c586a 100644 --- a/test/tap/unit-deps-earliestInstallable.js +++ b/test/tap/unit-deps-earliestInstallable.js @@ -67,7 +67,7 @@ test('earliestInstallable should consider devDependencies', function (t) { dep2a.parent = dep1 dep2.parent = pkg - var earliest = earliestInstallable(dep1, dep1, dep2a.package, log) + var earliest = earliestInstallable(dep1, dep1, dep2a.package, log, null) t.isDeeply(earliest, dep1, 'should hoist package when an incompatible devDependency is present') t.end() }) @@ -108,7 +108,58 @@ test('earliestInstallable should reuse shared prod/dev deps when they are identi dep1.parent = pkg dep2.parent = pkg - var earliest = earliestInstallable(dep1, dep1, dep2.package, log) + var earliest = earliestInstallable(dep1, dep1, dep2.package, log, null) t.isDeeply(earliest, pkg, 'should reuse identical shared dev/prod deps when installing both') t.end() }) + +test('earliestInstallable should consider peerDependencies', function (t) { + var dep1 = { + children: [], + package: { + name: 'dep1', + dependencies: { + dep2: '1.0.0', + dep3: '1.0.0' + } + }, + path: '/dep1', + realpath: '/dep1' + } + + var dep2 = { + package: { + name: 'dep2', + version: '1.0.0', + peerDependencies: { + dep3: '1.0.0' + }, + _requested: npa('dep2@^1.0.0') + }, + parent: dep1, + path: '/dep1/node_modules/dep2', + realpath: '/dep1/node_modules/dep2' + } + + var pkg = { + isTop: true, + children: [dep1], + package: { + name: 'pkg', + dependencies: { dep1: '1.0.0' } + }, + path: '/', + realpath: '/' + } + + dep1.parent = pkg + + var earliest = earliestInstallable(dep1, dep1, dep2.package, log, null) + t.isDeeply(earliest, dep1, 'should not be able to hoist the package to top-level') + + dep1.children.push(dep2) + + var earliestWithIgnore = earliestInstallable(dep1, dep1, dep2.package, log, dep2) + t.isDeeply(earliestWithIgnore, dep1, 'should not be able to hoist the package to top-level') + t.end() +}) diff --git a/test/tap/unit-token-validate-cidr.js b/test/tap/unit-token-validate-cidr.js index db963c31f386d..cda91b8f1e0da 100644 --- a/test/tap/unit-token-validate-cidr.js +++ b/test/tap/unit-token-validate-cidr.js @@ -1,7 +1,6 @@ 'use strict' const test = require('tap').test -const requireInject = require('require-inject') -const validateCIDRList = requireInject('../../lib/token.js', {'../../lib/npm.js': {}})._validateCIDRList +const validateCIDRList = require('../../lib/token.js')._validateCIDRList test('validateCIDRList', (t) => { t.plan(10) diff --git a/test/tap/update-symlink.js b/test/tap/update-symlink.js new file mode 100644 index 0000000000000..79139d306f5fd --- /dev/null +++ b/test/tap/update-symlink.js @@ -0,0 +1,109 @@ +'use strict' +const path = require('path') +const test = require('tap').test +const mr = require('npm-registry-mock') +const Tacks = require('tacks') +const File = Tacks.File +const Symlink = Tacks.Symlink +const Dir = Tacks.Dir +const common = require('../common-tap.js') + +const basedir = path.join(__dirname, path.basename(__filename, '.js')) +const testdir = path.join(basedir, 'testdir') +const cachedir = path.join(basedir, 'cache') +const globaldir = path.join(basedir, 'global') +const tmpdir = path.join(basedir, 'tmp') + +const conf = { + cwd: path.join(testdir, 'main'), + env: Object.assign({}, process.env, { + npm_config_cache: cachedir, + npm_config_tmp: tmpdir, + npm_config_prefix: globaldir, + npm_config_registry: common.registry, + npm_config_loglevel: 'warn' + }) +} + +let server +const fixture = new Tacks(Dir({ + cache: Dir(), + global: Dir(), + tmp: Dir(), + testdir: Dir({ + broken: Dir({ + 'package.json': File({ + name: 'broken', + version: '1.0.0' + }) + }), + main: Dir({ + node_modules: Dir({ + unbroken: Symlink('/testdir/unbroken') + }), + 'package-lock.json': File({ + name: 'main', + version: '1.0.0', + lockfileVersion: 1, + requires: true, + dependencies: { + broken: { + version: 'file:../broken' + }, + unbroken: { + version: 'file:../unbroken' + } + } + }), + 'package.json': File({ + name: 'main', + version: '1.0.0', + dependencies: { + broken: 'file:../broken', + unbroken: 'file:../unbroken' + } + }) + }), + unbroken: Dir({ + 'package.json': File({ + name: 'unbroken', + version: '1.0.0' + }) + }) + }) +})) + +function setup () { + cleanup() + fixture.create(basedir) +} + +function cleanup () { + fixture.remove(basedir) +} + +test('setup', function (t) { + setup() + mr({port: common.port, throwOnUnmatched: true}, function (err, s) { + if (err) throw err + server = s + t.done() + }) +}) + +test('update fixes broken links', function (t) { + common.npm(['update'], conf, function (err, code, stdout, stderr) { + if (err) throw err + t.is(code, 0, 'command ran ok') + t.comment(stdout.trim()) + t.comment(stderr.trim()) + t.match(stdout, '+ broken@1.0.0') + t.done() + }) +}) + +test('cleanup', function (t) { + server.close() + cleanup() + t.done() +})