From 601bb1196254fc63251cbf0d79371eb57a9feca1 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 14 Sep 2022 13:24:04 -0700 Subject: [PATCH 01/40] chore: template-oss@4.1.2 --- .github/workflows/release-please.yml | 2 +- docs/package.json | 4 +-- package-lock.json | 37 ++++++++++++++------------- package.json | 4 +-- smoke-tests/package.json | 4 +-- workspaces/arborist/package.json | 4 +-- workspaces/libnpmaccess/package.json | 4 +-- workspaces/libnpmdiff/package.json | 4 +-- workspaces/libnpmexec/package.json | 4 +-- workspaces/libnpmfund/package.json | 4 +-- workspaces/libnpmhook/package.json | 4 +-- workspaces/libnpmorg/package.json | 4 +-- workspaces/libnpmpack/package.json | 4 +-- workspaces/libnpmpublish/package.json | 4 +-- workspaces/libnpmsearch/package.json | 4 +-- workspaces/libnpmteam/package.json | 4 +-- workspaces/libnpmversion/package.json | 4 +-- 17 files changed, 50 insertions(+), 49 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index a61f5dbb82c67..edd39d0ba5da3 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -33,7 +33,7 @@ jobs: - run: npm i --ignore-scripts --no-audit --no-fund - name: Release Please id: release - run: npx --offline template-oss-release-please + run: npx --offline template-oss-release-please ${{ github.ref_name }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/package.json b/docs/package.json index 7950fed4eb1a9..74c575337f736 100644 --- a/docs/package.json +++ b/docs/package.json @@ -22,7 +22,7 @@ "@npmcli/eslint-config": "^3.1.0", "@npmcli/fs": "^2.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "cmark-gfm": "^0.9.0", "jsdom": "^18.1.0", "marked-man": "^0.7.0", @@ -59,6 +59,6 @@ "ciVersions": [ "16" ], - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/package-lock.json b/package-lock.json index 839a21597390d..bf31065aeb9a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -169,7 +169,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "fs-minipass": "^2.1.0", "licensee": "^8.2.0", "minimatch": "^5.1.0", @@ -189,7 +189,7 @@ "@npmcli/eslint-config": "^3.1.0", "@npmcli/fs": "^2.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "cmark-gfm": "^0.9.0", "jsdom": "^18.1.0", "marked-man": "^0.7.0", @@ -2362,15 +2362,16 @@ } }, "node_modules/@npmcli/template-oss": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/template-oss/-/template-oss-4.0.0.tgz", - "integrity": "sha512-4e4oYjMN3d1AN2PhDNZGAaIRAi/3p76jDdWREsuGZ8Du084QAcazl+uV2CKbDwsalOPeS46stDJwuuFG9riFzQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/template-oss/-/template-oss-4.1.2.tgz", + "integrity": "sha512-BS9YZeRtLsZ+lnCcQV3tZQa25K+MbUz/MgX5ZFzRmU+gTgCGthfajXZ7r8jJTjSiNgrElS0Ty/+x6Ds6B7oFdw==", "dev": true, "hasInstallScript": true, "dependencies": { "@actions/core": "^1.9.1", "@commitlint/cli": "^17.1.1", "@commitlint/config-conventional": "^17.1.0", + "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^2.0.1", "@npmcli/git": "^3.0.0", "@npmcli/map-workspaces": "^2.0.2", @@ -13843,7 +13844,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "minify-registry-metadata": "^2.2.0", "rimraf": "^3.0.2", "tap": "^16.0.1", @@ -13900,7 +13901,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "benchmark": "^2.1.4", "chalk": "^4.1.0", "minify-registry-metadata": "^2.1.0", @@ -13923,7 +13924,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -13946,7 +13947,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "tap": "^16.0.1" }, "engines": { @@ -13974,7 +13975,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "bin-links": "^3.0.3", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", @@ -13992,7 +13993,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "tap": "^16.0.1" }, "engines": { @@ -14008,7 +14009,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14025,7 +14026,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "minipass": "^3.1.1", "nock": "^13.2.4", "tap": "^16.0.1" @@ -14044,7 +14045,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.0.7", "tap": "^16.0.1" }, @@ -14064,7 +14065,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "libnpmpack": "^5.0.0-pre.0", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", @@ -14082,7 +14083,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14099,7 +14100,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14119,7 +14120,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "require-inject": "^1.4.4", "tap": "^16.0.1" }, diff --git a/package.json b/package.json index 703868e646b01..2ff60e51f9eba 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "fs-minipass": "^2.1.0", "licensee": "^8.2.0", "minimatch": "^5.1.0", @@ -251,7 +251,7 @@ "templateOSS": { "rootRepo": false, "rootModule": false, - "version": "4.0.0", + "version": "4.1.2", "releaseTest": "release.yml" }, "license": "Artistic-2.0", diff --git a/smoke-tests/package.json b/smoke-tests/package.json index 1c3d787723cf6..73ffde9910e39 100644 --- a/smoke-tests/package.json +++ b/smoke-tests/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "minify-registry-metadata": "^2.2.0", "rimraf": "^3.0.2", "tap": "^16.0.1", @@ -30,7 +30,7 @@ "license": "ISC", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0", + "version": "4.1.2", "workspaceRepo": false }, "tap": { diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index a6a1a0bc31124..b8384e5f0b5ee 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "benchmark": "^2.1.4", "chalk": "^4.1.0", "minify-registry-metadata": "^2.1.0", @@ -100,6 +100,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index 0c2df73a1ab1a..d05156710256b 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -43,6 +43,6 @@ ], "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index ee3a56a29889d..c1665390b8c53 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -43,7 +43,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "tap": "^16.0.1" }, "dependencies": { @@ -58,6 +58,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 8ac115d3fc732..3566779ac83bc 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -47,7 +47,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "bin-links": "^3.0.3", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", @@ -71,6 +71,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 9e69616c14552..c665fdeb16d29 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "tap": "^16.0.1" }, "dependencies": { @@ -53,6 +53,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmhook/package.json b/workspaces/libnpmhook/package.json index db94874c18bbb..a4f42a83e643a 100644 --- a/workspaces/libnpmhook/package.json +++ b/workspaces/libnpmhook/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -46,6 +46,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmorg/package.json b/workspaces/libnpmorg/package.json index b188a5e27859b..748dd83f00e79 100644 --- a/workspaces/libnpmorg/package.json +++ b/workspaces/libnpmorg/package.json @@ -28,7 +28,7 @@ ], "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "minipass": "^3.1.1", "nock": "^13.2.4", "tap": "^16.0.1" @@ -49,6 +49,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 545c2870a1ec3..f7d8fcfe28f7f 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.0.7", "tap": "^16.0.1" }, @@ -44,6 +44,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 07bead1202f1f..6959a8bd98354 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "libnpmpack": "^5.0.0-pre.0", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", @@ -50,6 +50,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmsearch/package.json b/workspaces/libnpmsearch/package.json index a10a51ec568ef..3581ecc31e876 100644 --- a/workspaces/libnpmsearch/package.json +++ b/workspaces/libnpmsearch/package.json @@ -26,7 +26,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -45,6 +45,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmteam/package.json b/workspaces/libnpmteam/package.json index 9c1f7cd5e9dbe..d9efe70197337 100644 --- a/workspaces/libnpmteam/package.json +++ b/workspaces/libnpmteam/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -39,6 +39,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } diff --git a/workspaces/libnpmversion/package.json b/workspaces/libnpmversion/package.json index ac3ecf47aeb4e..ec4e4bc8a73e6 100644 --- a/workspaces/libnpmversion/package.json +++ b/workspaces/libnpmversion/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.0.0", + "@npmcli/template-oss": "4.1.2", "require-inject": "^1.4.4", "tap": "^16.0.1" }, @@ -44,6 +44,6 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.0.0" + "version": "4.1.2" } } From 854521baa49ef88ff9586ec2cc5f1fbaee7fa364 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 30 Aug 2022 11:39:48 -0700 Subject: [PATCH 02/40] feat(rewrite): Rewrite libnpmaccess BREAKING CHANGE: the api for libnpmaccess is different now It is aligned more with how npm uses it, consolidating the mfa functions into a single command, and renames the functions to be easier to eventually consolidate into a registry client library. See the README for the new api. --- DEPENDENCIES.md | 2 - package-lock.json | 2 - workspaces/libnpmaccess/README.md | 235 +++---------- workspaces/libnpmaccess/lib/index.js | 254 ++++++-------- workspaces/libnpmaccess/package.json | 2 - workspaces/libnpmaccess/test/index.js | 465 ++++++++------------------ 6 files changed, 276 insertions(+), 684 deletions(-) diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 1ddd85b3d411d..105761dcb15bd 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -323,8 +323,6 @@ graph LR; init-package-json-->validate-npm-package-name; is-cidr-->cidr-regex; is-core-module-->has; - libnpmaccess-->aproba; - libnpmaccess-->minipass; libnpmaccess-->nock; libnpmaccess-->npm-package-arg; libnpmaccess-->npm-registry-fetch; diff --git a/package-lock.json b/package-lock.json index bf31065aeb9a5..e0a2304732744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13917,8 +13917,6 @@ "version": "7.0.0-pre.0", "license": "ISC", "dependencies": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", "npm-package-arg": "^9.0.1", "npm-registry-fetch": "^13.0.0" }, diff --git a/workspaces/libnpmaccess/README.md b/workspaces/libnpmaccess/README.md index 3e35562cfddbc..060016bc2a0b6 100644 --- a/workspaces/libnpmaccess/README.md +++ b/workspaces/libnpmaccess/README.md @@ -6,241 +6,88 @@ [`libnpmaccess`](https://github.com/npm/libnpmaccess) is a Node.js library that provides programmatic access to the guts of the npm CLI's `npm -access` command and its various subcommands. This includes managing account 2FA, -listing packages and permissions, looking at package collaborators, and defining +access` command. This includes managing account mfa settings, listing +packages and permissions, looking at package collaborators, and defining package permissions for users, orgs, and teams. ## Example ```javascript const access = require('libnpmaccess') +const opts = { '//registry.npmjs.org/:_authToken: 'npm_token } // List all packages @zkat has access to on the npm registry. -console.log(Object.keys(await access.lsPackages('zkat'))) +console.log(Object.keys(await access.getPackages('zkat', opts))) ``` -## Table of Contents - -* [Installing](#install) -* [Example](#example) -* [Contributing](#contributing) -* [API](#api) - * [access opts](#opts) - * [`public()`](#public) - * [`restricted()`](#restricted) - * [`grant()`](#grant) - * [`revoke()`](#revoke) - * [`tfaRequired()`](#tfa-required) - * [`tfaNotRequired()`](#tfa-not-required) - * [`lsPackages()`](#ls-packages) - * [`lsPackages.stream()`](#ls-packages-stream) - * [`lsCollaborators()`](#ls-collaborators) - * [`lsCollaborators.stream()`](#ls-collaborators-stream) - -### Install - -`$ npm install libnpmaccess` - ### API -#### `opts` for `libnpmaccess` commands +#### `opts` for all `libnpmaccess` commands `libnpmaccess` uses [`npm-registry-fetch`](https://npm.im/npm-registry-fetch). -All options are passed through directly to that library, so please refer to [its -own `opts` + +All options are passed through directly to that library, so please refer +to [its own `opts` documentation](https://www.npmjs.com/package/npm-registry-fetch#fetch-options) for options that can be passed in. -A couple of options of note for those in a hurry: - -* `opts.token` - can be passed in and will be used as the authentication token for the registry. For other ways to pass in auth details, see the n-r-f docs. -* `opts.otp` - certain operations will require an OTP token to be passed in. If a `libnpmaccess` command fails with `err.code === EOTP`, please retry the request with `{otp: <2fa token>}` - -#### `> access.public(spec, [opts]) -> Promise` +#### `spec` parameter for all `libnpmaccess` commands `spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible registry spec. -Makes package described by `spec` public. - -##### Example - -```javascript -await access.public('@foo/bar', {token: 'myregistrytoken'}) -// `@foo/bar` is now public -``` - -#### `> access.restricted(spec, [opts]) -> Promise` - -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. - -Makes package described by `spec` private/restricted. - -##### Example +#### `access.getCollaborators(spec, opts) -> Promise` -```javascript -await access.restricted('@foo/bar', {token: 'myregistrytoken'}) -// `@foo/bar` is now private -``` +Gets collaborators for a given package -#### `> access.grant(spec, team, permissions, [opts]) -> Promise` +#### `access.getPackages(user|scope|team, opts) -> Promise` -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. `team` must be a fully-qualified team name, in the `scope:team` -format, with or without the `@` prefix, and the team must be a valid team within -that scope. `permissions` must be one of `'read-only'` or `'read-write'`. +Gets all packages for a given user, scope, or team. -Grants `read-only` or `read-write` permissions for a certain package to a team. +Teams should be in the format `scope:team` or `@scope:team` -##### Example +Users and scopes can be in the format `@scope` or `scope` -```javascript -await access.grant('@foo/bar', '@foo:myteam', 'read-write', { - token: 'myregistrytoken' -}) -// `@foo/bar` is now read/write enabled for the @foo:myteam team. -``` +#### `access.getVisibility(spec, opts) -> Promise` -#### `> access.revoke(spec, team, [opts]) -> Promise` +Gets the visibility of a given package -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. `team` must be a fully-qualified team name, in the `scope:team` -format, with or without the `@` prefix, and the team must be a valid team within -that scope. `permissions` must be one of `'read-only'` or `'read-write'`. +#### `access.removePermissions(team, spec, opts) -> Promise` -Removes access to a package from a certain team. +Removes the access for a given team to a package. -##### Example +Teams should be in the format `scope:team` or `@scope:team` -```javascript -await access.revoke('@foo/bar', '@foo:myteam', { - token: 'myregistrytoken' -}) -// @foo:myteam can no longer access `@foo/bar` -``` +#### `access.setAccess(package, access, opts) -> Promise` -#### `> access.tfaRequired(spec, [opts]) -> Promise` +Sets access level for package described by `spec`. -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. - -Makes it so publishing or managing a package requires using 2FA tokens to -complete operations. +The npm registry accepts the following `access` levels: -##### Example +`public`: package is public +`private`: package is private -```javascript -await access.tfaRequires('lodash', {token: 'myregistrytoken'}) -// Publishing or changing dist-tags on `lodash` now require OTP to be enabled. -``` +The npm registry also only allows scoped packages to have their access +level set. -#### `> access.tfaNotRequired(spec, [opts]) -> Promise` +#### access.setMfa(spec, level, opts) -> Promise` -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. +Sets the publishing mfa requirements for a given package. Level must be one of the +following -Disabled the package-level 2FA requirement for `spec`. Note that you will need -to pass in an `otp` token in `opts` in order to complete this operation. +`none`: mfa is not required to publish this package. +`publish`: mfa is required to publish this package, automation tokens +cannot be used to publish. +`automation`: mfa is required to publish this package, automation tokens +may also be used for publishing from continuous integration workflows. -##### Example +#### access.setPermissions(team, spec, permssions, opts) -> Promise` -```javascript -await access.tfaNotRequired('lodash', {otp: '123654', token: 'myregistrytoken'}) -// Publishing or editing dist-tags on `lodash` no longer requires OTP to be -// enabled. -``` +Sets permissions levels for a given team to a package. -#### `> access.lsPackages(entity, [opts]) -> Promise` +Teams should be in the format `scope:team` or `@scope:team` -`entity` must be either a valid org or user name, or a fully-qualified team name -in the `scope:team` format, with or without the `@` prefix. +The npm registry accepts the following `permissions`: -Lists out packages a user, org, or team has access to, with corresponding -permissions. Packages that the access token does not have access to won't be -listed. - -In order to disambiguate between users and orgs, two requests may end up being -made when listing orgs or users. - -For a streamed version of these results, see -[`access.lsPackages.stream()`](#ls-package-stream). - -##### Example - -```javascript -await access.lsPackages('zkat', { - token: 'myregistrytoken' -}) -// Lists all packages `@zkat` has access to on the registry, and the -// corresponding permissions. -``` - -#### `> access.lsPackages.stream(scope, [team], [opts]) -> Stream` - -`entity` must be either a valid org or user name, or a fully-qualified team name -in the `scope:team` format, with or without the `@` prefix. - -Streams out packages a user, org, or team has access to, with corresponding -permissions, with each stream entry being formatted like `[packageName, -permissions]`. Packages that the access token does not have access to won't be -listed. - -In order to disambiguate between users and orgs, two requests may end up being -made when listing orgs or users. - -The returned stream is a valid `asyncIterator`. - -##### Example - -```javascript -for await (let [pkg, perm] of access.lsPackages.stream('zkat')) { - console.log('zkat has', perm, 'access to', pkg) -} -// zkat has read-write access to eggplant -// zkat has read-only access to @npmcorp/secret -``` - -#### `> access.lsCollaborators(spec, [user], [opts]) -> Promise` - -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. `user` must be a valid user name, with or without the `@` -prefix. - -Lists out access privileges for a certain package. Will only show permissions -for packages to which you have at least read access. If `user` is passed in, the -list is filtered only to teams _that_ user happens to belong to. - -For a streamed version of these results, see [`access.lsCollaborators.stream()`](#ls-collaborators-stream). - -##### Example - -```javascript -await access.lsCollaborators('@npm/foo', 'zkat', { - token: 'myregistrytoken' -}) -// Lists all teams with access to @npm/foo that @zkat belongs to. -``` - -#### `> access.lsCollaborators.stream(spec, [user], [opts]) -> Stream` - -`spec` must be an [`npm-package-arg`](https://npm.im/npm-package-arg)-compatible -registry spec. `user` must be a valid user name, with or without the `@` -prefix. - -Stream out access privileges for a certain package, with each entry in `[user, -permissions]` format. Will only show permissions for packages to which you have -at least read access. If `user` is passed in, the list is filtered only to teams -_that_ user happens to belong to. - -The returned stream is a valid `asyncIterator`. - -##### Example - -```javascript -for await (let [usr, perm] of access.lsCollaborators.stream('npm')) { - console.log(usr, 'has', perm, 'access to npm') -} -// zkat has read-write access to npm -// iarna has read-write access to npm -``` +`read-only`: Read only permissions +`read-write`: Read and write (aka publish) permissions diff --git a/workspaces/libnpmaccess/lib/index.js b/workspaces/libnpmaccess/lib/index.js index 71219d0098cfe..fca0e47279bfb 100644 --- a/workspaces/libnpmaccess/lib/index.js +++ b/workspaces/libnpmaccess/lib/index.js @@ -1,186 +1,140 @@ 'use strict' -const Minipass = require('minipass') const npa = require('npm-package-arg') const npmFetch = require('npm-registry-fetch') -const validate = require('aproba') -const eu = encodeURIComponent -const npar = spec => { +const npar = (spec) => { spec = npa(spec) if (!spec.registry) { - throw new Error('`spec` must be a registry spec') + throw new Error('must use package name only') } return spec } -const mapJSON = (value, [key]) => { - if (value === 'read') { - return [key, 'read-only'] - } else if (value === 'write') { - return [key, 'read-write'] - } else { - return [key, value] + +const parseTeam = (scopeTeam) => { + let slice = 0 + if (scopeTeam.startsWith('@')) { + slice = 1 } + const [scope, team] = scopeTeam.slice(slice).split(':').map(encodeURIComponent) + return { scope, team } } -const cmd = module.exports = {} +const getPackages = async (scopeTeam, opts) => { + const { scope, team } = parseTeam(scopeTeam) -cmd.public = (spec, opts) => setAccess(spec, 'public', opts) -cmd.restricted = (spec, opts) => setAccess(spec, 'restricted', opts) -function setAccess (spec, access, opts = {}) { - return Promise.resolve().then(() => { - spec = npar(spec) - validate('OSO', [spec, access, opts]) - const uri = `/-/package/${eu(spec.name)}/access` - return npmFetch(uri, { - ...opts, - method: 'POST', - body: { access }, - spec, - }).then(() => true) - }) -} - -cmd.grant = (spec, entity, permissions, opts = {}) => { - return Promise.resolve().then(() => { - spec = npar(spec) - const { scope, team } = splitEntity(entity) - validate('OSSSO', [spec, scope, team, permissions, opts]) - if (permissions !== 'read-write' && permissions !== 'read-only') { - throw new Error( - '`permissions` must be `read-write` or `read-only`. Got `' - + permissions + '` instead') + let uri + if (team) { + uri = `/-/team/${scope}/${team}/package` + } else { + uri = `/-/org/${scope}/package` + } + try { + return await npmFetch.json(uri, opts) + } catch (err) { + if (err.code === 'E404') { + uri = `/-/user/${scope}/package` + return npmFetch.json(uri, opts) } - const uri = `/-/team/${eu(scope)}/${eu(team)}/package` - return npmFetch(uri, { - ...opts, - method: 'PUT', - body: { package: spec.name, permissions }, - scope, - spec, - ignoreBody: true, - }) - .then(() => true) - }) + throw err + } } -cmd.revoke = (spec, entity, opts = {}) => { - return Promise.resolve().then(() => { - spec = npar(spec) - const { scope, team } = splitEntity(entity) - validate('OSSO', [spec, scope, team, opts]) - const uri = `/-/team/${eu(scope)}/${eu(team)}/package` - return npmFetch(uri, { - ...opts, - method: 'DELETE', - body: { package: spec.name }, - scope, - spec, - ignoreBody: true, - }) - .then(() => true) - }) +const getCollaborators = async (pkg, opts) => { + const spec = npar(pkg) + const uri = `/-/package/${spec.escapedName}/collaborators` + return npmFetch.json(uri, opts) } -cmd.lsPackages = (entity, opts) => { - return cmd.lsPackages.stream(entity, opts) - .collect() - .then(data => { - return data.reduce((acc, [key, val]) => { - if (!acc) { - acc = {} - } - acc[key] = val - return acc - }, null) - }) +const getVisibility = async (pkg, opts) => { + const spec = npar(pkg) + const uri = `/-/package/${spec.escapedName}/visibility` + return npmFetch.json(uri, opts) } -cmd.lsPackages.stream = (entity, opts = {}) => { - validate('SO|SZ', [entity, opts]) - const { scope, team } = splitEntity(entity) - let uri - if (team) { - uri = `/-/team/${eu(scope)}/${eu(team)}/package` - } else { - uri = `/-/org/${eu(scope)}/package` - } - const nextOpts = { +const setAccess = async (pkg, access, opts) => { + const spec = npar(pkg) + const uri = `/-/package/${spec.escapedName}/access` + await npmFetch(uri, { ...opts, - query: { format: 'cli' }, - mapJSON, - } - const ret = new Minipass({ objectMode: true }) - npmFetch.json.stream(uri, '*', nextOpts) - .on('error', err => { - if (err.code === 'E404' && !team) { - uri = `/-/user/${eu(scope)}/package` - npmFetch.json.stream(uri, '*', nextOpts) - .on('error', streamErr => ret.emit('error', streamErr)) - .pipe(ret) - } else { - ret.emit('error', err) - } - }) - .pipe(ret) - return ret -} - -cmd.lsCollaborators = (spec, user, opts) => { - return Promise.resolve().then(() => { - return cmd.lsCollaborators.stream(spec, user, opts) - .collect() - .then(data => { - return data.reduce((acc, [key, val]) => { - if (!acc) { - acc = {} - } - acc[key] = val - return acc - }, null) - }) + method: 'POST', + body: { access }, + spec, + ignoreBody: true, }) + return true } -cmd.lsCollaborators.stream = (spec, user, opts) => { - if (typeof user === 'object' && !opts) { - opts = user - user = undefined - } else if (!opts) { - opts = {} +const setMfa = async (pkg, level, opts) => { + const spec = npar(pkg) + const body = {} + switch (level) { + case 'none': + body.publish_requires_tfa = false + break + case 'publish': + // tfa is required, automation tokens can not override tfa + body.publish_requires_tfa = true + body.automation_token_overrides_tfa = false + break + case 'automation': + // tfa is required, automation tokens can override tfa + body.publish_requires_tfa = true + body.automation_token_overrides_tfa = true + break + default: + throw new Error(`Invalid mfa setting ${level}`) } - spec = npar(spec) - validate('OSO|OZO', [spec, user, opts]) - const uri = `/-/package/${eu(spec.name)}/collaborators` - return npmFetch.json.stream(uri, '*', { + const uri = `/-/package/${spec.escapedName}/access` + await npmFetch(uri, { ...opts, - query: { format: 'cli', user: user || undefined }, - mapJSON, + method: 'POST', + body, + spec, + ignoreBody: true, }) + return true } -cmd.tfaRequired = (spec, opts) => setRequires2fa(spec, true, opts) -cmd.tfaNotRequired = (spec, opts) => setRequires2fa(spec, false, opts) -function setRequires2fa (spec, required, opts = {}) { - return Promise.resolve().then(() => { - spec = npar(spec) - validate('OBO', [spec, required, opts]) - const uri = `/-/package/${eu(spec.name)}/access` - return npmFetch(uri, { - ...opts, - method: 'POST', - body: { publish_requires_tfa: required }, - spec, - ignoreBody: true, - }).then(() => true) +const setPermissions = async (scopeTeam, pkg, permissions, opts) => { + const spec = npar(pkg) + const { scope, team } = parseTeam(scopeTeam) + if (!scope || !team) { + throw new Error('team must be in format `scope:team`') + } + const uri = `/-/team/${scope}/${team}/package` + await npmFetch(uri, { + ...opts, + method: 'PUT', + body: { package: spec.name, permissions }, + scope, + spec, + ignoreBody: true, }) + return true } -cmd.edit = () => { - throw new Error('Not implemented yet') +const removePermissions = async (scopeTeam, pkg, opts) => { + const spec = npar(pkg) + const { scope, team } = parseTeam(scopeTeam) + const uri = `/-/team/${scope}/${team}/package` + await npmFetch(uri, { + ...opts, + method: 'DELETE', + body: { package: spec.name }, + scope, + spec, + ignoreBody: true, + }) + return true } -function splitEntity (entity = '') { - const [, scope, team] = entity.match(/^@?([^:]+)(?::(.*))?$/) || [] - return { scope, team } +module.exports = { + getCollaborators, + getPackages, + getVisibility, + removePermissions, + setAccess, + setMfa, + setPermissions, } diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index d05156710256b..8e73fd2676dd9 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -29,8 +29,6 @@ "bugs": "https://github.com/npm/libnpmaccess/issues", "homepage": "https://npmjs.com/package/libnpmaccess", "dependencies": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", "npm-package-arg": "^9.0.1", "npm-registry-fetch": "^13.0.0" }, diff --git a/workspaces/libnpmaccess/test/index.js b/workspaces/libnpmaccess/test/index.js index 689788d5269f7..bf73c3c8c929f 100644 --- a/workspaces/libnpmaccess/test/index.js +++ b/workspaces/libnpmaccess/test/index.js @@ -10,353 +10,150 @@ const OPTS = { registry: REG, } -t.test('access public', async t => { - tnock(t, REG).post( - '/-/package/%40foo%2Fbar/access', { access: 'public' } - ).reply(200) - await t.resolves(access.public('@foo/bar', OPTS)) -}) - -t.test('access public - failure', async t => { - tnock(t, REG).post( - '/-/package/%40foo%2Fbar/access', { access: 'public' } - ).reply(418) - await t.rejects( - access.public('@foo/bar', OPTS), - { statusCode: 418 }, - 'fails with code from registry' - ) -}) - -t.test('access restricted', async t => { - tnock(t, REG).post( - '/-/package/%40foo%2Fbar/access', { access: 'restricted' } - ).reply(200) - await t.resolves(access.restricted('@foo/bar', OPTS)) -}) - -t.test('access restricted - failure', async t => { - tnock(t, REG).post( - '/-/package/%40foo%2Fbar/access', { access: 'restricted' } - ).reply(418) - await t.rejects( - access.restricted('@foo/bar', OPTS), - { statusCode: 418 }, - 'fails with code from registry') -}) - -t.test('access 2fa-required', async t => { - tnock(t, REG).post('/-/package/%40foo%2Fbar/access', { - publish_requires_tfa: true, - }).reply(200, { ok: true }) - await t.resolves(access.tfaRequired('@foo/bar', OPTS)) -}) - -t.test('access 2fa-not-required', async t => { - tnock(t, REG).post('/-/package/%40foo%2Fbar/access', { - publish_requires_tfa: false, - }).reply(200, { ok: true }) - await t.resolves(access.tfaNotRequired('@foo/bar', OPTS)) -}) - -t.test('access grant basic read-write', async t => { - tnock(t, REG).put('/-/team/myorg/myteam/package', { - package: '@foo/bar', - permissions: 'read-write', - }).reply(201) - await t.resolves(access.grant('@foo/bar', 'myorg:myteam', 'read-write', OPTS)) -}) - -t.test('access grant basic read-only', async t => { - tnock(t, REG).put('/-/team/myorg/myteam/package', { - package: '@foo/bar', - permissions: 'read-only', - }).reply(201) - await t.resolves(access.grant('@foo/bar', 'myorg:myteam', 'read-only', OPTS)) -}) - -t.test('access grant bad perm', async t => { - await t.rejects( - access.grant('@foo/bar', 'myorg:myteam', 'unknown', OPTS), - { message: /must be.*read-write.*read-only/ }, - 'only read-write and read-only are accepted' - ) -}) - -t.test('access grant no entity', async t => { - await t.rejects( - access.grant('@foo/bar', undefined, 'read-write', OPTS), - { message: /Expected string/ }, - 'passing undefined entity gives useful error' - ) -}) - -t.test('access grant basic unscoped', async t => { - tnock(t, REG).put('/-/team/myorg/myteam/package', { - package: 'bar', - permissions: 'read-write', - }).reply(201) - await t.resolves(access.grant('bar', 'myorg:myteam', 'read-write', OPTS)) -}) - -t.test('access grant no opts passed', async t => { - // NOTE: mocking real url, because no opts variable means `registry` value - // will be defauled to real registry url - tnock(t, 'https://registry.npmjs.org/') - .put('/-/team/myorg/myteam/package', { - package: 'bar', - permissions: 'read-write', - }) - .reply(201) - await t.resolves(access.grant('bar', 'myorg:myteam', 'read-write')) -}) - -t.test('access revoke basic', async t => { - tnock(t, REG).delete('/-/team/myorg/myteam/package', { - package: '@foo/bar', - }).reply(200) - await t.resolves(access.revoke('@foo/bar', 'myorg:myteam', OPTS)) -}) - -t.test('access revoke basic unscoped', async t => { - tnock(t, REG).delete('/-/team/myorg/myteam/package', { - package: 'bar', - }).reply(200, { accessChanged: true }) - await t.resolves(access.revoke('bar', 'myorg:myteam', OPTS)) -}) - -t.test('access revoke no opts passed', async t => { - // NOTE: mocking real url, because no opts variable means `registry` value - // will be defauled to real registry url - tnock(t, 'https://registry.npmjs.org/') - .delete('/-/team/myorg/myteam/package', { - package: 'bar', - }) - .reply(201) - await t.resolves(access.revoke('bar', 'myorg:myteam')) -}) - -t.test('ls-packages on team', async t => { - const serverPackages = { - '@foo/bar': 'write', - '@foo/util': 'read', - '@foo/other': 'shrödinger', - } - const clientPackages = { - '@foo/bar': 'read-write', - '@foo/util': 'read-only', - '@foo/other': 'shrödinger', - } - tnock(t, REG).get( - '/-/team/myorg/myteam/package?format=cli' - ).reply(200, serverPackages) - const data = await access.lsPackages('myorg:myteam', OPTS) - t.same(data, clientPackages, 'got client package info') -}) - -t.test('ls-packages on org', async t => { - const serverPackages = { - '@foo/bar': 'write', - '@foo/util': 'read', - '@foo/other': 'shrödinger', - } - const clientPackages = { - '@foo/bar': 'read-write', - '@foo/util': 'read-only', - '@foo/other': 'shrödinger', - } - tnock(t, REG).get( - '/-/org/myorg/package?format=cli' - ).reply(200, serverPackages) - const data = await access.lsPackages('myorg', OPTS) - t.same(data, clientPackages, 'got client package info') -}) - -t.test('ls-packages on user', async t => { - const serverPackages = { - '@foo/bar': 'write', - '@foo/util': 'read', - '@foo/other': 'shrödinger', - } - const clientPackages = { - '@foo/bar': 'read-write', - '@foo/util': 'read-only', - '@foo/other': 'shrödinger', - } - const srv = tnock(t, REG) - srv.get('/-/org/myuser/package?format=cli').reply(404, { error: 'not found' }) - srv.get('/-/user/myuser/package?format=cli').reply(200, serverPackages) - const data = await access.lsPackages('myuser', OPTS) - t.same(data, clientPackages, 'got client package info') -}) - -t.test('ls-packages error on team', async t => { - tnock(t, REG).get('/-/team/myorg/myteam/package?format=cli').reply(404) - await t.rejects( - access.lsPackages('myorg:myteam', OPTS), - { code: 'E404' }, - 'spit out 404 directly if team provided' - ) -}) - -t.test('ls-packages error on user', async t => { - const srv = tnock(t, REG) - srv.get('/-/org/myuser/package?format=cli').reply(404, { error: 'not found' }) - srv.get('/-/user/myuser/package?format=cli').reply(404, { error: 'not found' }) - await t.rejects( - access.lsPackages('myuser', OPTS), - { code: 'E404' }, - 'spit out 404 if both reqs fail' - ) -}) - -t.test('ls-packages bad response', async t => { - tnock(t, REG).get( - '/-/team/myorg/myteam/package?format=cli' - ).reply(200, JSON.stringify(null)) - const data = await access.lsPackages('myorg:myteam', OPTS) - t.same(data, null, 'succeeds with null') -}) - -t.test('ls-packages stream', async t => { - const serverPackages = { - '@foo/bar': 'write', - '@foo/util': 'read', - '@foo/other': 'shrödinger', - } - const clientPackages = [ - ['@foo/bar', 'read-write'], - ['@foo/util', 'read-only'], - ['@foo/other', 'shrödinger'], - ] - tnock(t, REG).get( - '/-/team/myorg/myteam/package?format=cli' - ).reply(200, serverPackages) - const data = await access.lsPackages.stream('myorg:myteam', OPTS).collect() - t.same(data, clientPackages, 'got streamed client package info') -}) - -t.test('ls-packages stream no opts', async t => { - const serverPackages = { - '@foo/bar': 'write', - '@foo/util': 'read', - '@foo/other': 'shrödinger', - } - const clientPackages = [ - ['@foo/bar', 'read-write'], - ['@foo/util', 'read-only'], - ['@foo/other', 'shrödinger'], - ] - // NOTE: mocking real url, because no opts variable means `registry` value - // will be defauled to real registry url - tnock(t, 'https://registry.npmjs.org/') - .get('/-/team/myorg/myteam/package?format=cli') - .reply(200, serverPackages) - const data = await access.lsPackages.stream('myorg:myteam').collect() - t.same(data, clientPackages, 'got streamed client package info') +t.test('getCollaborators', t => { + t.test('success', async t => { + const collaborators = { + 'npm:myteam': 'write', + 'npm:anotherteam': 'read', + 'npm:thirdteam': 'special-case', + } + tnock(t, REG).get('/-/package/@npmcli%2ftest-package/collaborators').reply(200, collaborators) + const data = await access.getCollaborators('@npmcli/test-package', OPTS) + t.same(data, collaborators) + }) + t.test('non registry package', async t => { + await t.rejects(access.getCollaborators('./local', OPTS), /package name only/) + }) + t.end() }) -t.test('ls-collaborators', async t => { - const serverCollaborators = { - 'myorg:myteam': 'write', - 'myorg:anotherteam': 'read', - 'myorg:thirdteam': 'special-case', +t.test('getPackages', t => { + const packages = { + '@npmcli/test-package': 'write', + '@npmcli/util': 'read', + '@npmcli/other': 'shrödinger', } - const clientCollaborators = { - 'myorg:myteam': 'read-write', - 'myorg:anotherteam': 'read-only', - 'myorg:thirdteam': 'special-case', - } - tnock(t, REG).get( - '/-/package/%40foo%2Fbar/collaborators?format=cli' - ).reply(200, serverCollaborators) - const data = await access.lsCollaborators('@foo/bar', OPTS) - t.same(data, clientCollaborators, 'got collaborators') + t.test('team', async t => { + tnock(t, REG).get('/-/team/npm/myteam/package').reply(200, packages) + const data = await access.getPackages('npm:myteam', OPTS) + t.same(data, packages) + }) + t.test('org', async t => { + tnock(t, REG).get('/-/org/npm/package').reply(200, packages) + const data = await access.getPackages('npm', OPTS) + t.same(data, packages) + }) + t.test('user', async t => { + tnock(t, REG).get('/-/org/testuser/package').reply(404, {}) + tnock(t, REG).get('/-/user/testuser/package').reply(200, packages) + const data = await access.getPackages('testuser', OPTS) + t.same(data, packages) + }) + t.test('registry error', async t => { + tnock(t, REG).get('/-/org/npm/package').reply(500, {}) + await t.rejects(access.getPackages('npm', OPTS), { code: 'E500' }) + }) + t.end() }) -t.test('ls-collaborators stream', async t => { - const serverCollaborators = { - 'myorg:myteam': 'write', - 'myorg:anotherteam': 'read', - 'myorg:thirdteam': 'special-case', - } - const clientCollaborators = [ - ['myorg:myteam', 'read-write'], - ['myorg:anotherteam', 'read-only'], - ['myorg:thirdteam', 'special-case'], - ] - tnock(t, REG).get( - '/-/package/%40foo%2Fbar/collaborators?format=cli' - ).reply(200, serverCollaborators) - const data = await access.lsCollaborators.stream('@foo/bar', OPTS).collect() - t.same(data, clientCollaborators, 'got collaborators') +t.test('getVisibility', t => { + t.test('success', async t => { + const visibility = { public: true } + tnock(t, REG).get('/-/package/@npmcli%2ftest-package/visibility').reply(200, visibility) + const data = await access.getVisibility('@npmcli/test-package', OPTS) + t.same(data, visibility) + }) + t.test('non registry package', async t => { + await t.rejects(access.getVisibility('./local', OPTS), /package name only/) + }) + t.end() }) -t.test('ls-collaborators w/scope', async t => { - const serverCollaborators = { - 'myorg:myteam': 'write', - 'myorg:anotherteam': 'read', - 'myorg:thirdteam': 'special-case', - } - const clientCollaborators = { - 'myorg:myteam': 'read-write', - 'myorg:anotherteam': 'read-only', - 'myorg:thirdteam': 'special-case', - } - tnock(t, REG).get( - '/-/package/%40foo%2Fbar/collaborators?format=cli&user=zkat' - ).reply(200, serverCollaborators) - const data = await access.lsCollaborators('@foo/bar', 'zkat', OPTS) - t.same(data, clientCollaborators, 'got collaborators') +t.test('removePermissions', t => { + t.test('success', async t => { + tnock(t, REG).delete('/-/team/npm/myteam/package', { + package: '@npmcli/test-package', + }).reply(200) + await t.resolves(access.removePermissions('npm:myteam', '@npmcli/test-package', OPTS)) + }) + t.test('non registry spec', async t => { + await t.rejects(access.removePermissions('npm:myteam', './local', OPTS), /package name only/) + }) + t.end() }) -t.test('ls-collaborators w/o scope', async t => { - const serverCollaborators = { - 'myorg:myteam': 'write', - 'myorg:anotherteam': 'read', - 'myorg:thirdteam': 'special-case', - } - const clientCollaborators = { - 'myorg:myteam': 'read-write', - 'myorg:anotherteam': 'read-only', - 'myorg:thirdteam': 'special-case', - } - tnock(t, REG).get( - '/-/package/bar/collaborators?format=cli&user=zkat' - ).reply(200, serverCollaborators) - const data = await access.lsCollaborators('bar', 'zkat', OPTS) - t.same(data, clientCollaborators, 'got collaborators') +t.test('setAccess', t => { + t.test('public', async t => { + tnock(t, REG).post( + '/-/package/@npmcli%2ftest-package/access', { access: 'public' } + ).reply(200) + await t.resolves(access.setAccess('@npmcli/test-package', 'public', OPTS)) + }) + t.test('restricted', async t => { + tnock(t, REG).post( + '/-/package/@npmcli%2ftest-package/access', { access: 'restricted' } + ).reply(200) + await t.resolves(access.setAccess('@npmcli/test-package', 'restricted', OPTS)) + }) + t.test('non registry package', async t => { + await t.rejects(access.setAccess('./local', 'public', OPTS), /package name only/) + }) + t.end() }) -t.test('ls-collaborators bad response', async t => { - tnock(t, REG).get( - '/-/package/%40foo%2Fbar/collaborators?format=cli' - ).reply(200, JSON.stringify(null)) - const data = await access.lsCollaborators('@foo/bar', null, OPTS) - t.same(data, null, 'succeeds with null') +t.test('setMfa', t => { + t.test('none', async t => { + tnock(t, REG).post('/-/package/@npmcli%2ftest-package/access', { + publish_requires_tfa: false, + }).reply(200) + await t.resolves(access.setMfa('@npmcli/test-package', 'none', OPTS)) + }) + t.test('publish', async t => { + tnock(t, REG).post('/-/package/@npmcli%2ftest-package/access', { + publish_requires_tfa: true, + automation_token_overrides_tfa: false, + }).reply(200) + await t.resolves(access.setMfa('@npmcli/test-package', 'publish', OPTS)) + }) + t.test('automation', async t => { + tnock(t, REG).post('/-/package/@npmcli%2ftest-package/access', { + publish_requires_tfa: true, + automation_token_overrides_tfa: true, + }).reply(200) + await t.resolves(access.setMfa('@npmcli/test-package', 'automation', OPTS)) + }) + t.test('invalid', async t => { + await t.rejects(access.setMfa('@npmcli/test-package', 'invalid', OPTS), /Invalid mfa setting/) + }) + t.test('non registry spec', async t => { + await t.rejects(access.setMfa('./local', 'none', OPTS, /package name only/)) + }) + t.end() }) -t.test('error on non-registry specs', async t => { - await t.rejects(access.public('githubusername/reponame'), - /spec.*must be a registry spec/, 'registry spec required') - await t.rejects(access.restricted('foo/bar'), - /spec.*must be a registry spec/, 'registry spec required') - await t.rejects(access.grant('foo/bar', 'myorg', 'myteam', 'read-only'), - /spec.*must be a registry spec/, 'registry spec required') - await t.rejects(access.revoke('foo/bar', 'myorg', 'myteam'), - /spec.*must be a registry spec/, 'registry spec required') - await t.rejects(access.lsCollaborators('foo/bar'), - /spec.*must be a registry spec/, 'registry spec required') - await t.rejects(access.tfaRequired('foo/bar'), - /spec.*must be a registry spec/, 'registry spec required') - await t.rejects(access.tfaNotRequired('foo/bar'), - /spec.*must be a registry spec/, 'registry spec required') -}) +t.test('setPermissions', t => { + t.test('scope:team read-only', async t => { + tnock(t, REG).put('/-/team/npmcli/myteam/package', { + package: '@npmcli/test-package', + permissions: 'read-only', + }).reply(201) + await t.resolves( + access.setPermissions('npmcli:myteam', '@npmcli/test-package', 'read-only', OPTS) + ) + }) + t.test('scope only', async t => { + await t.rejects( + access.setPermissions('npmcli', '@npmcli/test-package', 'read-only', OPTS), + /scope:team/ + ) + }) + + t.test('no scope or team', async t => { + await t.rejects( + access.setPermissions('@:myteam', '@npmcli/test-package', 'read-only', OPTS), + /scope:team/ + ) + }) -t.test('edit', t => { - t.equal(typeof access.edit, 'function', 'access.edit exists') - t.throws(() => { - access.edit() - }, /Not implemented/, 'directly throws NIY message') t.end() }) From 9c32c6c8d6fc5bdfd6af685731fe26920d7e5446 Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 31 Aug 2022 08:37:26 -0700 Subject: [PATCH 03/40] feat(rewrite): rewrite `npm access` BREAKING CHANGE: renames most of the `npm access` subcommands - `edit`, having never been implemented, is removed - `public` is now `set status=public` - `restricted` is now `set status=private` - `ls-packages` is now `list packages` - `ls-collaborators` is now `list collaborators` - `2fa-required` is now `set mfa=publish` - `2fa-not-required` is now `set mfa=none` - `set mfa=automation` is added - output is no longer in json by default Usage: npm access list packages [|| [] npm access list collaborators [ []] npm access get status [] npm access set status=public|private [] npm access set mfa=false|publish|automation [] npm access grant [] npm access revoke [] Options: [--json] [--otp ] [--registry ] --- docs/content/commands/npm-access.md | 35 +- lib/commands/access.js | 284 ++++---- lib/commands/deprecate.js | 4 +- lib/commands/unpublish.js | 4 +- .../test/lib/commands/completion.js.test.cjs | 16 +- .../test/lib/load-all-commands.js.test.cjs | 14 +- tap-snapshots/test/lib/npm.js.test.cjs | 14 +- test/fixtures/mock-registry.js | 39 +- test/lib/commands/access.js | 659 ++++++++---------- test/lib/commands/deprecate.js | 9 +- test/lib/commands/unpublish.js | 43 +- 11 files changed, 517 insertions(+), 604 deletions(-) diff --git a/docs/content/commands/npm-access.md b/docs/content/commands/npm-access.md index f7a98af654714..bc481eac16336 100644 --- a/docs/content/commands/npm-access.md +++ b/docs/content/commands/npm-access.md @@ -11,15 +11,13 @@ description: Set access level on published packages ```bash -npm access public [] -npm access restricted [] +npm access list packages [|| [] +npm access list collaborators [ []] +npm access get status [] +npm access set status=public|private [] +npm access set mfa=none|publish|automation [] npm access grant [] npm access revoke [] -npm access 2fa-required [] -npm access 2fa-not-required [] -npm access ls-packages [||] -npm access ls-collaborators [ []] -npm access edit [] ``` @@ -91,12 +89,17 @@ Management of teams and team memberships is done with the `npm team` command. -#### `registry` +#### `json` -* Default: "https://registry.npmjs.org/" -* Type: URL +* Default: false +* Type: Boolean -The base URL of the npm registry. +Whether or not to output JSON data, rather than the normal output. + +* In `npm pkg set` it enables parsing set values with JSON.parse() before + saving them to your `package.json`. + +Not supported by all npm commands. @@ -115,6 +118,16 @@ password, npm will prompt on the command line for one. +#### `registry` + +* Default: "https://registry.npmjs.org/" +* Type: URL + +The base URL of the npm registry. + + + + ### See Also diff --git a/lib/commands/access.js b/lib/commands/access.js index 3621861537171..d5ac5bb2f008e 100644 --- a/lib/commands/access.js +++ b/lib/commands/access.js @@ -1,223 +1,221 @@ const path = require('path') -const libaccess = require('libnpmaccess') +const libnpmaccess = require('libnpmaccess') +const npa = require('npm-package-arg') const readPackageJson = require('read-package-json-fast') +const localeCompare = require('@isaacs/string-locale-compare')('en') const otplease = require('../utils/otplease.js') const getIdentity = require('../utils/get-identity.js') -const log = require('../utils/log-shim.js') const BaseCommand = require('../base-command.js') -const subcommands = [ - 'public', - 'restricted', +const commands = [ + 'get', 'grant', + 'list', 'revoke', - 'ls-packages', - 'ls-collaborators', - 'edit', - '2fa-required', - '2fa-not-required', + 'set', ] -const deprecated = [ - '2fa-not-required', - '2fa-required', - 'ls-collaborators', - 'ls-packages', - 'public', - 'restricted', +const setCommands = [ + 'status=public', + 'status=private', + 'mfa=none', + 'mfa=publish', + 'mfa=automation', + '2fa=none', + '2fa=publish', + '2fa=automation', ] class Access extends BaseCommand { static description = 'Set access level on published packages' static name = 'access' static params = [ - 'registry', + 'json', 'otp', + 'registry', ] static ignoreImplicitWorkspace = true static usage = [ - 'public []', - 'restricted []', + 'list packages [|| []', + 'list collaborators [ []]', + 'get status []', + 'set status=public|private []', + 'set mfa=none|publish|automation []', 'grant []', 'revoke []', - '2fa-required []', - '2fa-not-required []', - 'ls-packages [||]', - 'ls-collaborators [ []]', - 'edit []', ] async completion (opts) { const argv = opts.conf.argv.remain if (argv.length === 2) { - return subcommands + return commands } switch (argv[2]) { case 'grant': - if (argv.length === 3) { - return ['read-only', 'read-write'] - } else { - return [] - } - - case 'public': - case 'restricted': - case 'ls-packages': - case 'ls-collaborators': - case 'edit': - case '2fa-required': - case '2fa-not-required': + return ['read-only', 'read-write'] case 'revoke': return [] + case 'list': + case 'ls': + return ['packages', 'collaborators'] + case 'get': + return ['status'] + case 'set': + return setCommands default: throw new Error(argv[2] + ' not recognized') } } - async exec ([cmd, ...args]) { + async exec ([cmd, subcmd, ...args]) { if (!cmd) { - throw this.usageError('Subcommand is required.') + throw this.usageError() } - - if (!subcommands.includes(cmd) || !this[cmd]) { - throw this.usageError(`${cmd} is not a recognized subcommand.`) + if (!commands.includes(cmd)) { + throw this.usageError(`${cmd} is not a valid access command`) } - - if (deprecated.includes(cmd)) { - log.warn('access', `${cmd} subcommand will be removed in the next version of npm`) + // All commands take at least one more parameter so we can do this check up front + if (!subcmd) { + throw this.usageError() } - return this[cmd](args, { - ...this.npm.flatOptions, - }) - } - - public ([pkg], opts) { - return this.modifyPackage(pkg, opts, libaccess.public) - } - - restricted ([pkg], opts) { - return this.modifyPackage(pkg, opts, libaccess.restricted) - } - - async grant ([perms, scopeteam, pkg], opts) { - if (!perms || (perms !== 'read-only' && perms !== 'read-write')) { - throw this.usageError('First argument must be either `read-only` or `read-write`.') - } - - if (!scopeteam) { - throw this.usageError('`` argument is required.') - } - - const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || [] - - if (!scope && !team) { - throw this.usageError( - 'Second argument used incorrect format.\n' + - 'Example: @example:developers' - ) - } - - return this.modifyPackage(pkg, opts, (pkgName, opts) => - libaccess.grant(pkgName, scopeteam, perms, opts), false) - } - - async revoke ([scopeteam, pkg], opts) { - if (!scopeteam) { - throw this.usageError('`` argument is required.') - } - - const [, scope, team] = scopeteam.match(/^@?([^:]+):(.*)$/) || [] - - if (!scope || !team) { - throw this.usageError( - 'First argument used incorrect format.\n' + - 'Example: @example:developers' - ) + switch (cmd) { + case 'grant': + if (!['read-only', 'read-write'].includes(subcmd)) { + throw this.usageError('grant must be either `read-only` or `read-write`') + } + if (!args[0]) { + throw this.usageError('`` argument is required') + } + return this.#grant(subcmd, args[0], args[1]) + case 'revoke': + return this.#revoke(subcmd, args[0]) + case 'list': + case 'ls': + if (subcmd === 'packages') { + return this.#listPackages(args[0], args[1]) + } + if (subcmd === 'collaborators') { + return this.#listCollaborators(args[0], args[1]) + } + throw this.usageError(`list ${subcmd} is not a valid access command`) + case 'get': + if (subcmd !== 'status') { + throw this.usageError(`get ${subcmd} is not a valid access command`) + } + return this.#getStatus(args[0]) + case 'set': + if (!setCommands.includes(subcmd)) { + throw this.usageError(`set ${subcmd} is not a valid access command`) + } + return this.#set(subcmd, args[0]) } - - return this.modifyPackage(pkg, opts, (pkgName, opts) => - libaccess.revoke(pkgName, scopeteam, opts)) - } - - get ['2fa-required'] () { - return this.tfaRequired - } - - tfaRequired ([pkg], opts) { - return this.modifyPackage(pkg, opts, libaccess.tfaRequired, false) } - get ['2fa-not-required'] () { - return this.tfaNotRequired + async #grant (permissions, scope, pkg) { + await libnpmaccess.setPermissions(scope, pkg, permissions) } - tfaNotRequired ([pkg], opts) { - return this.modifyPackage(pkg, opts, libaccess.tfaNotRequired, false) + async #revoke (scope, pkg) { + await libnpmaccess.removePermissions(scope, pkg) } - get ['ls-packages'] () { - return this.lsPackages - } - - async lsPackages ([owner], opts) { + async #listPackages (owner, pkg) { if (!owner) { - owner = await getIdentity(this.npm, opts) + owner = await getIdentity(this.npm, this.npm.flatOptions) } - - const pkgs = await libaccess.lsPackages(owner, opts) - - // TODO - print these out nicely (breaking change) - this.npm.output(JSON.stringify(pkgs, null, 2)) + const pkgs = await libnpmaccess.getPackages(owner, this.npm.flatOptions) + this.#output(pkgs, pkg) } - get ['ls-collaborators'] () { - return this.lsCollaborators + async #listCollaborators (pkg, user) { + const pkgName = await this.#getPackage(pkg, false) + const collabs = await libnpmaccess.getCollaborators(pkgName, this.npm.flatOptions) + this.#output(collabs, user) } - async lsCollaborators ([pkg, usr], opts) { - const pkgName = await this.getPackage(pkg, false) - const collabs = await libaccess.lsCollaborators(pkgName, usr, opts) + async #getStatus (pkg) { + const pkgName = await this.#getPackage(pkg, false) + const visibility = await libnpmaccess.getVisibility(pkgName, this.npm.flatOptions) + this.#output({ [pkgName]: visibility.public ? 'public' : 'private' }) + } - // TODO - print these out nicely (breaking change) - this.npm.output(JSON.stringify(collabs, null, 2)) + async #set (subcmd, pkg) { + const [subkey, subval] = subcmd.split('=') + switch (subkey) { + case 'mfa': + case '2fa': + return this.#setMfa(pkg, subval) + case 'status': + return this.#setStatus(pkg, subval) + } } - async edit () { - throw new Error('edit subcommand is not implemented') + async #setMfa (pkg, level) { + const pkgName = await this.#getPackage(pkg, false) + await otplease(this.npm, this.npm.flatOptions, (opts) => { + return libnpmaccess.setMfa(pkgName, level, opts) + }) } - modifyPackage (pkg, opts, fn, requireScope = true) { - return this.getPackage(pkg, requireScope) - .then(pkgName => otplease(this.npm, opts, opts => fn(pkgName, opts))) + async #setStatus (pkg, status) { + // only scoped packages can have their access changed + const pkgName = await this.#getPackage(pkg, true) + if (status === 'private') { + status = 'restricted' + } + await otplease(this.npm, this.npm.flatOptions, (opts) => { + return libnpmaccess.setAccess(pkgName, status, opts) + }) + return this.#getStatus(pkgName) } - async getPackage (name, requireScope) { - if (name && name.trim()) { - return name.trim() - } else { + async #getPackage (name, requireScope) { + if (!name) { try { const pkg = await readPackageJson(path.resolve(this.npm.prefix, 'package.json')) name = pkg.name } catch (err) { if (err.code === 'ENOENT') { - throw new Error( - 'no package name passed to command and no package.json found' - ) + throw Object.assign(new Error('no package name given and no package.json found'), { + code: 'ENOENT', + }) } else { throw err } } + } - if (requireScope && !name.match(/^@[^/]+\/.*$/)) { - throw this.usageError('This command is only available for scoped packages.') - } else { - return name + const spec = npa(name) + if (requireScope && !spec.scope) { + throw this.usageError('This command is only available for scoped packages.') + } + return name + } + + #output (items, limiter) { + const output = {} + const lookup = { + __proto__: null, + read: 'read-only', + write: 'read-write', + } + for (const item in items) { + const val = items[item] + output[item] = lookup[val] || val + } + if (this.npm.config.get('json')) { + this.npm.output(JSON.stringify(output, null, 2)) + } else { + for (const item of Object.keys(output).sort(localeCompare)) { + if (!limiter || limiter === item) { + this.npm.output(`${item}: ${output[item]}`) + } } } } diff --git a/lib/commands/deprecate.js b/lib/commands/deprecate.js index 068bfdbcec717..c41546eb1b85e 100644 --- a/lib/commands/deprecate.js +++ b/lib/commands/deprecate.js @@ -23,10 +23,10 @@ class Deprecate extends BaseCommand { } const username = await getIdentity(this.npm, this.npm.flatOptions) - const packages = await libaccess.lsPackages(username, this.npm.flatOptions) + const packages = await libaccess.getPackages(username, this.npm.flatOptions) return Object.keys(packages) .filter((name) => - packages[name] === 'read-write' && + packages[name] === 'write' && (opts.conf.argv.remain.length === 0 || name.startsWith(opts.conf.argv.remain[0]))) } diff --git a/lib/commands/unpublish.js b/lib/commands/unpublish.js index 0e5ef3dc5e91d..968bcf8018958 100644 --- a/lib/commands/unpublish.js +++ b/lib/commands/unpublish.js @@ -42,11 +42,11 @@ class Unpublish extends BaseCommand { return [] } - const access = await libaccess.lsPackages(username, opts) + const access = await libaccess.getPackages(username, opts) // do a bit of filtering at this point, so that we don't need // to fetch versions for more than one thing, but also don't // accidentally unpublish a whole project - let pkgs = Object.keys(access || {}) + let pkgs = Object.keys(access) if (!partialWord || !pkgs.length) { return pkgs } diff --git a/tap-snapshots/test/lib/commands/completion.js.test.cjs b/tap-snapshots/test/lib/commands/completion.js.test.cjs index fb4c53a0205fb..85a883bd58b26 100644 --- a/tap-snapshots/test/lib/commands/completion.js.test.cjs +++ b/tap-snapshots/test/lib/commands/completion.js.test.cjs @@ -172,11 +172,7 @@ Array [ ` exports[`test/lib/commands/completion.js TAP completion filtered subcommands > filtered subcommands 1`] = ` -Array [ - Array [ - "public", - ], -] +Array [] ` exports[`test/lib/commands/completion.js TAP completion flags > flags 1`] = ` @@ -220,15 +216,11 @@ exports[`test/lib/commands/completion.js TAP completion subcommand completion > Array [ Array [ String( - public - restricted + get grant + list revoke - ls-packages - ls-collaborators - edit - 2fa-required - 2fa-not-required + set ), ], ] diff --git a/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/tap-snapshots/test/lib/load-all-commands.js.test.cjs index d4a340431792a..038121be95435 100644 --- a/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -9,18 +9,16 @@ exports[`test/lib/load-all-commands.js TAP load each command access > must match Set access level on published packages Usage: -npm access public [] -npm access restricted [] +npm access list packages [|| [] +npm access list collaborators [ []] +npm access get status [] +npm access set status=public|private [] +npm access set mfa=none|publish|automation [] npm access grant [] npm access revoke [] -npm access 2fa-required [] -npm access 2fa-not-required [] -npm access ls-packages [||] -npm access ls-collaborators [ []] -npm access edit [] Options: -[--registry ] [--otp ] +[--json] [--otp ] [--registry ] Run "npm help access" for more info ` diff --git a/tap-snapshots/test/lib/npm.js.test.cjs b/tap-snapshots/test/lib/npm.js.test.cjs index 68adb55516c72..1c3dbe39bd4ae 100644 --- a/tap-snapshots/test/lib/npm.js.test.cjs +++ b/tap-snapshots/test/lib/npm.js.test.cjs @@ -168,18 +168,16 @@ All commands: access Set access level on published packages Usage: - npm access public [] - npm access restricted [] + npm access list packages [|| [] + npm access list collaborators [ []] + npm access get status [] + npm access set status=public|private [] + npm access set mfa=none|publish|automation [] npm access grant [] npm access revoke [] - npm access 2fa-required [] - npm access 2fa-not-required [] - npm access ls-packages [||] - npm access ls-collaborators [ []] - npm access edit [] Options: - [--registry ] [--otp ] + [--json] [--otp ] [--registry ] Run "npm help access" for more info diff --git a/test/fixtures/mock-registry.js b/test/fixtures/mock-registry.js index 8fb5a055ff2d7..65d4759627aa6 100644 --- a/test/fixtures/mock-registry.js +++ b/test/fixtures/mock-registry.js @@ -67,21 +67,19 @@ class MockRegistry { } } - access ({ spec, access, publishRequires2fa }) { - const body = {} - if (access !== undefined) { - body.access = access - } - if (publishRequires2fa !== undefined) { - body.publish_requires_tfa = publishRequires2fa - } + setAccess ({ spec, body = {} }) { this.nock = this.nock.post( - `/-/package/${encodeURIComponent(spec)}/access`, + `/-/package/${npa(spec).escapedName}/access`, body ).reply(200) } - grant ({ spec, team, permissions }) { + getVisibility ({ spec, visibility }) { + this.nock = this.nock.get(`/-/package/${npa(spec).escapedName}/visibility`) + .reply(200, visibility) + } + + setPermissions ({ spec, team, permissions }) { if (team.startsWith('@')) { team = team.slice(1) } @@ -92,7 +90,7 @@ class MockRegistry { ).reply(200) } - revoke ({ spec, team }) { + removePermissions ({ spec, team }) { if (team.startsWith('@')) { team = team.slice(1) } @@ -141,27 +139,22 @@ class MockRegistry { } // team can be a team or a username - lsPackages ({ team, packages = {}, times = 1 }) { + getPackages ({ team, packages = {}, times = 1 }) { if (team.startsWith('@')) { team = team.slice(1) } - const [scope, teamName] = team.split(':') + const [scope, teamName] = team.split(':').map(encodeURIComponent) let uri if (teamName) { - uri = `/-/team/${encodeURIComponent(scope)}/${encodeURIComponent(teamName)}/package` + uri = `/-/team/${scope}/${teamName}/package` } else { - uri = `/-/org/${encodeURIComponent(scope)}/package` + uri = `/-/org/${scope}/package` } - this.nock = this.nock.get(uri).query({ format: 'cli' }).times(times).reply(200, packages) + this.nock = this.nock.get(uri).times(times).reply(200, packages) } - lsCollaborators ({ spec, user, collaborators = {} }) { - const query = { format: 'cli' } - if (user) { - query.user = user - } - this.nock = this.nock.get(`/-/package/${encodeURIComponent(spec)}/collaborators`) - .query(query) + getCollaborators ({ spec, collaborators = {} }) { + this.nock = this.nock.get(`/-/package/${npa(spec).escapedName}/collaborators`) .reply(200, collaborators) } diff --git a/test/lib/commands/access.js b/test/lib/commands/access.js index aa748b10681df..ae26f4c9332dc 100644 --- a/test/lib/commands/access.js +++ b/test/lib/commands/access.js @@ -3,6 +3,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') const MockRegistry = require('../../fixtures/mock-registry.js') +const token = 'test-auth-token' const auth = { '//registry.npmjs.org/:_authToken': 'test-auth-token' } t.test('completion', async t => { @@ -13,20 +14,21 @@ t.test('completion', async t => { t.resolves(res, expect, argv.join(' ')) } - testComp(['npm', 'access'], [ - 'public', 'restricted', 'grant', 'revoke', 'ls-packages', - 'ls-collaborators', 'edit', '2fa-required', '2fa-not-required', + testComp(['npm', 'access'], ['list', 'get', 'set', 'grant', 'revoke']) + testComp(['npm', 'access', 'list'], ['packages', 'collaborators']) + testComp(['npm', 'access', 'ls'], ['packages', 'collaborators']) + testComp(['npm', 'access', 'get'], ['status']) + testComp(['npm', 'access', 'set'], [ + 'status=public', + 'status=private', + 'mfa=none', + 'mfa=publish', + 'mfa=automation', + '2fa=none', + '2fa=publish', + '2fa=automation', ]) testComp(['npm', 'access', 'grant'], ['read-only', 'read-write']) - testComp(['npm', 'access', 'grant', 'read-only'], []) - testComp(['npm', 'access', 'public'], []) - testComp(['npm', 'access', 'restricted'], []) - testComp(['npm', 'access', 'revoke'], []) - testComp(['npm', 'access', 'ls-packages'], []) - testComp(['npm', 'access', 'ls-collaborators'], []) - testComp(['npm', 'access', 'edit'], []) - testComp(['npm', 'access', '2fa-required'], []) - testComp(['npm', 'access', '2fa-not-required'], []) testComp(['npm', 'access', 'revoke'], []) await t.rejects( @@ -35,406 +37,337 @@ t.test('completion', async t => { ) }) -t.test('subcommand required', async t => { +t.test('command required', async t => { const { npm } = await loadMockNpm(t) - const access = await npm.cmd('access') - await t.rejects( - npm.exec('access', []), - access.usageError('Subcommand is required.') - ) + await t.rejects(npm.exec('access', []), { code: 'EUSAGE' }) }) -t.test('unrecognized subcommand', async t => { +t.test('unrecognized command', async t => { const { npm } = await loadMockNpm(t) await t.rejects( - npm.exec('access', ['blerg']), - /blerg is not a recognized subcommand/, - 'should throw EUSAGE on missing subcommand' - ) + npm.exec('access', ['blerg']), { code: 'EUSAGE' }) }) -t.test('edit', async t => { +t.test('subcommand required', async t => { const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', ['edit', '@scoped/another']), - /edit subcommand is not implemented/, - 'should throw not implemented yet error' - ) + await t.rejects(npm.exec('access', ['get']), { code: 'EUSAGE' }) }) -t.test('access public on unscoped package', async t => { - const { npm } = await loadMockNpm(t, { - prefixDir: { - 'package.json': JSON.stringify({ - name: 'npm-access-public-pkg', - }), - }, - }) - await t.rejects( - npm.exec('access', ['public']), - /This command is only available for scoped packages/, - 'should throw scoped-restricted error' - ) +t.test('unrecognized subcommand', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects(npm.exec('access', ['list', 'blerg']), { code: 'EUSAGE' }) }) -t.test('access public on scoped package', async t => { - const name = '@scoped/npm-access-public-pkg' - const { npm, joinedOutput, logs } = await loadMockNpm(t, { - config: { - ...auth, - }, - prefixDir: { - 'package.json': JSON.stringify({ name }), - }, - }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', +t.test('grant', t => { + t.test('invalid permissions', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects(npm.exec('access', ['grant', 'other']), { code: 'EUSAGE' }) }) - registry.access({ spec: name, access: 'public' }) - await npm.exec('access', ['public']) - t.match(logs.warn[0], ['access', 'public subcommand will be removed in the next version of npm']) - t.equal(joinedOutput(), '') -}) -t.test('access public on missing package.json', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', ['public']), - /no package name passed to command and no package.json found/, - 'should throw no package.json found error' - ) -}) + t.test('no permissions', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects(npm.exec('access', ['grant', 'read-only']), { code: 'EUSAGE' }) + }) -t.test('access public on invalid package.json', async t => { - const { npm } = await loadMockNpm(t, { - prefixDir: { - 'package.json': '{\n', - node_modules: {}, - }, + t.test('read-only', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + const permissions = 'read-only' + registry.setPermissions({ spec: '@npmcli/test-package', team: '@npm:test-team', permissions }) + await npm.exec('access', ['grant', permissions, '@npm:test-team', '@npmcli/test-package']) }) - await t.rejects( - npm.exec('access', ['public']), - { code: 'EJSONPARSE' }, - 'should throw failed to parse package.json' - ) + t.end() }) -t.test('access restricted on unscoped package', async t => { - const { npm } = await loadMockNpm(t, { - prefixDir: { - 'package.json': JSON.stringify({ - name: 'npm-access-restricted-pkg', - }), - }, +t.test('revoke', t => { + t.test('success', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.removePermissions({ spec: '@npmcli/test-package', team: '@npm:test-team' }) + await npm.exec('access', ['revoke', '@npm:test-team', '@npmcli/test-package']) }) - await t.rejects( - npm.exec('access', ['public']), - /This command is only available for scoped packages/, - 'should throw scoped-restricted error' - ) + t.end() }) -t.test('access restricted on scoped package', async t => { - const name = '@scoped/npm-access-restricted-pkg' - const { npm, joinedOutput, logs } = await loadMockNpm(t, { - config: { - ...auth, - }, - prefixDir: { - 'package.json': JSON.stringify({ name }), - }, +t.test('list', t => { + const packages = { + '@npmcli/test-package': 'read', + '@npmcli/other-package': 'write', + } + const collaborators = { + npm: 'write', + github: 'read', + } + t.test('invalid subcommand', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects(npm.exec('access', ['list', 'other'], { code: 'EUSAGE' })) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + + t.test('packages explicit user', async t => { + const { npm, outputs } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getPackages({ team: '@npm:test-team', packages }) + await npm.exec('access', ['list', 'packages', '@npm:test-team']) + t.same(outputs, [ + ['@npmcli/other-package: read-write'], + ['@npmcli/test-package: read-only'], + ]) }) - registry.access({ spec: name, access: 'restricted' }) - await npm.exec('access', ['restricted']) - t.match(logs.warn[0], - ['access', 'restricted subcommand will be removed in the next version of npm'] - ) - t.equal(joinedOutput(), '') -}) -t.test('access restricted on missing package.json', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', ['restricted']), - /no package name passed to command and no package.json found/, - 'should throw no package.json found error' - ) -}) + t.test('packages infer user', async t => { + const { npm, outputs } = await loadMockNpm(t, { config: { ...auth } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: token, + }) + registry.whoami({ username: 'npm' }) + registry.getPackages({ team: 'npm', packages }) + await npm.exec('access', ['list', 'packages']) + t.same(outputs, [ + ['@npmcli/other-package: read-write'], + ['@npmcli/test-package: read-only'], + ]) + }) -t.test('access restricted on invalid package.json', async t => { - const { npm } = await loadMockNpm(t, { - prefixDir: { - 'package.json': '{\n', - node_modules: {}, - }, + t.test('packages json', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getPackages({ team: '@npm:test-team', packages }) + await npm.exec('access', ['list', 'packages', '@npm:test-team']) + t.same(JSON.parse(joinedOutput()), { + '@npmcli/test-package': 'read-only', + '@npmcli/other-package': 'read-write', + }) }) - await t.rejects( - npm.exec('access', ['restricted']), - { code: 'EJSONPARSE' }, - 'should throw failed to parse package.json' - ) -}) -t.test('access grant read-only', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - ...auth, - }, + t.test('collaborators explicit package', async t => { + const { npm, outputs } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getCollaborators({ spec: '@npmcli/test-package', collaborators }) + await npm.exec('access', ['list', 'collaborators', '@npmcli/test-package']) + t.same(outputs, [ + ['github: read-only'], + ['npm: read-write'], + ]) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + + t.test('collaborators user', async t => { + const { npm, outputs } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getCollaborators({ spec: '@npmcli/test-package', collaborators }) + await npm.exec('access', ['list', 'collaborators', '@npmcli/test-package', 'npm']) + t.same(outputs, [ + ['npm: read-write'], + ]) }) - registry.grant({ spec: '@scoped/another', team: 'myorg:myteam', permissions: 'read-only' }) - await npm.exec('access', ['grant', 'read-only', 'myorg:myteam', '@scoped/another']) - t.equal(joinedOutput(), '') + t.end() }) -t.test('access grant read-write', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - ...auth, - }, - }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', +t.test('get', t => { + t.test('invalid subcommand', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects(npm.exec('access', ['get', 'other'], { code: 'EUSAGE' })) }) - registry.grant({ spec: '@scoped/another', team: 'myorg:myteam', permissions: 'read-write' }) - await npm.exec('access', ['grant', 'read-write', 'myorg:myteam', '@scoped/another']) - t.equal(joinedOutput(), '') -}) -t.test('access grant current cwd', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - ...auth, - }, - prefixDir: { - 'package.json': JSON.stringify({ - name: 'yargs', - }), - }, + t.test('status explicit package', async t => { + const { npm, outputs } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getVisibility({ spec: '@npmcli/test-package', visibility: { public: true } }) + await npm.exec('access', ['get', 'status', '@npmcli/test-package']) + t.same(outputs, [['@npmcli/test-package: public']]) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('status implicit package', async t => { + const { npm, outputs } = await loadMockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ name: '@npmcli/test-package' }), + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getVisibility({ spec: '@npmcli/test-package', visibility: { public: true } }) + await npm.exec('access', ['get', 'status']) + t.same(outputs, [['@npmcli/test-package: public']]) }) - registry.grant({ spec: 'yargs', team: 'myorg:myteam', permissions: 'read-write' }) - await npm.exec('access', ['grant', 'read-write', 'myorg:myteam']) - t.equal(joinedOutput(), '') -}) - -t.test('access grant others', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', [ - 'grant', - 'rerere', - 'myorg:myteam', - '@scoped/another', - ]), - /First argument must be either `read-only` or `read-write`./, - 'should throw unrecognized argument error' - ) -}) - -t.test('access grant missing team args', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', [ - 'grant', - 'read-only', - undefined, - '@scoped/another', - ]), - /`` argument is required./, - 'should throw missing argument error' - ) -}) - -t.test('access grant malformed team arg', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', [ - 'grant', - 'read-only', - 'foo', - '@scoped/another', - ]), - /Second argument used incorrect format.\n/, - 'should throw malformed arg error' - ) -}) - -t.test('access 2fa-required', async t => { - const { npm, joinedOutput, logs } = await loadMockNpm(t, { - config: { - ...auth, - }, + t.test('status no package', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects( + npm.exec('access', ['get', 'status']), + { code: 'ENOENT' } + ) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('status invalid package', async t => { + const { npm } = await loadMockNpm(t, { + prefixDir: { 'package.json': '[not:valid_json}' }, + }) + await t.rejects( + npm.exec('access', ['get', 'status']), + { code: 'EJSONPARSE' } + ) }) - registry.access({ spec: '@scope/pkg', publishRequires2fa: true }) - await npm.exec('access', ['2fa-required', '@scope/pkg']) - t.match(logs.warn[0], - ['access', '2fa-required subcommand will be removed in the next version of npm'] - ) - t.equal(joinedOutput(), '') + t.test('status json', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { config: { json: true } }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.getVisibility({ spec: '@npmcli/test-package', visibility: { public: true } }) + await npm.exec('access', ['get', 'status', '@npmcli/test-package']) + t.same(JSON.parse(joinedOutput()), { '@npmcli/test-package': 'public' }) + }) + t.end() }) -t.test('access 2fa-not-required', async t => { - const { npm, joinedOutput, logs } = await loadMockNpm(t, { - config: { - ...auth, - }, +t.test('set', t => { + t.test('status=public', async t => { + const { npm, outputs } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', body: { access: 'public' } }) + registry.getVisibility({ spec: '@npmcli/test-package', visibility: { public: true } }) + await npm.exec('access', ['set', 'status=public', '@npmcli/test-package']) + t.same(outputs, [['@npmcli/test-package: public']]) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('status=private', async t => { + const { npm, outputs } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', body: { access: 'restricted' } }) + registry.getVisibility({ spec: '@npmcli/test-package', visibility: { public: false } }) + await npm.exec('access', ['set', 'status=private', '@npmcli/test-package']) + t.same(outputs, [['@npmcli/test-package: private']]) }) - registry.access({ spec: '@scope/pkg', publishRequires2fa: false }) - await npm.exec('access', ['2fa-not-required', '@scope/pkg']) - t.match(logs.warn[0], - ['access', '2fa-not-required subcommand will be removed in the next version of npm'] - ) - t.equal(joinedOutput(), '') -}) - -t.test('access revoke', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - ...auth, - }, + t.test('status=invalid', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects( + npm.exec('access', ['set', 'status=invalid', '@npmcli/test-package']), + { code: 'EUSAGE' } + ) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('status non scoped package', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects( + npm.exec('access', ['set', 'status=public', 'npm']), + { code: 'EUSAGE' } + ) }) - registry.revoke({ spec: '@scoped/another', team: 'myorg:myteam' }) - await npm.exec('access', ['revoke', 'myorg:myteam', '@scoped/another']) - t.equal(joinedOutput(), '') -}) - -t.test('access revoke missing team args', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', [ - 'revoke', - undefined, - '@scoped/another', - ]), - /`` argument is required./, - 'should throw missing argument error' - ) -}) - -t.test('access revoke malformed team arg', async t => { - const { npm } = await loadMockNpm(t) - await t.rejects( - npm.exec('access', [ - 'revoke', - 'foo', - '@scoped/another', - ]), - /First argument used incorrect format.\n/, - 'should throw malformed arg error' - ) -}) - -t.test('npm access ls-packages with no team', async t => { - const { npm, joinedOutput, logs } = await loadMockNpm(t, { - config: { - ...auth, - }, + t.test('mfa=none', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', + body: { + publish_requires_tfa: false, + } }) + await npm.exec('access', ['set', 'mfa=none', '@npmcli/test-package']) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('mfa=publish', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', + body: { + publish_requires_tfa: true, + automation_token_overrides_tfa: false, + } }) + await npm.exec('access', ['set', 'mfa=publish', '@npmcli/test-package']) }) - const team = 'foo' - const packages = { 'test-package': 'read-write' } - registry.whoami({ username: team }) - registry.lsPackages({ team, packages }) - await npm.exec('access', ['ls-packages']) - t.match(logs.warn[0], - ['access', 'ls-packages subcommand will be removed in the next version of npm'] - ) - t.match(JSON.parse(joinedOutput()), packages) -}) - -t.test('access ls-packages on team', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - ...auth, - }, + t.test('mfa=automation', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', + body: { + publish_requires_tfa: true, + automation_token_overrides_tfa: true, + } }) + await npm.exec('access', ['set', 'mfa=automation', '@npmcli/test-package']) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('mfa=invalid', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects( + npm.exec('access', ['set', 'mfa=invalid']), + { code: 'EUSAGE' } + ) }) - const team = 'myorg:myteam' - const packages = { 'test-package': 'read-write' } - registry.lsPackages({ team, packages }) - await npm.exec('access', ['ls-packages', 'myorg:myteam']) - t.match(JSON.parse(joinedOutput()), packages) -}) - -t.test('access ls-collaborators on current', async t => { - const { npm, joinedOutput, logs } = await loadMockNpm(t, { - config: { - ...auth, - }, - prefixDir: { - 'package.json': JSON.stringify({ - name: 'yargs', - }), - }, + t.test('2fa=none', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', + body: { + publish_requires_tfa: false, + } }) + await npm.exec('access', ['set', '2fa=none', '@npmcli/test-package']) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('2fa=publish', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', + body: { + publish_requires_tfa: true, + automation_token_overrides_tfa: false, + } }) + await npm.exec('access', ['set', '2fa=publish', '@npmcli/test-package']) }) - const collaborators = { 'test-user': 'read-write' } - registry.lsCollaborators({ spec: 'yargs', collaborators }) - await npm.exec('access', ['ls-collaborators']) - t.match(logs.warn[0], - ['access', 'ls-collaborators subcommand will be removed in the next version of npm'] - ) - t.match(JSON.parse(joinedOutput()), collaborators) -}) - -t.test('access ls-collaborators on spec', async t => { - const { npm, joinedOutput } = await loadMockNpm(t, { - config: { - ...auth, - }, + t.test('2fa=automation', async t => { + const { npm } = await loadMockNpm(t) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.setAccess({ spec: '@npmcli/test-package', + body: { + publish_requires_tfa: true, + automation_token_overrides_tfa: true, + } }) + await npm.exec('access', ['set', '2fa=automation', '@npmcli/test-package']) }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', + t.test('2fa=invalid', async t => { + const { npm } = await loadMockNpm(t) + await t.rejects( + npm.exec('access', ['set', '2fa=invalid']), + { code: 'EUSAGE' } + ) }) - const collaborators = { 'test-user': 'read-write' } - registry.lsCollaborators({ spec: 'yargs', collaborators }) - await npm.exec('access', ['ls-collaborators', 'yargs']) - t.match(JSON.parse(joinedOutput()), collaborators) + + t.end() }) diff --git a/test/lib/commands/deprecate.js b/test/lib/commands/deprecate.js index 3a610a703a2dc..57ed9c93ba0f4 100644 --- a/test/lib/commands/deprecate.js +++ b/test/lib/commands/deprecate.js @@ -32,7 +32,7 @@ t.test('completion', async t => { }) registry.whoami({ username: user, times: 4 }) - registry.lsPackages({ team: user, packages, times: 4 }) + registry.getPackages({ team: user, packages, times: 4 }) await Promise.all([ testComp([], ['foo', 'bar', 'baz']), testComp(['b'], ['bar', 'baz']), @@ -42,9 +42,12 @@ t.test('completion', async t => { await testComp(['foo', 'something'], []) - registry.whoami({ statusCode: 404, body: {} }) + registry.whoami({ responseCode: 401, body: {} }) - t.rejects(testComp([], []), { code: 'EINVALIDTYPE' }) + await t.rejects( + testComp([], []), + { code: 'E401' } + ) }) t.test('no args', async t => { diff --git a/test/lib/commands/unpublish.js b/test/lib/commands/unpublish.js index 28f93ea3e77a4..9efd2a147d42f 100644 --- a/test/lib/commands/unpublish.js +++ b/test/lib/commands/unpublish.js @@ -424,7 +424,7 @@ t.test('completion', async t => { }) await registry.package({ manifest, query: { write: true } }) registry.whoami({ username: user }) - registry.nock.get('/-/org/test-user/package?format=cli').reply(200, { [pkg]: 'write' }) + registry.getPackages({ team: user, packages: { [pkg]: 'write' } }) await testComp(t, { argv: ['npm', 'unpublish'], @@ -446,7 +446,7 @@ t.test('completion', async t => { manifest.versions = {} await registry.package({ manifest, query: { write: true } }) registry.whoami({ username: user }) - registry.nock.get('/-/org/test-user/package?format=cli').reply(200, { [pkg]: 'write' }) + registry.getPackages({ team: user, packages: { [pkg]: 'write' } }) await testComp(t, { argv: ['npm', 'unpublish'], @@ -465,11 +465,12 @@ t.test('completion', async t => { authorization: 'test-auth-token', }) registry.whoami({ username: user }) - registry.nock.get('/-/org/test-user/package?format=cli').reply(200, { - [pkg]: 'write', - [`${pkg}a`]: 'write', - [`${pkg}b`]: 'write', - }) + registry.getPackages({ team: user, + packages: { + [pkg]: 'write', + [`${pkg}a`]: 'write', + [`${pkg}b`]: 'write', + } }) await testComp(t, { argv: ['npm', 'unpublish'], @@ -489,7 +490,7 @@ t.test('completion', async t => { authorization: 'test-auth-token', }) registry.whoami({ username: user }) - registry.nock.get('/-/org/test-user/package?format=cli').reply(200, {}) + registry.getPackages({ team: user, packages: {} }) await testComp(t, { argv: ['npm', 'unpublish'], @@ -506,10 +507,11 @@ t.test('completion', async t => { authorization: 'test-auth-token', }) registry.whoami({ username: user }) - registry.nock.get('/-/org/test-user/package?format=cli').reply(200, { - [pkg]: 'write', - [`${pkg}a`]: 'write', - }) + registry.getPackages({ team: user, + packages: { + [pkg]: 'write', + [`${pkg}a`]: 'write', + } }) await testComp(t, { argv: ['npm', 'unpublish'], @@ -519,23 +521,6 @@ t.test('completion', async t => { }) }) - t.test('no pkg names retrieved from user account', async t => { - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - authorization: 'test-auth-token', - }) - registry.whoami({ username: user }) - registry.nock.get('/-/org/test-user/package?format=cli').reply(200, null) - - await testComp(t, { - argv: ['npm', 'unpublish'], - partialWord: pkg, - expect: [], - title: 'should have no autocomplete', - }) - }) - t.test('logged out user', async t => { const registry = new MockRegistry({ tap: t, From c3d75499cfd4e3601c6ca31621b2f693af466c4d Mon Sep 17 00:00:00 2001 From: Gar Date: Mon, 12 Sep 2022 09:03:31 -0700 Subject: [PATCH 04/40] fix: add tag to publish log message --- lib/commands/publish.js | 5 ++++- tap-snapshots/test/lib/commands/publish.js.test.cjs | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 3d17866a684a4..64b6dfc513c95 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -114,7 +114,10 @@ class Publish extends BaseCommand { } } - log.notice('', `Publishing to ${outputRegistry}${dryRun ? ' (dry-run)' : ''}`) + log.notice( + '', + `Publishing to ${outputRegistry} with tag ${defaultTag}${dryRun ? ' (dry-run)' : ''}` + ) if (!dryRun) { await otplease(this.npm, opts, opts => libpub(manifest, tarballData, opts)) diff --git a/tap-snapshots/test/lib/commands/publish.js.test.cjs b/tap-snapshots/test/lib/commands/publish.js.test.cjs index d85a1164e22bf..3b215960fa37e 100644 --- a/tap-snapshots/test/lib/commands/publish.js.test.cjs +++ b/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -51,7 +51,7 @@ Array [ ], Array [ "", - "Publishing to https://registry.npmjs.org/ (dry-run)", + "Publishing to https://registry.npmjs.org/ with tag latest (dry-run)", ], ] ` @@ -72,7 +72,7 @@ exports[`test/lib/commands/publish.js TAP json > must match snapshot 1`] = ` Array [ Array [ "", - "Publishing to https://registry.npmjs.org/", + "Publishing to https://registry.npmjs.org/ with tag latest", ], ] ` @@ -165,7 +165,7 @@ Array [ ], Array [ "", - "Publishing to https://registry.npmjs.org/", + "Publishing to https://registry.npmjs.org/ with tag latest", ], ] ` From 64801aac3e4349787e00794ee4c9fee513b23ee8 Mon Sep 17 00:00:00 2001 From: Gar Date: Mon, 12 Sep 2022 08:56:45 -0700 Subject: [PATCH 05/40] chore: remove postpublish template-oss got most of the other ones cause they lived in `prepublishOnly` but this one was in `postpublish` --- workspaces/libnpmaccess/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index 8e73fd2676dd9..21d31f18aa0f9 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -6,7 +6,6 @@ "license": "ISC", "main": "lib/index.js", "scripts": { - "postpublish": "git push origin --follow-tags", "lint": "eslint \"**/*.js\"", "test": "tap", "postlint": "template-oss-check", From 88fa2a07539282d919e289d9413d8e9465e21eff Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 14 Sep 2022 14:58:53 -0700 Subject: [PATCH 06/40] chore: remove reference to removed workspace-deps plugin --- release-please-config.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/release-please-config.json b/release-please-config.json index 87ff3b2cac37b..808e4a7a084de 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,8 +1,7 @@ { "bootstrap-sha": "141faf0c19eae382d0e19833129f5545fc2355c8", "plugins": [ - "node-workspace", - "workspace-deps" + "node-workspace" ], "changelog-sections": [ { From fd0eebe4c2b55dd69972aff7de1b4db14ea6799a Mon Sep 17 00:00:00 2001 From: Hugh Lilly Date: Tue, 6 Sep 2022 20:32:45 +1200 Subject: [PATCH 07/40] docs: update registry docs header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrects grammar (previously said `other’s`). --- docs/content/using-npm/registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/using-npm/registry.md b/docs/content/using-npm/registry.md index 4a265db03f079..fd7e44de48eba 100644 --- a/docs/content/using-npm/registry.md +++ b/docs/content/using-npm/registry.md @@ -69,7 +69,7 @@ to force it to be published only to your internal/private registry. See [`package.json`](/configuring-npm/package-json) for more info on what goes in the package.json file. -### Where can I find my own, & other's, published packages? +### Where can I find my (and others') published packages? From f3b0c438d5b62b267f36c21d7b9fa57ae9507ef5 Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 13 Sep 2022 09:52:29 -0700 Subject: [PATCH 08/40] fix: keep saveTypes separate for each `add` --- workspaces/arborist/lib/add-rm-pkg-deps.js | 23 +++++++++++---------- workspaces/arborist/test/add-rm-pkg-deps.js | 16 ++++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/workspaces/arborist/lib/add-rm-pkg-deps.js b/workspaces/arborist/lib/add-rm-pkg-deps.js index 7b43c38e2492b..59d5e32547c29 100644 --- a/workspaces/arborist/lib/add-rm-pkg-deps.js +++ b/workspaces/arborist/lib/add-rm-pkg-deps.js @@ -5,23 +5,24 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const add = ({ pkg, add, saveBundle, saveType }) => { for (const { name, rawSpec } of add) { + let addSaveType = saveType // if the user does not give us a type, we infer which type(s) // to keep based on the same order of priority we do when // building the tree as defined in the _loadDeps method of // the node class. - if (!saveType) { - saveType = inferSaveType(pkg, name) + if (!addSaveType) { + addSaveType = inferSaveType(pkg, name) } - if (saveType === 'prod') { + if (addSaveType === 'prod') { // a production dependency can only exist as production (rpj ensures it // doesn't coexist w/ optional) deleteSubKey(pkg, 'devDependencies', name, 'dependencies') deleteSubKey(pkg, 'peerDependencies', name, 'dependencies') - } else if (saveType === 'dev') { + } else if (addSaveType === 'dev') { // a dev dependency may co-exist as peer, or optional, but not production deleteSubKey(pkg, 'dependencies', name, 'devDependencies') - } else if (saveType === 'optional') { + } else if (addSaveType === 'optional') { // an optional dependency may co-exist as dev (rpj ensures it doesn't // coexist w/ prod) deleteSubKey(pkg, 'peerDependencies', name, 'optionalDependencies') @@ -31,23 +32,23 @@ const add = ({ pkg, add, saveBundle, saveType }) => { deleteSubKey(pkg, 'optionalDependencies', name, 'peerDependencies') } - const depType = saveTypeMap.get(saveType) + const depType = saveTypeMap.get(addSaveType) pkg[depType] = pkg[depType] || {} if (rawSpec !== '' || pkg[depType][name] === undefined) { pkg[depType][name] = rawSpec || '*' } - if (saveType === 'optional') { + if (addSaveType === 'optional') { // Affordance for previous npm versions that require this behaviour pkg.dependencies = pkg.dependencies || {} pkg.dependencies[name] = pkg.optionalDependencies[name] } - if (saveType === 'peer' || saveType === 'peerOptional') { + if (addSaveType === 'peer' || addSaveType === 'peerOptional') { const pdm = pkg.peerDependenciesMeta || {} - if (saveType === 'peer' && pdm[name] && pdm[name].optional) { + if (addSaveType === 'peer' && pdm[name] && pdm[name].optional) { pdm[name].optional = false - } else if (saveType === 'peerOptional') { + } else if (addSaveType === 'peerOptional') { pdm[name] = pdm[name] || {} pdm[name].optional = true pkg.peerDependenciesMeta = pdm @@ -59,7 +60,7 @@ const add = ({ pkg, add, saveBundle, saveType }) => { } } - if (saveBundle && saveType !== 'peer' && saveType !== 'peerOptional') { + if (saveBundle && addSaveType !== 'peer' && addSaveType !== 'peerOptional') { // keep it sorted, keep it unique const bd = new Set(pkg.bundleDependencies || []) bd.add(name) diff --git a/workspaces/arborist/test/add-rm-pkg-deps.js b/workspaces/arborist/test/add-rm-pkg-deps.js index 77ea2bd61e550..b15b9f96d74a3 100644 --- a/workspaces/arborist/test/add-rm-pkg-deps.js +++ b/workspaces/arborist/test/add-rm-pkg-deps.js @@ -17,6 +17,22 @@ t.test('add', t => { } process.on('log', log) t.teardown(() => process.off('log', log)) + t.strictSame(add({ + pkg: { + dependencies: { bar: '1' }, + devDependencies: { foo: '2' }, + }, + add: [ + foo1, + bar, + ], + path: '/', + }), { + dependencies: { bar: '1' }, + devDependencies: { foo: '1' }, + }, 'inferred save types stay the same for each dependency') + + t.strictSame(logs, []) t.strictSame(add({ pkg: { dependencies: { bar: '1' }, From 2d16b433dd4c7212338d2091ae386f2f39d0561f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 14 Sep 2022 23:10:49 +0000 Subject: [PATCH 09/40] chore: release 9.0.0-pre.1 --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 27 +++++++++++++++++++++++++++ package-lock.json | 2 +- package.json | 10 +++++----- workspaces/arborist/CHANGELOG.md | 6 ++++++ workspaces/arborist/package.json | 2 +- workspaces/libnpmaccess/CHANGELOG.md | 10 ++++++++++ workspaces/libnpmaccess/package.json | 2 +- workspaces/libnpmexec/CHANGELOG.md | 6 ++++++ workspaces/libnpmexec/package.json | 4 ++-- workspaces/libnpmfund/CHANGELOG.md | 6 ++++++ workspaces/libnpmfund/package.json | 4 ++-- 12 files changed, 72 insertions(+), 17 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index efdb054e92edd..78ed38ff80b5b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,10 +1,10 @@ { - ".": "9.0.0-pre.0", - "workspaces/arborist": "6.0.0-pre.0", - "workspaces/libnpmaccess": "7.0.0-pre.0", + ".": "9.0.0-pre.1", + "workspaces/arborist": "6.0.0-pre.1", + "workspaces/libnpmaccess": "7.0.0-pre.1", "workspaces/libnpmdiff": "5.0.0-pre.0", - "workspaces/libnpmexec": "5.0.0-pre.0", - "workspaces/libnpmfund": "4.0.0-pre.0", + "workspaces/libnpmexec": "5.0.0-pre.1", + "workspaces/libnpmfund": "4.0.0-pre.1", "workspaces/libnpmhook": "9.0.0-pre.0", "workspaces/libnpmorg": "5.0.0-pre.0", "workspaces/libnpmpack": "5.0.0-pre.0", diff --git a/CHANGELOG.md b/CHANGELOG.md index 66f68b44fcc11..855e602bc19d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## [9.0.0-pre.1](https://github.com/npm/cli/compare/v9.0.0-pre.0...v9.0.0-pre.1) (2022-09-14) + +### ⚠️ BREAKING CHANGES + +* renames most of the `npm access` subcommands +* the api for libnpmaccess is different now + +### Features + +* [`9c32c6c`](https://github.com/npm/cli/commit/9c32c6c8d6fc5bdfd6af685731fe26920d7e5446) rewrite: rewrite `npm access` (@wraithgar) +* [`854521b`](https://github.com/npm/cli/commit/854521baa49ef88ff9586ec2cc5f1fbaee7fa364) rewrite: Rewrite libnpmaccess (@wraithgar) + +### Bug Fixes + +* [`c3d7549`](https://github.com/npm/cli/commit/c3d75499cfd4e3601c6ca31621b2f693af466c4d) add tag to publish log message (@wraithgar) + +### Documentation + +* [`fd0eebe`](https://github.com/npm/cli/commit/fd0eebe4c2b55dd69972aff7de1b4db14ea6799a) update registry docs header (@hughlilly) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.0...arborist-v6.0.0-pre.1): `@npmcli/arborist@6.0.0-pre.1` +* [Workspace](https://github.com/npm/cli/compare/libnpmaccess-v7.0.0-pre.0...libnpmaccess-v7.0.0-pre.1): `libnpmaccess@7.0.0-pre.1` +* [Workspace](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.0...libnpmexec-v5.0.0-pre.1): `libnpmexec@5.0.0-pre.1` +* [Workspace](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.0...libnpmfund-v4.0.0-pre.1): `libnpmfund@4.0.0-pre.1` + ## [9.0.0-pre.0](https://github.com/npm/cli/compare/v8.19.1...v9.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/package-lock.json b/package-lock.json index e0a2304732744..9705d21a10cb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "npm", - "version": "9.0.0-pre.0", + "version": "9.0.0-pre.1", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 2ff60e51f9eba..048ec7ee9629b 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "9.0.0-pre.0", + "version": "9.0.0-pre.1", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -56,7 +56,7 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.0.0-pre.0", + "@npmcli/arborist": "^6.0.0-pre.1", "@npmcli/ci-detect": "^2.0.0", "@npmcli/config": "^4.2.1", "@npmcli/fs": "^2.1.0", @@ -79,10 +79,10 @@ "init-package-json": "^3.0.2", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^2.3.1", - "libnpmaccess": "^7.0.0-pre.0", + "libnpmaccess": "^7.0.0-pre.1", "libnpmdiff": "^5.0.0-pre.0", - "libnpmexec": "^5.0.0-pre.0", - "libnpmfund": "^4.0.0-pre.0", + "libnpmexec": "^5.0.0-pre.1", + "libnpmfund": "^4.0.0-pre.1", "libnpmhook": "^9.0.0-pre.0", "libnpmorg": "^5.0.0-pre.0", "libnpmpack": "^5.0.0-pre.0", diff --git a/workspaces/arborist/CHANGELOG.md b/workspaces/arborist/CHANGELOG.md index 6afe93f2dde7d..c96cf00e7a8db 100644 --- a/workspaces/arborist/CHANGELOG.md +++ b/workspaces/arborist/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [6.0.0-pre.1](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.0...arborist-v6.0.0-pre.1) (2022-09-14) + +### Bug Fixes + +* [`f3b0c43`](https://github.com/npm/cli/commit/f3b0c438d5b62b267f36c21d7b9fa57ae9507ef5) keep saveTypes separate for each `add` (@wraithgar) + ## [6.0.0-pre.0](https://github.com/npm/cli/compare/arborist-v5.6.1...arborist-v6.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index b8384e5f0b5ee..9c58bff582367 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "6.0.0-pre.0", + "version": "6.0.0-pre.1", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", diff --git a/workspaces/libnpmaccess/CHANGELOG.md b/workspaces/libnpmaccess/CHANGELOG.md index 8fd14a63f0066..4bfe6ce9ebb53 100644 --- a/workspaces/libnpmaccess/CHANGELOG.md +++ b/workspaces/libnpmaccess/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [7.0.0-pre.1](https://github.com/npm/cli/compare/libnpmaccess-v7.0.0-pre.0...libnpmaccess-v7.0.0-pre.1) (2022-09-14) + +### ⚠️ BREAKING CHANGES + +* the api for libnpmaccess is different now + +### Features + +* [`854521b`](https://github.com/npm/cli/commit/854521baa49ef88ff9586ec2cc5f1fbaee7fa364) rewrite: Rewrite libnpmaccess (@wraithgar) + ## [7.0.0-pre.0](https://github.com/npm/cli/compare/libnpmaccess-v6.0.4...libnpmaccess-v7.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index 21d31f18aa0f9..93fa3bb973bf5 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -1,6 +1,6 @@ { "name": "libnpmaccess", - "version": "7.0.0-pre.0", + "version": "7.0.0-pre.1", "description": "programmatic library for `npm access` commands", "author": "GitHub Inc.", "license": "ISC", diff --git a/workspaces/libnpmexec/CHANGELOG.md b/workspaces/libnpmexec/CHANGELOG.md index 91fce3939d765..79486595a645f 100644 --- a/workspaces/libnpmexec/CHANGELOG.md +++ b/workspaces/libnpmexec/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.0-pre.1](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.0...libnpmexec-v5.0.0-pre.1) (2022-09-14) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.0...arborist-v6.0.0-pre.1): `@npmcli/arborist@6.0.0-pre.1` + ## [5.0.0-pre.0](https://github.com/npm/cli/compare/libnpmexec-v4.0.12...libnpmexec-v5.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 3566779ac83bc..39c185ee4a0f2 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "5.0.0-pre.0", + "version": "5.0.0-pre.1", "files": [ "bin/", "lib/" @@ -54,7 +54,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.0", + "@npmcli/arborist": "^6.0.0-pre.1", "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.2.0", diff --git a/workspaces/libnpmfund/CHANGELOG.md b/workspaces/libnpmfund/CHANGELOG.md index a2d26703e4684..e10f4b45bb352 100644 --- a/workspaces/libnpmfund/CHANGELOG.md +++ b/workspaces/libnpmfund/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.0.0-pre.1](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.0...libnpmfund-v4.0.0-pre.1) (2022-09-14) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.0...arborist-v6.0.0-pre.1): `@npmcli/arborist@6.0.0-pre.1` + ## [4.0.0-pre.0](https://github.com/npm/cli/compare/libnpmfund-v3.0.3...libnpmfund-v4.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index c665fdeb16d29..271be4e686c9e 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "4.0.0-pre.0", + "version": "4.0.0-pre.1", "main": "lib/index.js", "files": [ "bin/", @@ -46,7 +46,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.0" + "@npmcli/arborist": "^6.0.0-pre.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" From e5761b9adafe8607ad68baa9599ad4eb228bc6be Mon Sep 17 00:00:00 2001 From: npm CLI robot Date: Wed, 14 Sep 2022 23:12:19 +0000 Subject: [PATCH 10/40] chore: post pull request --- AUTHORS | 1 + package-lock.json | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/AUTHORS b/AUTHORS index 51a75460a7d80..313d036461b52 100644 --- a/AUTHORS +++ b/AUTHORS @@ -853,3 +853,4 @@ Kyle West Nathan Hughes Sandeep Meduru <73886592+sandeepmeduru@users.noreply.github.com> Kid <44045911+kidonng@users.noreply.github.com> +Hugh Lilly diff --git a/package-lock.json b/package-lock.json index 9705d21a10cb4..0cb2bb110377a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "npm", - "version": "9.0.0-pre.0", + "version": "9.0.0-pre.1", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -91,7 +91,7 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.0.0-pre.0", + "@npmcli/arborist": "^6.0.0-pre.1", "@npmcli/ci-detect": "^2.0.0", "@npmcli/config": "^4.2.1", "@npmcli/fs": "^2.1.0", @@ -114,10 +114,10 @@ "init-package-json": "^3.0.2", "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^2.3.1", - "libnpmaccess": "^7.0.0-pre.0", + "libnpmaccess": "^7.0.0-pre.1", "libnpmdiff": "^5.0.0-pre.0", - "libnpmexec": "^5.0.0-pre.0", - "libnpmfund": "^4.0.0-pre.0", + "libnpmexec": "^5.0.0-pre.1", + "libnpmfund": "^4.0.0-pre.1", "libnpmhook": "^9.0.0-pre.0", "libnpmorg": "^5.0.0-pre.0", "libnpmpack": "^5.0.0-pre.0", @@ -13856,7 +13856,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "6.0.0-pre.0", + "version": "6.0.0-pre.1", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -13914,7 +13914,7 @@ } }, "workspaces/libnpmaccess": { - "version": "7.0.0-pre.0", + "version": "7.0.0-pre.1", "license": "ISC", "dependencies": { "npm-package-arg": "^9.0.1", @@ -13953,10 +13953,10 @@ } }, "workspaces/libnpmexec": { - "version": "5.0.0-pre.0", + "version": "5.0.0-pre.1", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.0", + "@npmcli/arborist": "^6.0.0-pre.1", "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.2.0", @@ -13984,10 +13984,10 @@ } }, "workspaces/libnpmfund": { - "version": "4.0.0-pre.0", + "version": "4.0.0-pre.1", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.0" + "@npmcli/arborist": "^6.0.0-pre.1" }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", From 83f8942df9440bdcfe6c99ca0c294de6ffb5fc72 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Mon, 19 Sep 2022 14:11:16 -0700 Subject: [PATCH 11/40] chore: template-oss@4.3.2 --- DEPENDENCIES.md | 1 + docs/package.json | 13 +- node_modules/.gitignore | 1 + package-lock.json | 44 ++-- package.json | 19 +- scripts/release-manager.js | 189 ++++++++++++++++++ scripts/template-oss/_step-deps.yml | 2 + .../template-oss/branch-specific-config.js | 5 + scripts/template-oss/ci-release.yml | 23 +++ scripts/template-oss/ci.yml | 35 ++++ scripts/template-oss/index.js | 3 + scripts/template-oss/root.js | 44 ++++ smoke-tests/package.json | 6 +- workspaces/arborist/package.json | 5 +- workspaces/libnpmaccess/package.json | 5 +- workspaces/libnpmdiff/package.json | 5 +- workspaces/libnpmexec/package.json | 5 +- workspaces/libnpmfund/package.json | 5 +- workspaces/libnpmhook/package.json | 5 +- workspaces/libnpmorg/package.json | 5 +- workspaces/libnpmpack/package.json | 5 +- workspaces/libnpmpublish/package.json | 5 +- workspaces/libnpmsearch/package.json | 5 +- workspaces/libnpmteam/package.json | 5 +- workspaces/libnpmversion/package.json | 5 +- 25 files changed, 385 insertions(+), 60 deletions(-) create mode 100644 scripts/release-manager.js create mode 100644 scripts/template-oss/_step-deps.yml create mode 100644 scripts/template-oss/branch-specific-config.js create mode 100644 scripts/template-oss/ci-release.yml create mode 100644 scripts/template-oss/ci.yml create mode 100644 scripts/template-oss/index.js create mode 100644 scripts/template-oss/root.js diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 105761dcb15bd..e14cecf0dc7fe 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -523,6 +523,7 @@ graph LR; npm-->npmcli-run-script["@npmcli/run-script"]; npm-->npmcli-template-oss["@npmcli/template-oss"]; npm-->npmlog; + npm-->octokit-rest["@octokit/rest"]; npm-->opener; npm-->p-map; npm-->pacote; diff --git a/docs/package.json b/docs/package.json index 74c575337f736..7e9c4038c0a75 100644 --- a/docs/package.json +++ b/docs/package.json @@ -22,7 +22,7 @@ "@npmcli/eslint-config": "^3.1.0", "@npmcli/fs": "^2.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "cmark-gfm": "^0.9.0", "jsdom": "^18.1.0", "marked-man": "^0.7.0", @@ -51,14 +51,15 @@ "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "distPaths": [ - "bin/", - "lib/", "content/", "nav.yml" ], - "ciVersions": [ - "16" + "allowPaths": [ + "/content/", + "/nav.yml" ], - "version": "4.1.2" + "ciVersions": "latest", + "version": "4.3.2", + "content": "../scripts/template-oss/index.js" } } diff --git a/node_modules/.gitignore b/node_modules/.gitignore index ce939861b6519..37530342b697a 100644 --- a/node_modules/.gitignore +++ b/node_modules/.gitignore @@ -379,6 +379,7 @@ __pycache__ /jsonpath /JSONStream /jsprim +/just-deep-map-values /kind-of /lcov-parse /levn diff --git a/package-lock.json b/package-lock.json index 0cb2bb110377a..ecf6ac60477c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -169,7 +169,8 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", + "@octokit/rest": "^19.0.4", "fs-minipass": "^2.1.0", "licensee": "^8.2.0", "minimatch": "^5.1.0", @@ -189,7 +190,7 @@ "@npmcli/eslint-config": "^3.1.0", "@npmcli/fs": "^2.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "cmark-gfm": "^0.9.0", "jsdom": "^18.1.0", "marked-man": "^0.7.0", @@ -2362,9 +2363,9 @@ } }, "node_modules/@npmcli/template-oss": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/template-oss/-/template-oss-4.1.2.tgz", - "integrity": "sha512-BS9YZeRtLsZ+lnCcQV3tZQa25K+MbUz/MgX5ZFzRmU+gTgCGthfajXZ7r8jJTjSiNgrElS0Ty/+x6Ds6B7oFdw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/template-oss/-/template-oss-4.3.2.tgz", + "integrity": "sha512-4sVkA9hvoRlGDxZ+UtiE5YEvJWAFUiY3tzi2N8zAxsgf1qS0HkrVBqRJikBRzleUBjmYLrxAI1qqY8Lz/ubupg==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -2381,6 +2382,7 @@ "handlebars": "^4.7.7", "hosted-git-info": "^5.0.0", "json-parse-even-better-errors": "^2.3.1", + "just-deep-map-values": "^1.1.1", "just-diff": "^5.0.1", "lodash": "^4.17.21", "npm-package-arg": "^9.0.1", @@ -6959,6 +6961,12 @@ "node": ">=0.6.0" } }, + "node_modules/just-deep-map-values": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/just-deep-map-values/-/just-deep-map-values-1.1.1.tgz", + "integrity": "sha512-hCMqPI0FjM2wpOWBYgvrdZlmFZF+7PeC/IzBxvt7dgUsK/OFeFOwJ1kv40Vx5I3RJiWv7ninPUxjk2Af0YiDAw==", + "dev": true + }, "node_modules/just-diff": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.1.1.tgz", @@ -13844,7 +13852,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "minify-registry-metadata": "^2.2.0", "rimraf": "^3.0.2", "tap": "^16.0.1", @@ -13901,7 +13909,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "benchmark": "^2.1.4", "chalk": "^4.1.0", "minify-registry-metadata": "^2.1.0", @@ -13922,7 +13930,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -13945,7 +13953,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "tap": "^16.0.1" }, "engines": { @@ -13973,7 +13981,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "bin-links": "^3.0.3", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", @@ -13991,7 +13999,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "tap": "^16.0.1" }, "engines": { @@ -14007,7 +14015,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14024,7 +14032,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "minipass": "^3.1.1", "nock": "^13.2.4", "tap": "^16.0.1" @@ -14043,7 +14051,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.0.7", "tap": "^16.0.1" }, @@ -14063,7 +14071,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "libnpmpack": "^5.0.0-pre.0", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", @@ -14081,7 +14089,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14098,7 +14106,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14118,7 +14126,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "require-inject": "^1.4.4", "tap": "^16.0.1" }, diff --git a/package.json b/package.json index 048ec7ee9629b..f5441bea2f76b 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,8 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", + "@octokit/rest": "^19.0.4", "fs-minipass": "^2.1.0", "licensee": "^8.2.0", "minimatch": "^5.1.0", @@ -223,16 +224,18 @@ "test-all": "npm run test --if-present --workspaces --include-workspace-root", "snap": "tap", "postsnap": "make -s docs", - "test:nocleanup": "NO_TEST_CLEANUP=1 npm run test --", - "sudotest": "sudo npm run test --", - "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 npm run test --", + "test:nocleanup": "NO_TEST_CLEANUP=1 node . run test --", + "sudotest": "sudo node . run test --", + "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 node . run test --", "posttest": "npm run lint", "lint": "eslint \"**/*.js\"", "lintfix": "npm run lint -- --fix", "lint-all": "npm run lint --if-present --workspaces --include-workspace-root", "prelint": "rimraf test/npm_cache*", "resetdeps": "bash scripts/resetdeps.sh", - "rp-pull-request": "npm run resetdeps && npm run authors" + "rp-pull-request": "node . run authors && node scripts/release-manager.js", + "postlint": "template-oss-check", + "template-oss-apply": "template-oss-apply --force" }, "tap": { "test-env": [ @@ -249,10 +252,8 @@ ] }, "templateOSS": { - "rootRepo": false, - "rootModule": false, - "version": "4.1.2", - "releaseTest": "release.yml" + "version": "4.3.2", + "content": "./scripts/template-oss/root.js" }, "license": "Artistic-2.0", "engines": { diff --git a/scripts/release-manager.js b/scripts/release-manager.js new file mode 100644 index 0000000000000..27968e80b7891 --- /dev/null +++ b/scripts/release-manager.js @@ -0,0 +1,189 @@ +#!/usr/bin/env node + +const { Octokit } = require('@octokit/rest') +const semver = require('semver') + +const log = (...logs) => console.error('LOG', ...logs) + +const getReleaseProcess = async () => { + // XXX: the release steps need to always be the last thing in the doc for this to work + const RELEASE_PROCESS_SECTION = '### Release the CLI and workspaces' + const RELEASE_PROCESS_WIKI = 'https://raw.githubusercontent.com/wiki/npm/cli/Release-Process.md' + const RELEASE_LIST_ITEM = /^\d+\.\s/gm + + log(`Fetching release process from:`, RELEASE_PROCESS_WIKI) + + const releaseProcess = await new Promise((resolve, reject) => { + require('https') + .get(RELEASE_PROCESS_WIKI, resp => { + let d = '' + resp.on('data', c => (d += c)) + resp.on('end', () => resolve(d)) + }) + .on('error', reject) + }) + + const section = releaseProcess.split(RELEASE_PROCESS_SECTION)[1] + + if (!section) { + throw new Error('Could not find release process section:', RELEASE_PROCESS_SECTION) + } + + return section.split({ + [Symbol.split] (str) { + const [, ...matches] = str.split(RELEASE_LIST_ITEM) + log(`Found ${matches.length} release items`) + return matches.map((m, i) => `- [ ] . ${m}`.trim()) + }, + }) +} + +const getPrReleases = async (pr) => { + const RELEASE_SEPARATOR = /
.*<\/summary>/g + const MONO_VERSIONS = /
(?:(.*?):\s)?(.*?)<\/summary>/ + const ROOT_VERSION = /\n##\s\[(.*?)\]/ + + const getReleaseInfo = ({ name, version: rawVersion }) => { + const version = semver.parse(rawVersion) + const prerelease = !!version.prerelease.length + const tag = `${name ? `${name}-` : ''}v${rawVersion}` + return { + name, + tag, + prerelease, + version: rawVersion, + major: version.major, + url: `https://github.com/${pr.base.repo.full_name}/releases/tag/${tag}`, + flags: name ? `-w ${name} ${prerelease ? `--tag prerelease` : ''}`.trim() : '', + } + } + + const releases = pr.body.match(RELEASE_SEPARATOR) + + if (!releases) { + log('Found no monorepo, checking for single root version') + const [, version] = pr.body.match(ROOT_VERSION) || [] + + if (!version) { + throw new Error('Could not find version with:', ROOT_VERSION) + } + + log('Found version', version) + return [getReleaseInfo({ version })] + } + + log(`Found ${releases.length} releases`) + + return releases.reduce((acc, r) => { + const [, name, version] = r.match(MONO_VERSIONS) + const release = getReleaseInfo({ name, version }) + + if (!name) { + log('Found root', release.tag) + acc[0] = release + } else { + log('Found workspace', release.tag) + acc[1].push(release) + } + + return acc + }, [null, []]) +} + +const appendToComment = async ({ github, commentId, title, body }) => { + if (!commentId) { + log(`No comment id, skipping append to comment`) + return + } + + const { data: comment } = await github.rest.issues.getComment({ + ...github.repo, + comment_id: commentId, + }) + + const hasAppended = comment.body.includes(title) + + log('Found comment with id:', commentId) + log(hasAppended ? 'Comment has aready been appended, replacing' : 'Appending to comment') + + const prefix = hasAppended + ? comment.body.split(title)[0] + : comment.body + + return github.rest.issues.updateComment({ + ...github.repo, + comment_id: commentId, + body: [prefix, title, body].join('\n\n'), + }) +} + +const main = async (env) => { + // These env vars are set by the release.yml workflow from template-oss + const { + CI, + GITHUB_TOKEN, + GITHUB_REPOSITORY, + RELEASE_PR_NUMBER, + RELEASE_COMMENT_ID, // comment is optional for testing + } = env + + if (!CI || !GITHUB_TOKEN || !GITHUB_REPOSITORY || !RELEASE_PR_NUMBER) { + throw new Error('This script is designed to run in CI. If you want to test it, set the ' + + `following env vars: \`CI, GITHUB_TOKEN, GITHUB_REPOSITORY, RELEASE_PR_NUMBER\``) + } + + const github = new Octokit({ auth: GITHUB_TOKEN }) + github.repo = { owner: GITHUB_REPOSITORY.split('/')[0], repo: GITHUB_REPOSITORY.split('/')[1] } + + const { data: pr } = await github.rest.pulls.get({ + ...github.repo, + pull_number: RELEASE_PR_NUMBER, + }) + + const [release, workspaces = []] = await getPrReleases(pr) + + const RELEASE_OMIT_PRERELEASE = '> NOT FOR PRERELEASE' + const RELEASE_OMIT_WORKSPACES = 'Publish workspaces' + const releaseItems = (await getReleaseProcess()) + .filter((item) => { + if (release.prerelease && item.includes(RELEASE_OMIT_PRERELEASE)) { + return false + } + + if (!workspaces.length && item.includes(RELEASE_OMIT_WORKSPACES)) { + return false + } + + return true + }) + .map((item, index) => item.replace('', index + 1)) + + log( + `Filtered ${releaseItems.length} release process items:\n`, + releaseItems.map(r => r.split('\n')[0]).join('\n') + ) + + const releaseTitle = `### Release Checklist for ${release.tag}` + const releaseChecklist = releaseItems + .join('\n\n') + .replace(//g, pr.head.ref) + .replace(//g, pr.base.ref) + .replace(//g, release.major) + .replace(//g, release.version) + .replace(//g, release.url) + .replace(/(\s+node \. publish )-w /g, workspaces.map(w => `$1${w.flags}`).join('')) + .trim() + + await appendToComment({ + github, + commentId: RELEASE_COMMENT_ID, + title: releaseTitle, + body: releaseChecklist, + }) +} + +main(process.env) + // This is part of the release CI and is for posting a release manager + // comment to the issue but we dont want it to ever fail the workflow so + // just log but dont set the error code + .catch(err => console.error(err)) diff --git a/scripts/template-oss/_step-deps.yml b/scripts/template-oss/_step-deps.yml new file mode 100644 index 0000000000000..2f77eabdc4337 --- /dev/null +++ b/scripts/template-oss/_step-deps.yml @@ -0,0 +1,2 @@ +- name: Reset Deps + run: {{rootNpmPath}} run resetdeps diff --git a/scripts/template-oss/branch-specific-config.js b/scripts/template-oss/branch-specific-config.js new file mode 100644 index 0000000000000..9dfbedd7d2a05 --- /dev/null +++ b/scripts/template-oss/branch-specific-config.js @@ -0,0 +1,5 @@ +// Leave this empty to use the default ciVersions from template-oss +// This file is kept here to make it easier to apply template-oss +// changes to other branches which might have different ciVersions +// or other conifg options +module.exports = {} diff --git a/scripts/template-oss/ci-release.yml b/scripts/template-oss/ci-release.yml new file mode 100644 index 0000000000000..93dd4f1edeed3 --- /dev/null +++ b/scripts/template-oss/ci-release.yml @@ -0,0 +1,23 @@ +{{> ciRelease}} + + smoke-publish: + {{> jobMatrix + jobName="Smoke Publish" + jobCheck=(obj sha="${{ inputs.check-sha }}") + jobCheckout=(obj ref="${{ inputs.ref }}") + }} + - name: Pack + run: | + NPM_VERSION="$({{ rootNpmPath }} --version)-$GITHUB_SHA.0" + {{ rootNpmPath }} version $NPM_VERSION --ignore-scripts + {{ rootNpmPath }} run resetdeps + git clean -fd + {{ rootNpmPath }} ls --production >/dev/null + {{ rootNpmPath }} prune --production --no-save --no-audit --no-fund + node scripts/git-dirty.js + {{ rootNpmPath }} pack --pack-destination=$RUNNER_TEMP + {{ rootNpmPath }} install -g $RUNNER_TEMP/npm-$NPM_VERSION.tgz + {{ rootNpmPath }} install -w smoke-tests --ignore-scripts --no-audit --no-fund + rm -rf {lib,bin,index.js} + SMOKE_PUBLISH_NPM=1 {{ rootNpmPath }} test -w smoke-tests --ignore-scripts + {{> stepChecks jobCheck=true }} diff --git a/scripts/template-oss/ci.yml b/scripts/template-oss/ci.yml new file mode 100644 index 0000000000000..0ddffde96eec3 --- /dev/null +++ b/scripts/template-oss/ci.yml @@ -0,0 +1,35 @@ +name: CI - cli + +on: + {{> onCi }} + +jobs: + lint: + {{> job jobName="Lint" }} + {{> stepLint jobRunFlags=pkgFlags }} + + check-docs: + {{> job jobName="Check Docs" }} + - name: Make Docs + run: make freshdocs + - name: Check Git Status + run: node scripts/git-dirty.js + + licenses: + {{> job jobName="Check Licenses" }} + - name: Check Licenses + run: {{rootNpmPath}} run licenses + + smoke-tests: + {{> job jobName="Smoke Tests" }} + - name: Run Smoke Tests + run: {{rootNpmPath}} test -w smoke-tests --ignore-scripts + - name: Check Git Status + run: node scripts/git-dirty.js + + test: + {{> jobMatrix jobName="Test" }} + {{> stepTest jobRunFlags=pkgFlags }} + - name: Check Git Status + if: matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/scripts/template-oss/index.js b/scripts/template-oss/index.js new file mode 100644 index 0000000000000..f18acc210b355 --- /dev/null +++ b/scripts/template-oss/index.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('./branch-specific-config.js'), +} diff --git a/scripts/template-oss/root.js b/scripts/template-oss/root.js new file mode 100644 index 0000000000000..fdcdd6b6663c6 --- /dev/null +++ b/scripts/template-oss/root.js @@ -0,0 +1,44 @@ +module.exports = { + rootRepo: { + add: { + '.github/ISSUE_TEMPLATE/config.yml': false, + '.github/ISSUE_TEMPLATE/bug.yml': false, + '.github/workflows/ci.yml': 'ci.yml', + '.github/workflows/ci-release.yml': 'ci-release.yml', + }, + }, + workspaceRepo: { + add: { + '.github/workflows/release.yml': false, + '.github/workflows/ci-release.yml': false, + }, + }, + lockfile: true, + npm: '.', + defaultBranch: 'latest', + distPaths: [ + 'index.js', + 'docs/content/**/*.md', + 'docs/output/**/*.html', + 'man', + ], + allowPaths: [ + '/node_modules/', + '/index.js', + '/Makefile', + '/make.bat', + '/DEPENDENCIES.md', + '/CONTRIBUTING.md', + '/configure', + '/changelogs/', + '/AUTHORS', + '/.mailmap', + '/.licensee.json', + '/.gitattributes', + ], + ignorePaths: [ + '/node_modules/.bin/', + '/node_modules/.cache/', + ], + ...require('./branch-specific-config.js'), +} diff --git a/smoke-tests/package.json b/smoke-tests/package.json index 73ffde9910e39..59f78602ae09d 100644 --- a/smoke-tests/package.json +++ b/smoke-tests/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "minify-registry-metadata": "^2.2.0", "rimraf": "^3.0.2", "tap": "^16.0.1", @@ -30,8 +30,8 @@ "license": "ISC", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2", - "workspaceRepo": false + "version": "4.3.2", + "content": "../scripts/template-oss/index.js" }, "tap": { "no-coverage": true, diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 9c58bff582367..b9c3d4320a43b 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "benchmark": "^2.1.4", "chalk": "^4.1.0", "minify-registry-metadata": "^2.1.0", @@ -100,6 +100,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index 93fa3bb973bf5..faafec2f2278f 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -40,6 +40,7 @@ ], "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index c1665390b8c53..80f020ccfc468 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -43,7 +43,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "tap": "^16.0.1" }, "dependencies": { @@ -58,6 +58,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 39c185ee4a0f2..01cf528953942 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -47,7 +47,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "bin-links": "^3.0.3", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", @@ -71,6 +71,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 271be4e686c9e..98f6acda1b1de 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "tap": "^16.0.1" }, "dependencies": { @@ -53,6 +53,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmhook/package.json b/workspaces/libnpmhook/package.json index a4f42a83e643a..a2bc28ad46b1b 100644 --- a/workspaces/libnpmhook/package.json +++ b/workspaces/libnpmhook/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -46,6 +46,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmorg/package.json b/workspaces/libnpmorg/package.json index 748dd83f00e79..f63ab47e8c65f 100644 --- a/workspaces/libnpmorg/package.json +++ b/workspaces/libnpmorg/package.json @@ -28,7 +28,7 @@ ], "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "minipass": "^3.1.1", "nock": "^13.2.4", "tap": "^16.0.1" @@ -49,6 +49,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index f7d8fcfe28f7f..5cd9deb9b4b7b 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.0.7", "tap": "^16.0.1" }, @@ -44,6 +44,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 6959a8bd98354..6bd608a55428e 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "libnpmpack": "^5.0.0-pre.0", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", @@ -50,6 +50,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmsearch/package.json b/workspaces/libnpmsearch/package.json index 3581ecc31e876..d90d7beac2608 100644 --- a/workspaces/libnpmsearch/package.json +++ b/workspaces/libnpmsearch/package.json @@ -26,7 +26,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -45,6 +45,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmteam/package.json b/workspaces/libnpmteam/package.json index d9efe70197337..ef1e78fc22d36 100644 --- a/workspaces/libnpmteam/package.json +++ b/workspaces/libnpmteam/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -39,6 +39,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmversion/package.json b/workspaces/libnpmversion/package.json index ec4e4bc8a73e6..ed3082b918220 100644 --- a/workspaces/libnpmversion/package.json +++ b/workspaces/libnpmversion/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.1.2", + "@npmcli/template-oss": "4.3.2", "require-inject": "^1.4.4", "tap": "^16.0.1" }, @@ -44,6 +44,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.1.2" + "version": "4.3.2", + "content": "../../scripts/template-oss/index.js" } } From d3ff2aa9b57d7448c5770ba307118ce4c3b6a888 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Mon, 19 Sep 2022 14:13:49 -0700 Subject: [PATCH 12/40] chore: apply template-oss changes --- .commitlintrc.js | 10 + .eslintrc.js | 9 + .github/CODEOWNERS | 4 +- .github/dependabot.yml | 185 +++++++++++++++ .github/workflows/audit.yml | 34 +++ .github/workflows/ci-docs.yml | 79 ++++--- .github/workflows/ci-libnpmaccess.yml | 81 ++++--- .github/workflows/ci-libnpmdiff.yml | 81 ++++--- .github/workflows/ci-libnpmexec.yml | 81 ++++--- .github/workflows/ci-libnpmfund.yml | 81 ++++--- .github/workflows/ci-libnpmhook.yml | 81 ++++--- .github/workflows/ci-libnpmorg.yml | 81 ++++--- .github/workflows/ci-libnpmpack.yml | 81 ++++--- .github/workflows/ci-libnpmpublish.yml | 81 ++++--- .github/workflows/ci-libnpmsearch.yml | 81 ++++--- .github/workflows/ci-libnpmteam.yml | 81 ++++--- .github/workflows/ci-libnpmversion.yml | 81 ++++--- .github/workflows/ci-npmcli-arborist.yml | 81 ++++--- .github/workflows/ci-release.yml | 214 +++++++++++++++++ .github/workflows/ci-smoke-tests.yml | 91 ++++++++ .github/workflows/ci.yml | 159 +++++++++---- .github/workflows/codeql-analysis.yml | 38 +++ .github/workflows/post-dependabot.yml | 88 +++++++ .github/workflows/pull-request.yml | 45 ++++ .github/workflows/release-please.yml | 101 -------- .github/workflows/release.yml | 284 ++++++++++++++++------- .gitignore | 63 +++-- .npmrc | 3 + CODE_OF_CONDUCT.md | 7 + SECURITY.md | 2 + docs/.gitignore | 18 +- docs/package.json | 12 +- package-lock.json | 2 +- package.json | 26 ++- smoke-tests/.gitignore | 18 +- smoke-tests/package.json | 10 +- workspaces/arborist/.gitignore | 18 +- workspaces/arborist/package.json | 10 +- workspaces/libnpmaccess/.gitignore | 18 +- workspaces/libnpmaccess/package.json | 10 +- workspaces/libnpmdiff/.gitignore | 18 +- workspaces/libnpmdiff/package.json | 10 +- workspaces/libnpmexec/.gitignore | 18 +- workspaces/libnpmexec/package.json | 10 +- workspaces/libnpmfund/.gitignore | 18 +- workspaces/libnpmfund/package.json | 10 +- workspaces/libnpmhook/.gitignore | 18 +- workspaces/libnpmhook/package.json | 10 +- workspaces/libnpmorg/.gitignore | 18 +- workspaces/libnpmorg/package.json | 10 +- workspaces/libnpmpack/.gitignore | 18 +- workspaces/libnpmpack/package.json | 10 +- workspaces/libnpmpublish/.gitignore | 18 +- workspaces/libnpmpublish/package.json | 10 +- workspaces/libnpmsearch/.gitignore | 18 +- workspaces/libnpmsearch/package.json | 10 +- workspaces/libnpmteam/.gitignore | 18 +- workspaces/libnpmteam/package.json | 10 +- workspaces/libnpmversion/.gitignore | 18 +- workspaces/libnpmversion/package.json | 10 +- 60 files changed, 1855 insertions(+), 955 deletions(-) create mode 100644 .commitlintrc.js create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/audit.yml create mode 100644 .github/workflows/ci-release.yml create mode 100644 .github/workflows/ci-smoke-tests.yml create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/post-dependabot.yml create mode 100644 .github/workflows/pull-request.yml delete mode 100644 .github/workflows/release-please.yml create mode 100644 CODE_OF_CONDUCT.md diff --git a/.commitlintrc.js b/.commitlintrc.js new file mode 100644 index 0000000000000..5b0b1a5232728 --- /dev/null +++ b/.commitlintrc.js @@ -0,0 +1,10 @@ +/* This file is automatically added by @npmcli/template-oss. Do not edit. */ + +module.exports = { + extends: ['@commitlint/config-conventional'], + rules: { + 'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'deps', 'chore']], + 'header-max-length': [2, 'always', 80], + 'subject-case': [0, 'always', ['lower-case', 'sentence-case', 'start-case']], + }, +} diff --git a/.eslintrc.js b/.eslintrc.js index 1718f033c4122..ff8d43d7ffe5c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,3 +1,7 @@ +/* This file is automatically added by @npmcli/template-oss. Do not edit. */ + +'use strict' + const { readdirSync: readdir } = require('fs') const localConfigs = readdir(__dirname) @@ -6,6 +10,11 @@ const localConfigs = readdir(__dirname) module.exports = { root: true, + ignorePatterns: [ + 'docs/**', + 'smoke-tests/**', + 'workspaces/**', + ], extends: [ '@npmcli', ...localConfigs, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ef8743136d8a1..2c54b0d250372 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,3 @@ -* @npm/cli-team +# This file is automatically added by @npmcli/template-oss. Do not edit. + +* @npm/cli-team diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000000..a7931f39843bc --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,185 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +version: 2 + +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: docs/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: smoke-tests/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/arborist/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmaccess/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmdiff/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmexec/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmfund/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmhook/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmorg/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmpack/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmpublish/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmsearch/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmteam/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" + - package-ecosystem: npm + directory: workspaces/libnpmversion/ + schedule: + interval: daily + allow: + - dependency-type: direct + versioning-strategy: increase-if-necessary + commit-message: + prefix: deps + prefix-development: chore + labels: + - "Dependencies" diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 0000000000000..1eca24a409ce3 --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,34 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Audit + +on: + workflow_dispatch: + schedule: + # "At 08:00 UTC (01:00 PT) on Monday" https://crontab.guru/#0_8_*_*_1 + - cron: "0 8 * * 1" + +jobs: + audit: + name: Audit Dependencies + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Run Audit + run: node . audit diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index dd8a43192ddd0..b79c9f5b8077a 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -5,8 +5,6 @@ name: CI - docs on: workflow_dispatch: pull_request: - branches: - - '*' paths: - docs/** push: @@ -21,67 +19,68 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: - node-version: 16 - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w docs + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: - node-version: - - 16 platform: - - os: ubuntu-latest + - name: Linux + os: ubuntu-latest shell: bash - - os: macos-latest + - name: macOS + os: macos-latest shell: bash - - os: windows-latest + - name: Windows + os: windows-latest shell: cmd + node-version: + - 18.x runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w docs + - name: Test + run: node . test --ignore-scripts -w docs diff --git a/.github/workflows/ci-libnpmaccess.yml b/.github/workflows/ci-libnpmaccess.yml index 6f27d9555e669..5cbe173c1dba8 100644 --- a/.github/workflows/ci-libnpmaccess.yml +++ b/.github/workflows/ci-libnpmaccess.yml @@ -5,8 +5,6 @@ name: CI - libnpmaccess on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmaccess/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmaccess + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmaccess + - name: Test + run: node . test --ignore-scripts -w libnpmaccess diff --git a/.github/workflows/ci-libnpmdiff.yml b/.github/workflows/ci-libnpmdiff.yml index daba1324de171..cd7623243f427 100644 --- a/.github/workflows/ci-libnpmdiff.yml +++ b/.github/workflows/ci-libnpmdiff.yml @@ -5,8 +5,6 @@ name: CI - libnpmdiff on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmdiff/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmdiff + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmdiff + - name: Test + run: node . test --ignore-scripts -w libnpmdiff diff --git a/.github/workflows/ci-libnpmexec.yml b/.github/workflows/ci-libnpmexec.yml index e7cd771243274..644d04ce445a6 100644 --- a/.github/workflows/ci-libnpmexec.yml +++ b/.github/workflows/ci-libnpmexec.yml @@ -5,8 +5,6 @@ name: CI - libnpmexec on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmexec/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmexec + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmexec + - name: Test + run: node . test --ignore-scripts -w libnpmexec diff --git a/.github/workflows/ci-libnpmfund.yml b/.github/workflows/ci-libnpmfund.yml index 268db59da6e92..ea50c49e63524 100644 --- a/.github/workflows/ci-libnpmfund.yml +++ b/.github/workflows/ci-libnpmfund.yml @@ -5,8 +5,6 @@ name: CI - libnpmfund on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmfund/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmfund + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmfund + - name: Test + run: node . test --ignore-scripts -w libnpmfund diff --git a/.github/workflows/ci-libnpmhook.yml b/.github/workflows/ci-libnpmhook.yml index 81eb7fe680ea7..250fb2f5a47aa 100644 --- a/.github/workflows/ci-libnpmhook.yml +++ b/.github/workflows/ci-libnpmhook.yml @@ -5,8 +5,6 @@ name: CI - libnpmhook on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmhook/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmhook + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmhook + - name: Test + run: node . test --ignore-scripts -w libnpmhook diff --git a/.github/workflows/ci-libnpmorg.yml b/.github/workflows/ci-libnpmorg.yml index 26e5a26dd8ceb..dc901e4f3e74b 100644 --- a/.github/workflows/ci-libnpmorg.yml +++ b/.github/workflows/ci-libnpmorg.yml @@ -5,8 +5,6 @@ name: CI - libnpmorg on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmorg/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmorg + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmorg + - name: Test + run: node . test --ignore-scripts -w libnpmorg diff --git a/.github/workflows/ci-libnpmpack.yml b/.github/workflows/ci-libnpmpack.yml index 4bd344e76f5e6..fac63daf6690e 100644 --- a/.github/workflows/ci-libnpmpack.yml +++ b/.github/workflows/ci-libnpmpack.yml @@ -5,8 +5,6 @@ name: CI - libnpmpack on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmpack/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmpack + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmpack + - name: Test + run: node . test --ignore-scripts -w libnpmpack diff --git a/.github/workflows/ci-libnpmpublish.yml b/.github/workflows/ci-libnpmpublish.yml index cad4ea600e5a6..7947dc61a5230 100644 --- a/.github/workflows/ci-libnpmpublish.yml +++ b/.github/workflows/ci-libnpmpublish.yml @@ -5,8 +5,6 @@ name: CI - libnpmpublish on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmpublish/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmpublish + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmpublish + - name: Test + run: node . test --ignore-scripts -w libnpmpublish diff --git a/.github/workflows/ci-libnpmsearch.yml b/.github/workflows/ci-libnpmsearch.yml index 83341b4655a4a..95a8d30bfa1a5 100644 --- a/.github/workflows/ci-libnpmsearch.yml +++ b/.github/workflows/ci-libnpmsearch.yml @@ -5,8 +5,6 @@ name: CI - libnpmsearch on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmsearch/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmsearch + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmsearch + - name: Test + run: node . test --ignore-scripts -w libnpmsearch diff --git a/.github/workflows/ci-libnpmteam.yml b/.github/workflows/ci-libnpmteam.yml index 38d77d209aaf7..aa82f5a7a7ea8 100644 --- a/.github/workflows/ci-libnpmteam.yml +++ b/.github/workflows/ci-libnpmteam.yml @@ -5,8 +5,6 @@ name: CI - libnpmteam on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmteam/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmteam + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmteam + - name: Test + run: node . test --ignore-scripts -w libnpmteam diff --git a/.github/workflows/ci-libnpmversion.yml b/.github/workflows/ci-libnpmversion.yml index 023fd8b7a870a..1bb0219fc6795 100644 --- a/.github/workflows/ci-libnpmversion.yml +++ b/.github/workflows/ci-libnpmversion.yml @@ -5,8 +5,6 @@ name: CI - libnpmversion on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/libnpmversion/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w libnpmversion + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w libnpmversion + - name: Test + run: node . test --ignore-scripts -w libnpmversion diff --git a/.github/workflows/ci-npmcli-arborist.yml b/.github/workflows/ci-npmcli-arborist.yml index d2c83de9eba23..7d571a608c5d9 100644 --- a/.github/workflows/ci-npmcli-arborist.yml +++ b/.github/workflows/ci-npmcli-arborist.yml @@ -5,8 +5,6 @@ name: CI - @npmcli/arborist on: workflow_dispatch: pull_request: - branches: - - '*' paths: - workspaces/arborist/** push: @@ -21,26 +19,47 @@ on: jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - run: npm run lint -w @npmcli/arborist + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -48,45 +67,25 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Setup git user + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User run: | git config --global user.email "npm-cli+bot@github.com" git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 + - name: Setup Node + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Update to workable npm (windows) - # node 12 and 14 ship with npm@6, which is known to fail when updating itself in windows - if: matrix.platform.os == 'windows-latest' && (startsWith(matrix.node-version, '12.') || startsWith(matrix.node-version, '14.')) - run: | - curl -sO https://registry.npmjs.org/npm/-/npm-7.5.4.tgz - tar xf npm-7.5.4.tgz - cd package - node lib/npm.js install --no-fund --no-audit -g ..\npm-7.5.4.tgz - cd .. - rmdir /s /q package - - name: Update npm to 7 - # If we do test on npm 10 it needs npm7 - if: startsWith(matrix.node-version, '10.') - run: npm i --prefer-online --no-fund --no-audit -g npm@7 - - name: Update npm to latest - if: ${{ !startsWith(matrix.node-version, '10.') }} - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: add tap problem matcher + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" - - run: npm test --ignore-scripts -w @npmcli/arborist + - name: Test + run: node . test --ignore-scripts -w @npmcli/arborist diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml new file mode 100644 index 0000000000000..8e07a57fea5ef --- /dev/null +++ b/.github/workflows/ci-release.yml @@ -0,0 +1,214 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: CI - Release + +on: + workflow_call: + inputs: + ref: + required: true + type: string + check-sha: + required: true + type: string + +jobs: + lint-all: + name: Lint All + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Lint All + sha: ${{ inputs.check-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} + + test-all: + name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Test All - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + sha: ${{ inputs.check-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: node . test --ignore-scripts -ws -iwr --if-present + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} + + smoke-publish: + name: Smoke Publish - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Smoke Publish - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + sha: ${{ inputs.check-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Pack + run: | + NPM_VERSION="$(node . --version)-$GITHUB_SHA.0" + node . version $NPM_VERSION --ignore-scripts + node . run resetdeps + git clean -fd + node . ls --production >/dev/null + node . prune --production --no-save --no-audit --no-fund + node scripts/git-dirty.js + node . pack --pack-destination=$RUNNER_TEMP + node . install -g $RUNNER_TEMP/npm-$NPM_VERSION.tgz + node . install -w smoke-tests --ignore-scripts --no-audit --no-fund + rm -rf {lib,bin,index.js} + SMOKE_PUBLISH_NPM=1 node . test -w smoke-tests --ignore-scripts + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ steps.check.outputs.check_id }} diff --git a/.github/workflows/ci-smoke-tests.yml b/.github/workflows/ci-smoke-tests.yml new file mode 100644 index 0000000000000..346335a72a18c --- /dev/null +++ b/.github/workflows/ci-smoke-tests.yml @@ -0,0 +1,91 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: CI - smoke-tests + +on: + workflow_dispatch: + pull_request: + paths: + - smoke-tests/** + push: + branches: + - main + - latest + paths: + - smoke-tests/** + schedule: + # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 + - cron: "0 9 * * 1" + +jobs: + lint: + name: Lint + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts + + test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: node . test --ignore-scripts -w smoke-tests diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8914fa041cc28..cb34dca3262f9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,70 +1,139 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + name: CI - cli on: workflow_dispatch: pull_request: - branches: - - '*' + paths-ignore: push: branches: + - main - latest + paths-ignore: + schedule: + # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 + - cron: "0 9 * * 1" jobs: lint: + name: Lint + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Use Node.js 16.x + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x cache: npm - - run: node bin/npm-cli.js run resetdeps - - run: node bin/npm-cli.js run lint + - name: Reset Deps + run: node . run resetdeps + - name: Lint + run: node . run lint --ignore-scripts + - name: Post Lint + run: node . run postlint --ignore-scripts - check_docs: + check-docs: + name: Check Docs + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Use Node.js 16.x + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x cache: npm - - run: make freshdocs - - run: node scripts/git-dirty.js + - name: Reset Deps + run: node . run resetdeps + - name: Make Docs + run: make freshdocs + - name: Check Git Status + run: node scripts/git-dirty.js licenses: + name: Check Licenses + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Use Node.js 16.x + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x cache: npm - - run: node bin/npm-cli.js run resetdeps - - run: node bin/npm-cli.js run licenses - + - name: Reset Deps + run: node . run resetdeps + - name: Check Licenses + run: node . run licenses + smoke-tests: + name: Smoke Tests + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - - name: Use Node.js 16.x + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x cache: npm - - run: node bin/npm-cli.js run resetdeps - - run: node bin/npm-cli.js test -w smoke-tests --ignore-scripts - - name: git status - if: matrix.platform.os != 'windows-latest' + - name: Reset Deps + run: node . run resetdeps + - name: Run Smoke Tests + run: node . test -w smoke-tests --ignore-scripts + - name: Check Git Status run: node scripts/git-dirty.js test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' strategy: fail-fast: false matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd node-version: - 14.17.0 - 14.x @@ -72,26 +141,28 @@ jobs: - 16.x - 18.0.0 - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: npm - - run: node bin/npm-cli.js run resetdeps - - run: node bin/npm-cli.js run test --ignore-scripts - - name: git status - if: matrix.platform.os != 'windows-latest' - run: node scripts/git-dirty.js + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: node . test --ignore-scripts -iwr + - name: Check Git Status + if: matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000000000..66b9498a685b9 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,38 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: CodeQL + +on: + push: + branches: + - main + - latest + pull_request: + branches: + - main + - latest + schedule: + # "At 10:00 UTC (03:00 PT) on Monday" https://crontab.guru/#0_10_*_*_1 + - cron: "0 10 * * 1" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: javascript + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml new file mode 100644 index 0000000000000..1302c7a80d31a --- /dev/null +++ b/.github/workflows/post-dependabot.yml @@ -0,0 +1,88 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Post Dependabot + +on: pull_request + +permissions: + contents: write + +jobs: + template-oss: + name: template-oss + if: github.repository_owner == 'npm' && github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head_ref }} + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Fetch Dependabot Metadata + id: metadata + uses: dependabot/fetch-metadata@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + # Dependabot can update multiple directories so we output which directory + # it is acting on so we can run the command for the correct root or workspace + - name: Get Dependabot Directory + if: contains(steps.metadata.outputs.dependency-names, '@npmcli/template-oss') + id: flags + run: | + if [[ "${{ steps.metadata.outputs.directory }}" == "/" ]]; then + echo "::set-output name=workspace::-iwr" + else + echo "::set-output name=workspace::-w ${{ steps.metadata.outputs.directory }}" + fi + + - name: Apply Changes + if: steps.flags.outputs.workspace + id: apply + run: | + node . run template-oss-apply ${{ steps.flags.outputs.workspace }} + if [[ `git status --porcelain` ]]; then + echo "::set-output name=changes::true" + fi + + # This step will fail if template-oss has made any workflow updates. It is impossible + # for a workflow to update other workflows. In the case it does fail, we continue + # and then try to apply only a portion of the changes in the next step + - name: Push All Changes + if: steps.apply.outputs.changes + id: push + continue-on-error: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git commit -am "chore: postinstall for dependabot template-oss PR" + git push + + - name: Push All Changes Except Workflows + if: steps.push.outcome == 'failure' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git reset HEAD~ + git checkout HEAD -- .github/workflows/ + git clean -fd .github/workflows/ + git commit -am "chore: postinstall for dependabot template-oss PR" + git push + + - name: Check Changes + if: steps.apply.outputs.changes + run: | + node . exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml new file mode 100644 index 0000000000000..3d008208833f3 --- /dev/null +++ b/.github/workflows/pull-request.yml @@ -0,0 +1,45 @@ +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Pull Request + +on: + pull_request: + types: + - opened + - reopened + - edited + - synchronize + +jobs: + commitlint: + name: Lint Commits + if: github.repository_owner == 'npm' + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: 18.x + cache: npm + - name: Reset Deps + run: node . run resetdeps + - name: Run Commitlint on Commits + id: commit + continue-on-error: true + run: | + npx --offline commitlint -V --from origin/${{ github.base_ref }} --to ${{ github.event.pull_request.head.sha }} + - name: Run Commitlint on PR Title + if: steps.commit.outcome == 'failure' + run: | + echo ${{ github.event.pull_request.title }} | npx --offline commitlint -V diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml deleted file mode 100644 index edd39d0ba5da3..0000000000000 --- a/.github/workflows/release-please.yml +++ /dev/null @@ -1,101 +0,0 @@ -# This file is automatically added by @npmcli/template-oss. Do not edit. - -name: Release Please - -on: - push: - branches: - - main - - latest - -permissions: - contents: write - pull-requests: write - -jobs: - release-please: - runs-on: ubuntu-latest - outputs: - pr: ${{ steps.release.outputs.pr }} - release: ${{ steps.release.outputs.release }} - steps: - - uses: actions/checkout@v3 - - name: Setup git user - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: Release Please - id: release - run: npx --offline template-oss-release-please ${{ github.ref_name }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - post-pr: - needs: release-please - if: needs.release-please.outputs.pr - runs-on: ubuntu-latest - outputs: - ref: ${{ steps.ref.outputs.branch }} - steps: - - name: Output ref - id: ref - run: echo "::set-output name=branch::${{ fromJSON(needs.release-please.outputs.pr).headBranchName }}" - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - ref: ${{ steps.ref.outputs.branch }} - - name: Setup git user - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: Post pull request actions - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npm run rp-pull-request --ignore-scripts --if-present -ws -iwr - git commit -am "chore: post pull request" || true - git push - - release-test: - needs: post-pr - if: needs.post-pr.outputs.ref - uses: ./.github/workflows/release.yml - with: - ref: ${{ needs.post-pr.outputs.ref }} - - post-release: - needs: release-please - if: needs.release-please.outputs.release - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Setup git user - run: | - git config --global user.email "npm-cli+bot@github.com" - git config --global user.name "npm CLI robot" - - uses: actions/setup-node@v3 - with: - node-version: 18.x - - name: Update npm to latest - run: npm i --prefer-online --no-fund --no-audit -g npm@latest - - run: npm -v - - run: npm i --ignore-scripts --no-audit --no-fund - - name: Post release actions - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - npm run rp-release --ignore-scripts --if-present -ws -iwr diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5035e26519272..87d95eeeaad99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,111 +1,225 @@ -name: Release - cli +# This file is automatically added by @npmcli/template-oss. Do not edit. + +name: Release on: - workflow_call: - inputs: - ref: - required: true - type: string + push: + branches: + - main + - latest + +permissions: + contents: write + pull-requests: write + checks: write jobs: - lint-all: + release: + outputs: + pr: ${{ steps.release.outputs.pr }} + releases: ${{ steps.release.outputs.releases }} + release-flags: ${{ steps.release.outputs.release-flags }} + branch: ${{ steps.release.outputs.pr-branch }} + pr-number: ${{ steps.release.outputs.pr-number }} + comment-id: ${{ steps.pr-comment.outputs.result }} + check-id: ${{ steps.check.outputs.check_id }} + name: Release + if: github.repository_owner == 'npm' runs-on: ubuntu-latest + defaults: + run: + shell: bash steps: - - uses: actions/checkout@v3 - with: - ref: ${{ inputs.ref }} - - name: Use Node.js 16.x + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x cache: npm - - run: node bin/npm-cli.js run resetdeps - - run: node bin/npm-cli.js run lint-all --ignore-scripts + - name: Reset Deps + run: node . run resetdeps + - name: Release Please + id: release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + npx --offline template-oss-release-please ${{ github.ref_name }} + - name: Post Pull Request Comment + if: steps.release.outputs.pr-number + uses: actions/github-script@v6 + id: pr-comment + env: + PR_NUMBER: ${{ steps.release.outputs.pr-number }} + with: + script: | + const repo = { owner: context.repo.owner, repo: context.repo.repo } + const issue = { ...repo, issue_number: process.env.PR_NUMBER } - smoke-publish: - strategy: - fail-fast: false - matrix: - node-version: - - 14.17.0 - - 14.x - - 16.13.0 - - 16.x - - 18.0.0 - - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - # XXX: this should be possible in windows also - # but resetdeps cant be a bash script - runs-on: ${{ matrix.platform.os }} + const { data: workflow } = await github.rest.actions.getWorkflowRun({ ...repo, run_id: context.runId }) + + let body = '## Release Manager\n\n' + + const comments = await github.paginate(github.rest.issues.listComments, issue) + let commentId = comments?.find(c => c.user.login === 'github-actions[bot]' && c.body.startsWith(body))?.id + + body += `- Release workflow run: ${workflow.html_url}` + if (commentId) { + await github.rest.issues.updateComment({ ...repo, comment_id: commentId, body }) + } else { + const { data: comment } = await github.rest.issues.createComment({ ...issue, body }) + commentId = comment?.id + } + + return commentId + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + if: steps.release.outputs.pr-number + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Release + sha: ${{ steps.release.outputs.pr-sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + + update: + needs: release + outputs: + sha: ${{ steps.commit.outputs.sha }} + check-id: ${{ steps.check.outputs.check_id }} + name: Update - Release + if: github.repository_owner == 'npm' && needs.release.outputs.pr + runs-on: ubuntu-latest defaults: run: - shell: ${{ matrix.platform.shell }} + shell: bash steps: - - uses: actions/checkout@v3 + - name: Checkout + uses: actions/checkout@v3 with: - ref: ${{ inputs.ref }} - - name: Setup git user + fetch-depth: 0 + ref: ${{ needs.release.outputs.branch }} + - name: Setup Git User run: | - git config --global user.email "ops+npm-cli@npmjs.com" - git config --global user.name "npm cli ops bot" - - name: Use Node.js 16.x + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 18.x cache: npm - - name: Pack + - name: Reset Deps + run: node . run resetdeps + - name: Run Post Pull Request Actions + env: + RELEASE_PR_NUMBER: ${{ needs.release.outputs.pr-number }} + RELEASE_COMMENT_ID: ${{ needs.release.outputs.comment-id }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - NPM_VERSION="$(node bin/npm-cli.js --version)-$GITHUB_SHA.0" - node bin/npm-cli.js version $NPM_VERSION --ignore-scripts - node bin/npm-cli.js run resetdeps - git clean -fd - node bin/npm-cli.js ls --production >/dev/null - node bin/npm-cli.js prune --production --no-save --no-audit --no-fund - node scripts/git-dirty.js - node bin/npm-cli.js pack --pack-destination=$RUNNER_TEMP - node bin/npm-cli.js install -g $RUNNER_TEMP/npm-$NPM_VERSION.tgz - node bin/npm-cli.js install -w smoke-tests --ignore-scripts --no-audit --no-fund - rm -rf {lib,bin,index.js} - SMOKE_PUBLISH_NPM=1 npm test -w smoke-tests --ignore-scripts - - test-all: - strategy: - fail-fast: false - matrix: - node-version: - - 14.17.0 - - 14.x - - 16.13.0 - - 16.x - - 18.0.0 - - 18.x - platform: - - os: ubuntu-latest - shell: bash - - os: macos-latest - shell: bash - - os: windows-latest - shell: cmd - runs-on: ${{ matrix.platform.os }} + node . run rp-pull-request --ignore-scripts -ws -iwr --if-present + - name: Commit + id: commit + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git commit --all --amend --no-edit || true + git push --force-with-lease + echo "::set-output name=sha::$(git rev-parse HEAD)" + - name: Create Check + uses: LouisBrunner/checks-action@v1.3.1 + id: check + + with: + token: ${{ secrets.GITHUB_TOKEN }} + status: in_progress + name: Release + sha: ${{ steps.commit.outputs.sha }} + # XXX: this does not work when using the default GITHUB_TOKEN. + # Instead we post the main job url to the PR as a comment which + # will link to all the other checks. To work around this we would + # need to create a GitHub that would create on-demand tokens. + # https://github.com/LouisBrunner/checks-action/issues/18 + # details_url: + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() + with: + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ job.status }} + check_id: ${{ needs.release.outputs.check-id }} + + ci: + name: CI - Release + needs: [ release, update ] + if: needs.release.outputs.pr + uses: ./.github/workflows/ci-release.yml + with: + ref: ${{ needs.release.outputs.branch }} + check-sha: ${{ needs.update.outputs.sha }} + + post-ci: + needs: [ release, update, ci ] + name: Post CI - Release + if: github.repository_owner == 'npm' && needs.release.outputs.pr && always() + runs-on: ubuntu-latest defaults: run: - shell: ${{ matrix.platform.shell }} + shell: bash steps: - - uses: actions/checkout@v3 + - name: Get Needs Result + id: needs-result + run: | + result="" + if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" ]]; then + result="failure" + elif [[ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then + result="cancelled" + else + result="success" + fi + echo "::set-output name=result::$result" + - name: Conclude Check + uses: LouisBrunner/checks-action@v1.3.1 + if: always() with: - ref: ${{ inputs.ref }} - - name: Use Node.js ${{ matrix.node-version }} + token: ${{ secrets.GITHUB_TOKEN }} + conclusion: ${{ steps.needs-result.outputs.result }} + check_id: ${{ needs.update.outputs.check-id }} + + post-release: + needs: release + name: Post Release - Release + if: github.repository_owner == 'npm' && needs.release.outputs.releases + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: 18.x cache: npm - - run: node bin/npm-cli.js run resetdeps - - run: node bin/npm-cli.js link -f --ignore-scripts - - run: node bin/npm-cli.js run test-all --ignore-scripts - - name: git status - if: matrix.platform.os != 'windows-latest' - run: node scripts/git-dirty.js + - name: Reset Deps + run: node . run resetdeps + - name: Run Post Release Actions + env: + RELEASES: ${{ needs.release.outputs.releases }} + run: | + node . run rp-release --ignore-scripts --if-present ${{ join(fromJSON(needs.release.outputs.release-flags), ' ') }} diff --git a/.gitignore b/.gitignore index 94f6b413c7636..370f45df41cd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,59 @@ -/* +# This file is automatically added by @npmcli/template-oss. Do not edit. -!/.github/ -!/bin/ -!/changelogs/ -!/docs/ -!/lib/ -!/node_modules/ -/node_modules/.bin/ -/node_modules/.cache/ -!/scripts/ -!/smoke-tests/ -!/tap-snapshots/ -!/test/ -!/workspaces/ +# ignore everything in the root +/* -!/.release-please-manifest.json -!/release-please-config.json +# keep these +!**/.gitignore +!/.commitlintrc.js !/.eslintrc.js -!/.eslintrc.local.json +!/.eslintrc.local.* !/.gitattributes +!/.github/ !/.gitignore !/.licensee.json !/.mailmap !/.npmrc +!/.release-please-manifest.json !/AUTHORS -!/CHANGELOG.md +!/bin/ +!/CHANGELOG* +!/changelogs/ +!/CODE_OF_CONDUCT.md !/configure !/CONTRIBUTING.md +!/DEPENDENCIES.md +!/docs/ !/index.js -!/LICENSE +!/lib/ +!/LICENSE* !/make.bat !/Makefile +!/map.js +!/node_modules/ +/node_modules/.bin/ +/node_modules/.cache/ !/package-lock.json !/package.json -!/README.md +!/README* +!/release-please-config.json +!/scripts/ !/SECURITY.md -!/DEPENDENCIES.md +!/tap-snapshots/ +!/test/ +!/docs/ +!/smoke-tests/ +!/workspaces/ +/workspaces/* +!/workspaces/arborist/ +!/workspaces/libnpmaccess/ +!/workspaces/libnpmdiff/ +!/workspaces/libnpmexec/ +!/workspaces/libnpmfund/ +!/workspaces/libnpmhook/ +!/workspaces/libnpmorg/ +!/workspaces/libnpmpack/ +!/workspaces/libnpmpublish/ +!/workspaces/libnpmsearch/ +!/workspaces/libnpmteam/ +!/workspaces/libnpmversion/ diff --git a/.npmrc b/.npmrc index e69de29bb2d1d..63cd3a3b11d06 100644 --- a/.npmrc +++ b/.npmrc @@ -0,0 +1,3 @@ +; This file is automatically added by @npmcli/template-oss. Do not edit. + +package-lock=true diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000000..167043c29d41d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,7 @@ + + +All interactions in this repo are covered by the [npm Code of +Conduct](https://docs.npmjs.com/policies/conduct) + +The npm cli team may, at its own discretion, moderate, remove, or edit +any interactions such as pull requests, issues, and comments. diff --git a/SECURITY.md b/SECURITY.md index 41b76c24663ed..a93106d0cb896 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1 +1,3 @@ + + Please send vulnerability reports through [hackerone](https://hackerone.com/github). diff --git a/docs/.gitignore b/docs/.gitignore index 2231d46ac2b98..c09c2f4a26d85 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -4,20 +4,20 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* !/content/ +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/nav.yml !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/docs/package.json b/docs/package.json index 7e9c4038c0a75..768c7318e4cec 100644 --- a/docs/package.json +++ b/docs/package.json @@ -7,10 +7,10 @@ "lint": "eslint \"**/*.js\"", "postlint": "template-oss-check", "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", + "lintfix": "node .. run lint -- --fix", "snap": "tap", "test": "tap", - "posttest": "npm run lint" + "posttest": "node .. run lint" }, "repository": { "type": "git", @@ -39,14 +39,18 @@ "nav.yml" ], "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "tap": { "statements": 81, "branches": 72, "functions": 75, "lines": 81, - "timeout": 600 + "timeout": 600, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", diff --git a/package-lock.json b/package-lock.json index ecf6ac60477c2..2fabe79b6bbf4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -199,7 +199,7 @@ "yaml": "^1.10.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@actions/core": { diff --git a/package.json b/package.json index f5441bea2f76b..a9e872d7253c6 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ "workspaces/*" ], "files": [ + "bin/", + "lib/", "index.js", - "bin", "docs/content/**/*.md", "docs/output/**/*.html", - "lib", "man" ], "keywords": [ @@ -26,10 +26,10 @@ "publishtest": false }, "homepage": "https://docs.npmjs.com/", - "author": "Isaac Z. Schlueter (http://blog.izs.me)", + "author": "GitHub Inc.", "repository": { "type": "git", - "url": "https://github.com/npm/cli" + "url": "https://github.com/npm/cli.git" }, "bugs": { "url": "https://github.com/npm/cli/issues" @@ -221,16 +221,16 @@ "authors": "bash scripts/update-authors.sh", "licenses": "licensee --production --errors-only", "test": "tap", - "test-all": "npm run test --if-present --workspaces --include-workspace-root", + "test-all": "node . run test -ws -iwr --if-present", "snap": "tap", "postsnap": "make -s docs", "test:nocleanup": "NO_TEST_CLEANUP=1 node . run test --", - "sudotest": "sudo node . run test --", + "sudotest": "sudo node . run run test --", "sudotest:nocleanup": "sudo NO_TEST_CLEANUP=1 node . run test --", - "posttest": "npm run lint", + "posttest": "node . run lint", "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", - "lint-all": "npm run lint --if-present --workspaces --include-workspace-root", + "lintfix": "node . run lint -- --fix", + "lint-all": "node . run lint -ws -iwr --if-present", "prelint": "rimraf test/npm_cache*", "resetdeps": "bash scripts/resetdeps.sh", "rp-pull-request": "node . run authors && node scripts/release-manager.js", @@ -245,13 +245,19 @@ "files": "test/{lib,bin,index.js}", "timeout": 600, "nyc-arg": [ + "--exclude", + "docs/**", + "--exclude", + "smoke-tests/**", "--exclude", "workspaces/**", "--exclude", "tap-snapshots/**" - ] + ], + "test-ignore": "^(docs|smoke-tests|workspaces)/**" }, "templateOSS": { + "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "./scripts/template-oss/root.js" }, diff --git a/smoke-tests/.gitignore b/smoke-tests/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/smoke-tests/.gitignore +++ b/smoke-tests/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/smoke-tests/package.json b/smoke-tests/package.json index 59f78602ae09d..829d81952b2d9 100644 --- a/smoke-tests/package.json +++ b/smoke-tests/package.json @@ -7,10 +7,10 @@ "lint": "eslint \"**/*.js\"", "postlint": "template-oss-check", "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", + "lintfix": "node .. run lint -- --fix", "snap": "tap", "test": "tap", - "posttest": "npm run lint" + "posttest": "node .. run lint" }, "repository": { "type": "git", @@ -36,7 +36,11 @@ "tap": { "no-coverage": true, "timeout": 300, - "files": "test/index.js" + "files": "test/index.js", + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "files": [ "bin/", diff --git a/workspaces/arborist/.gitignore b/workspaces/arborist/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/arborist/.gitignore +++ b/workspaces/arborist/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index b9c3d4320a43b..4c685676da09a 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -52,13 +52,13 @@ }, "scripts": { "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "snap": "tap", "postsnap": "npm run lintfix", "test-proxy": "ARBORIST_TEST_PROXY=1 tap --snapshot", "eslint": "eslint", "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "benchmark": "node scripts/benchmark.js", "benchclean": "rm -rf scripts/benchmark/*/", "npmclilint": "npmcli-lint", @@ -93,7 +93,11 @@ "--no-warnings", "--no-deprecation" ], - "timeout": "360" + "timeout": "360", + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/workspaces/libnpmaccess/.gitignore b/workspaces/libnpmaccess/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmaccess/.gitignore +++ b/workspaces/libnpmaccess/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index faafec2f2278f..90370d67d9b95 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -9,9 +9,9 @@ "lint": "eslint \"**/*.js\"", "test": "tap", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "snap": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "template-oss-apply": "template-oss-apply --force" }, "devDependencies": { @@ -42,5 +42,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmdiff/.gitignore b/workspaces/libnpmdiff/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmdiff/.gitignore +++ b/workspaces/libnpmdiff/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 80f020ccfc468..cdc9191064f32 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -34,9 +34,9 @@ "scripts": { "eslint": "eslint", "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "snap": "tap", "postlint": "template-oss-check", "template-oss-apply": "template-oss-apply --force" @@ -60,5 +60,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmexec/.gitignore b/workspaces/libnpmexec/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmexec/.gitignore +++ b/workspaces/libnpmexec/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 01cf528953942..3c91e89dc34b0 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -34,16 +34,20 @@ "license": "ISC", "scripts": { "lint": "eslint \"**/*.js\"", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "test": "tap", "snap": "tap", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "template-oss-apply": "template-oss-apply --force" }, "tap": { "color": true, - "files": "test/*.js" + "files": "test/*.js", + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", diff --git a/workspaces/libnpmfund/.gitignore b/workspaces/libnpmfund/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmfund/.gitignore +++ b/workspaces/libnpmfund/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 98f6acda1b1de..f6c2406153723 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -33,8 +33,8 @@ "scripts": { "eslint": "eslint", "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", - "posttest": "npm run lint", + "lintfix": "node ../.. run lint -- --fix", + "posttest": "node ../.. run lint", "test": "tap", "snap": "tap", "postlint": "template-oss-check", @@ -55,5 +55,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmhook/.gitignore b/workspaces/libnpmhook/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmhook/.gitignore +++ b/workspaces/libnpmhook/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmhook/package.json b/workspaces/libnpmhook/package.json index a2bc28ad46b1b..ee4b535ea14fd 100644 --- a/workspaces/libnpmhook/package.json +++ b/workspaces/libnpmhook/package.json @@ -13,9 +13,9 @@ "test": "tap", "lint": "eslint \"**/*.js\"", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "snap": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "template-oss-apply": "template-oss-apply --force" }, "repository": { @@ -48,5 +48,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmorg/.gitignore b/workspaces/libnpmorg/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmorg/.gitignore +++ b/workspaces/libnpmorg/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmorg/package.json b/workspaces/libnpmorg/package.json index f63ab47e8c65f..23f3a5c8438dd 100644 --- a/workspaces/libnpmorg/package.json +++ b/workspaces/libnpmorg/package.json @@ -16,9 +16,9 @@ "scripts": { "lint": "eslint \"**/*.js\"", "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "snap": "tap", "template-oss-apply": "template-oss-apply --force" }, @@ -51,5 +51,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmpack/.gitignore b/workspaces/libnpmpack/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmpack/.gitignore +++ b/workspaces/libnpmpack/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 5cd9deb9b4b7b..a41236feb4d8e 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -15,9 +15,9 @@ "scripts": { "lint": "eslint \"**/*.js\"", "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "snap": "tap", "template-oss-apply": "template-oss-apply --force" }, @@ -46,5 +46,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmpublish/.gitignore b/workspaces/libnpmpublish/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmpublish/.gitignore +++ b/workspaces/libnpmpublish/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 6bd608a55428e..cfccf0131b291 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -16,9 +16,9 @@ "scripts": { "eslint": "eslint", "lint": "eslint \"**/*.js\"", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "postlint": "template-oss-check", "snap": "tap", "template-oss-apply": "template-oss-apply --force" @@ -52,5 +52,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmsearch/.gitignore b/workspaces/libnpmsearch/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmsearch/.gitignore +++ b/workspaces/libnpmsearch/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmsearch/package.json b/workspaces/libnpmsearch/package.json index d90d7beac2608..2a8b7a0ef7520 100644 --- a/workspaces/libnpmsearch/package.json +++ b/workspaces/libnpmsearch/package.json @@ -16,11 +16,11 @@ ], "license": "ISC", "scripts": { - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "test": "tap", "lint": "eslint \"**/*.js\"", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "snap": "tap", "template-oss-apply": "template-oss-apply --force" }, @@ -47,5 +47,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmteam/.gitignore b/workspaces/libnpmteam/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmteam/.gitignore +++ b/workspaces/libnpmteam/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmteam/package.json b/workspaces/libnpmteam/package.json index ef1e78fc22d36..ea859f4900cce 100644 --- a/workspaces/libnpmteam/package.json +++ b/workspaces/libnpmteam/package.json @@ -8,9 +8,9 @@ "scripts": { "lint": "eslint \"**/*.js\"", "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "snap": "tap", "template-oss-apply": "template-oss-apply --force" }, @@ -41,5 +41,11 @@ "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", "version": "4.3.2", "content": "../../scripts/template-oss/index.js" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/workspaces/libnpmversion/.gitignore b/workspaces/libnpmversion/.gitignore index 617e50ca05288..79af2bfcaa4d8 100644 --- a/workspaces/libnpmversion/.gitignore +++ b/workspaces/libnpmversion/.gitignore @@ -4,18 +4,18 @@ /* # keep these -!/.eslintrc.local.* !**/.gitignore -!/docs/ -!/tap-snapshots/ -!/test/ -!/map.js -!/scripts/ -!/README* -!/LICENSE* -!/CHANGELOG* !/.eslintrc.js +!/.eslintrc.local.* !/.gitignore !/bin/ +!/CHANGELOG* +!/docs/ !/lib/ +!/LICENSE* +!/map.js !/package.json +!/README* +!/scripts/ +!/tap-snapshots/ +!/test/ diff --git a/workspaces/libnpmversion/package.json b/workspaces/libnpmversion/package.json index ed3082b918220..83aaf8ab87176 100644 --- a/workspaces/libnpmversion/package.json +++ b/workspaces/libnpmversion/package.json @@ -17,14 +17,18 @@ "scripts": { "lint": "eslint \"**/*.js\"", "test": "tap", - "posttest": "npm run lint", + "posttest": "node ../.. run lint", "snap": "tap", "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", + "lintfix": "node ../.. run lint -- --fix", "template-oss-apply": "template-oss-apply --force" }, "tap": { - "coverage-map": "map.js" + "coverage-map": "map.js", + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", From 314311c61b8f341715c168199d52976ee3237077 Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 21 Sep 2022 13:07:30 -0700 Subject: [PATCH 13/40] feat: separate login/adduser, remove auth types (#5550) The difference between `adduser` and `login` depends on the `auth-type`. - `web`: the POST to `/-/v1/login` contains a `{ create: true }` value in its payload for `adduser` - `legacy` the `PUT` request to `/-/user/org.couchdb.user:${username}` contains an `email` value in its payload for `adduser`. BREAKING CHANGE: `login`, `adduser`, and `auth-type` changes - This removes all `auth-type` configs except `web` and `legacy`. - `login` and `adduser` are now separate commands that send different data to the registry. - `auth-type` config values `web` and `legacy` only try their respective methods, npm no longer tries them all and waits to see which one doesn't fail. --- docs/content/commands/npm-adduser.md | 27 +- docs/content/commands/npm-login.md | 110 +++++ docs/content/using-npm/config.md | 30 +- docs/nav.yml | 3 + lib/auth/legacy.js | 100 ---- lib/auth/oauth.js | 8 - lib/auth/saml.js | 8 - lib/auth/sso.js | 81 ---- lib/commands/adduser.js | 65 +-- lib/commands/login.js | 53 +++ lib/utils/auth.js | 78 ++++ lib/utils/cmd-list.js | 1 - lib/utils/config/definitions.js | 45 +- lib/utils/otplease.js | 6 +- .../test/lib/commands/adduser.js.test.cjs | 17 - .../test/lib/commands/completion.js.test.cjs | 1 - .../test/lib/commands/config.js.test.cjs | 4 - .../test/lib/load-all-commands.js.test.cjs | 16 +- tap-snapshots/test/lib/npm.js.test.cjs | 16 +- .../test/lib/utils/cmd-list.js.test.cjs | 1 - .../lib/utils/config/definitions.js.test.cjs | 30 +- .../lib/utils/config/describe-all.js.test.cjs | 30 +- test/fixtures/mock-registry.js | 57 ++- test/lib/auth/legacy.js | 429 ------------------ test/lib/auth/oauth.js | 28 -- test/lib/auth/saml.js | 28 -- test/lib/auth/sso.js | 236 ---------- test/lib/commands/adduser.js | 315 +++++++------ test/lib/commands/login.js | 151 ++++++ 29 files changed, 645 insertions(+), 1329 deletions(-) create mode 100644 docs/content/commands/npm-login.md delete mode 100644 lib/auth/legacy.js delete mode 100644 lib/auth/oauth.js delete mode 100644 lib/auth/saml.js delete mode 100644 lib/auth/sso.js create mode 100644 lib/commands/login.js create mode 100644 lib/utils/auth.js delete mode 100644 tap-snapshots/test/lib/commands/adduser.js.test.cjs delete mode 100644 test/lib/auth/legacy.js delete mode 100644 test/lib/auth/oauth.js delete mode 100644 test/lib/auth/saml.js delete mode 100644 test/lib/auth/sso.js create mode 100644 test/lib/commands/login.js diff --git a/docs/content/commands/npm-adduser.md b/docs/content/commands/npm-adduser.md index 700aecb2255b2..91f1195afbbee 100644 --- a/docs/content/commands/npm-adduser.md +++ b/docs/content/commands/npm-adduser.md @@ -13,7 +13,7 @@ description: Add a registry user account ```bash npm adduser -aliases: login, add-user +alias: add-user ``` @@ -25,22 +25,12 @@ Note: This command is unaware of workspaces. ### Description -Create or verify a user named `` in the specified registry, and -save the credentials to the `.npmrc` file. If no registry is specified, -the default registry will be used (see [`config`](/using-npm/config)). +Create a new user in the specified registry, and save the credentials to +the `.npmrc` file. If no registry is specified, the default registry +will be used (see [`config`](/using-npm/config)). -The username, password, and email are read in from prompts. - -To reset your password, go to - -To change your email address, go to - -You may use this command multiple times with the same user account to -authorize on a new machine. When authenticating on a new machine, -the username, password and email address must all match with -your existing record. - -`npm login` is an alias to `adduser` and behaves exactly the same way. +When using `legacy` for your `auth-type`, the username, password, and +email are read in from prompts. ### Configuration @@ -93,10 +83,7 @@ npm init --scope=@foo --yes #### `auth-type` * Default: "legacy" -* Type: "legacy", "web", "sso", "saml", "oauth", or "webauthn" - -NOTE: auth-type values "sso", "saml", "oauth", and "webauthn" will be -removed in a future version. +* Type: "legacy" or "web" What authentication strategy to use with `login`. diff --git a/docs/content/commands/npm-login.md b/docs/content/commands/npm-login.md new file mode 100644 index 0000000000000..4f821c903b168 --- /dev/null +++ b/docs/content/commands/npm-login.md @@ -0,0 +1,110 @@ +--- +title: npm-login +section: 1 +description: Login to a registry user account +--- + +### Synopsis + + + + + +```bash +npm login +``` + + + + + + +Note: This command is unaware of workspaces. + +### Description + +Verify a user in the specified registry, and save the credentials to the +`.npmrc` file. If no registry is specified, the default registry will be +used (see [`config`](/using-npm/config)). + +When using `legacy` for your `auth-type`, the username and password, are +read in from prompts. + +To reset your password, go to + +To change your email address, go to + +You may use this command multiple times with the same user account to +authorize on a new machine. When authenticating on a new machine, +the username, password and email address must all match with +your existing record. + +### Configuration + + + + +#### `registry` + +* Default: "https://registry.npmjs.org/" +* Type: URL + +The base URL of the npm registry. + + + + +#### `scope` + +* Default: the scope of the current project, if any, or "" +* Type: String + +Associate an operation with a scope for a scoped registry. + +Useful when logging in to or out of a private registry: + +``` +# log in, linking the scope to the custom registry +npm login --scope=@mycorp --registry=https://registry.mycorp.com + +# log out, removing the link and the auth token +npm logout --scope=@mycorp +``` + +This will cause `@mycorp` to be mapped to the registry for future +installation of packages specified according to the pattern +`@mycorp/package`. + +This will also cause `npm init` to create a scoped package. + +``` +# accept all defaults, and create a package named "@foo/whatever", +# instead of just named "whatever" +npm init --scope=@foo --yes +``` + + + + + +#### `auth-type` + +* Default: "legacy" +* Type: "legacy" or "web" + +What authentication strategy to use with `login`. + + + + + + +### See Also + +* [npm registry](/using-npm/registry) +* [npm config](/commands/npm-config) +* [npmrc](/configuring-npm/npmrc) +* [npm owner](/commands/npm-owner) +* [npm whoami](/commands/npm-whoami) +* [npm token](/commands/npm-token) +* [npm profile](/commands/npm-profile) diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index e6a7231861ba0..2b704bda2df4e 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -218,10 +218,7 @@ exit code. #### `auth-type` * Default: "legacy" -* Type: "legacy", "web", "sso", "saml", "oauth", or "webauthn" - -NOTE: auth-type values "sso", "saml", "oauth", and "webauthn" will be -removed in a future version. +* Type: "legacy" or "web" What authentication strategy to use with `login`. @@ -2084,31 +2081,6 @@ Alias for --package-lock -#### `sso-poll-frequency` - -* Default: 500 -* Type: Number -* DEPRECATED: The --auth-type method of SSO/SAML/OAuth will be removed in a - future version of npm in favor of web-based login. - -When used with SSO-enabled `auth-type`s, configures how regularly the -registry should be polled while the user is completing authentication. - - - - -#### `sso-type` - -* Default: "oauth" -* Type: null, "oauth", or "saml" -* DEPRECATED: The --auth-type method of SSO/SAML/OAuth will be removed in a - future version of npm in favor of web-based login. - -If `--auth-type=sso`, the type of SSO type to use. - - - - #### `tmp` * Default: The value returned by the Node.js `os.tmpdir()` method diff --git a/docs/nav.yml b/docs/nav.yml index 565537054a0d7..43051e4e9c3f1 100644 --- a/docs/nav.yml +++ b/docs/nav.yml @@ -96,6 +96,9 @@ - title: npm link url: /commands/npm-link description: Symlink a package folder + - title: npm login + url: /commands/npm-login + description: Login to a registry user account - title: npm logout url: /commands/npm-logout description: Log out of the registry diff --git a/lib/auth/legacy.js b/lib/auth/legacy.js deleted file mode 100644 index 9aed12f3926fb..0000000000000 --- a/lib/auth/legacy.js +++ /dev/null @@ -1,100 +0,0 @@ -const profile = require('npm-profile') -const log = require('../utils/log-shim') -const openUrlPrompt = require('../utils/open-url-prompt.js') -const read = require('../utils/read-user-info.js') - -const loginPrompter = async (creds) => { - creds.username = await read.username('Username:', creds.username) - creds.password = await read.password('Password:', creds.password) - creds.email = await read.email('Email: (this IS public) ', creds.email) - - return creds -} - -const login = async (npm, opts) => { - let res - - const requestOTP = async () => { - const otp = await read.otp( - 'Enter one-time password: ' - ) - - return profile.loginCouch( - opts.creds.username, - opts.creds.password, - { ...opts, otp } - ) - } - - const addNewUser = async () => { - let newUser - - try { - newUser = await profile.adduserCouch( - opts.creds.username, - opts.creds.email, - opts.creds.password, - opts - ) - } catch (err) { - if (err.code === 'EOTP') { - newUser = await requestOTP() - } else { - throw err - } - } - - return newUser - } - - const openerPromise = (url, emitter) => - openUrlPrompt( - npm, - url, - 'Authenticate your account at', - 'Press ENTER to open in the browser...', - emitter - ) - - try { - res = await profile.login(openerPromise, loginPrompter, opts) - } catch (err) { - const needsMoreInfo = !(opts && - opts.creds && - opts.creds.username && - opts.creds.password && - opts.creds.email) - if (err.code === 'EOTP') { - res = await requestOTP() - } else if (needsMoreInfo) { - throw err - } else { - // TODO: maybe this needs to check for err.code === 'E400' instead? - res = await addNewUser() - } - } - - const newCreds = {} - if (res && res.token) { - newCreds.token = res.token - } else { - newCreds.username = opts.creds.username - newCreds.password = opts.creds.password - newCreds.email = opts.creds.email - newCreds.alwaysAuth = opts.creds.alwaysAuth - } - - const usermsg = opts.creds.username ? ` user ${opts.creds.username}` : '' - const scopeMessage = opts.scope ? ` to scope ${opts.scope}` : '' - const userout = opts.creds.username ? ` as ${opts.creds.username}` : '' - const message = `Logged in${userout}${scopeMessage} on ${opts.registry}.` - - log.info('login', `Authorized${usermsg}`) - - return { - message, - newCreds, - } -} - -module.exports = login diff --git a/lib/auth/oauth.js b/lib/auth/oauth.js deleted file mode 100644 index 99c2ca0ca04b7..0000000000000 --- a/lib/auth/oauth.js +++ /dev/null @@ -1,8 +0,0 @@ -const sso = require('./sso.js') - -const login = (npm, opts) => { - npm.config.set('sso-type', 'oauth') - return sso(npm, opts) -} - -module.exports = login diff --git a/lib/auth/saml.js b/lib/auth/saml.js deleted file mode 100644 index 3dd31ca013f52..0000000000000 --- a/lib/auth/saml.js +++ /dev/null @@ -1,8 +0,0 @@ -const sso = require('./sso.js') - -const login = (npm, opts) => { - npm.config.set('sso-type', 'saml') - return sso(npm, opts) -} - -module.exports = login diff --git a/lib/auth/sso.js b/lib/auth/sso.js deleted file mode 100644 index 621ead5d21b65..0000000000000 --- a/lib/auth/sso.js +++ /dev/null @@ -1,81 +0,0 @@ -// XXX: To date, npm Enterprise Legacy is the only system that ever -// implemented support for this type of login. A better way to do -// SSO is to use the WebLogin type of login supported by the npm-login -// module. This more forward-looking login style is, ironically, -// supported by the '--auth-type=legacy' type of login. -// When and if npm Enterprise Legacy is no longer supported by the npm -// CLI, we can remove this, and fold the lib/auth/legacy.js back into -// lib/adduser.js - -const profile = require('npm-profile') -const npmFetch = require('npm-registry-fetch') -const log = require('../utils/log-shim') -const openUrl = require('../utils/open-url.js') -const otplease = require('../utils/otplease.js') - -const pollForSession = ({ registry, token, opts }) => { - log.info('adduser', 'Polling for validated SSO session') - return npmFetch.json( - '/-/whoami', { ...opts, registry, forceAuth: { token } } - ).then( - ({ username }) => username, - err => { - if (err.code === 'E401') { - return sleep(opts.ssoPollFrequency).then(() => { - return pollForSession({ registry, token, opts }) - }) - } else { - throw err - } - } - ) -} - -function sleep (time) { - return new Promise((resolve) => setTimeout(resolve, time)) -} - -const login = async (npm, { creds, registry, scope }) => { - const opts = { ...npm.flatOptions, creds, registry, scope } - const { ssoType } = opts - - if (!ssoType) { - throw new Error('Missing option: sso-type') - } - - // We're reusing the legacy login endpoint, so we need some dummy - // stuff here to pass validation. They're never used. - const auth = { - username: 'npm_' + ssoType + '_auth_dummy_user', - password: 'placeholder', - email: 'support@npmjs.com', - authType: ssoType, - } - - const { token, sso } = await otplease(npm, opts, - opts => profile.loginCouch(auth.username, auth.password, opts) - ) - - if (!token) { - throw new Error('no SSO token returned') - } - if (!sso) { - throw new Error('no SSO URL returned by services') - } - - await openUrl(npm, sso, 'to complete your login please visit') - - const username = await pollForSession({ registry, token, opts }) - - log.info('adduser', `Authorized user ${username}`) - - const scopeMessage = scope ? ' to scope ' + scope : '' - const message = `Logged in as ${username}${scopeMessage} on ${registry}.` - - return { - message, - newCreds: { token }, - } -} - -module.exports = login diff --git a/lib/commands/adduser.js b/lib/commands/adduser.js index 2853269ef3dee..1e92b35f4a662 100644 --- a/lib/commands/adduser.js +++ b/lib/commands/adduser.js @@ -1,14 +1,8 @@ const log = require('../utils/log-shim.js') const replaceInfo = require('../utils/replace-info.js') +const auth = require('../utils/auth.js') + const BaseCommand = require('../base-command.js') -const authTypes = { - legacy: require('../auth/legacy.js'), - web: require('../auth/legacy.js'), - webauthn: require('../auth/legacy.js'), - oauth: require('../auth/oauth.js'), - saml: require('../auth/saml.js'), - sso: require('../auth/sso.js'), -} class AddUser extends BaseCommand { static description = 'Add a registry user account' @@ -22,63 +16,38 @@ class AddUser extends BaseCommand { static ignoreImplicitWorkspace = true async exec (args) { - const { scope } = this.npm.flatOptions - const registry = this.getRegistry(this.npm.flatOptions) - const auth = this.getAuthType(this.npm.flatOptions) - const creds = this.npm.config.getCredentialsByURI(registry) - - log.disableProgress() - - log.warn('adduser', - '`adduser` will be split into `login` and `register` in a future version.' - + ' `adduser` will become an alias of `register`.' - + ' `login` (currently an alias) will become its own command.') - log.notice('', `Log in on ${replaceInfo(registry)}`) - - const { message, newCreds } = await auth(this.npm, { - ...this.npm.flatOptions, - creds, - registry, - scope, - }) - - await this.updateConfig({ - newCreds, - registry, - scope, - }) - - this.npm.output(message) - } + const scope = this.npm.config.get('scope') + let registry = this.npm.config.get('registry') - getRegistry ({ scope, registry }) { if (scope) { const scopedRegistry = this.npm.config.get(`${scope}:registry`) const cliRegistry = this.npm.config.get('registry', 'cli') if (scopedRegistry && !cliRegistry) { - return scopedRegistry + registry = scopedRegistry } } - return registry - } - getAuthType ({ authType }) { - const type = authTypes[authType] + const creds = this.npm.config.getCredentialsByURI(registry) - if (!type) { - throw new Error('no such auth module') - } + log.disableProgress() + log.notice('', `Log in on ${replaceInfo(registry)}`) - return type - } + const { message, newCreds } = await auth.adduser(this.npm, { + ...this.npm.flatOptions, + creds, + registry, + }) - async updateConfig ({ newCreds, registry, scope }) { this.npm.config.delete('_token', 'user') // prevent legacy pollution this.npm.config.setCredentialsByURI(registry, newCreds) + if (scope) { this.npm.config.set(scope + ':registry', registry, 'user') } + await this.npm.config.save('user') + + this.npm.output(message) } } module.exports = AddUser diff --git a/lib/commands/login.js b/lib/commands/login.js new file mode 100644 index 0000000000000..7f6898d00ba93 --- /dev/null +++ b/lib/commands/login.js @@ -0,0 +1,53 @@ +const log = require('../utils/log-shim.js') +const replaceInfo = require('../utils/replace-info.js') +const auth = require('../utils/auth.js') + +const BaseCommand = require('../base-command.js') + +class Login extends BaseCommand { + static description = 'Login to a registry user account' + static name = 'login' + static params = [ + 'registry', + 'scope', + 'auth-type', + ] + + static ignoreImplicitWorkspace = true + + async exec (args) { + const scope = this.npm.config.get('scope') + let registry = this.npm.config.get('registry') + + if (scope) { + const scopedRegistry = this.npm.config.get(`${scope}:registry`) + const cliRegistry = this.npm.config.get('registry', 'cli') + if (scopedRegistry && !cliRegistry) { + registry = scopedRegistry + } + } + + const creds = this.npm.config.getCredentialsByURI(registry) + + log.disableProgress() + log.notice('', `Log in on ${replaceInfo(registry)}`) + + const { message, newCreds } = await auth.login(this.npm, { + ...this.npm.flatOptions, + creds, + registry, + }) + + this.npm.config.delete('_token', 'user') // prevent legacy pollution + this.npm.config.setCredentialsByURI(registry, newCreds) + + if (scope) { + this.npm.config.set(scope + ':registry', registry, 'user') + } + + await this.npm.config.save('user') + + this.npm.output(message) + } +} +module.exports = Login diff --git a/lib/utils/auth.js b/lib/utils/auth.js new file mode 100644 index 0000000000000..8b9125a1c3ef0 --- /dev/null +++ b/lib/utils/auth.js @@ -0,0 +1,78 @@ +const profile = require('npm-profile') +const log = require('../utils/log-shim') +const openUrlPrompt = require('../utils/open-url-prompt.js') +const read = require('../utils/read-user-info.js') +const otplease = require('../utils/otplease.js') + +const adduser = async (npm, { creds, ...opts }) => { + const authType = npm.config.get('auth-type') + let res + if (authType === 'web') { + res = await profile.adduserWeb((url, emitter) => { + openUrlPrompt( + npm, + url, + 'Create your account at', + 'Press ENTER to open in the browser...', + emitter + ) + }, opts) + } else { + const username = await read.username('Username:', creds.username) + const password = await read.password('Password:', creds.password) + const email = await read.email('Email: (this IS public) ', creds.email) + // npm registry quirk: If you "add" an existing user with their current + // password, it's effectively a login, and if that account has otp you'll + // be prompted for it. + res = await otplease(npm, opts, (reqOpts) => + profile.adduserCouch(username, email, password, opts) + ) + } + + // We don't know the username if it was a web login, all we can reliably log is scope and registry + const message = `Logged in${opts.scope ? ` to scope ${opts.scope}` : ''} on ${opts.registry}.` + + log.info('adduser', message) + + return { + message, + newCreds: { token: res.token }, + } +} + +const login = async (npm, { creds, ...opts }) => { + const authType = npm.config.get('auth-type') + let res + if (authType === 'web') { + res = await profile.loginWeb((url, emitter) => { + openUrlPrompt( + npm, + url, + 'Login at', + 'Press ENTER to open in the browser...', + emitter + ) + }, opts) + } else { + const username = await read.username('Username:', creds.username) + const password = await read.password('Password:', creds.password) + res = await otplease(npm, opts, (reqOpts) => + profile.loginCouch(username, password, reqOpts) + ) + } + + // We don't know the username if it was a web login, all we can reliably log is scope and registry + const message = `Logged in${opts.scope ? ` to scope ${opts.scope}` : ''} on ${opts.registry}.` + + log.info('login', message) + + return { + message, + newCreds: { token: res.token }, + } +} + +module.exports = { + adduser, + login, +} diff --git a/lib/utils/cmd-list.js b/lib/utils/cmd-list.js index c712ece0de2ac..6fffde32a5ee2 100644 --- a/lib/utils/cmd-list.js +++ b/lib/utils/cmd-list.js @@ -4,7 +4,6 @@ const abbrev = require('abbrev') const aliases = { // aliases - login: 'adduser', author: 'owner', home: 'docs', issues: 'bugs', diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index a76484b5228f5..5f10bd5e38898 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -3,7 +3,6 @@ module.exports = definitions const Definition = require('./definition.js') -const log = require('../log-shim') const { version: npmVersion } = require('../../../package.json') const ciDetect = require('@npmcli/ci-detect') const ciName = ciDetect() @@ -239,24 +238,11 @@ define('audit-level', { define('auth-type', { default: 'legacy', - type: ['legacy', 'web', 'sso', 'saml', 'oauth', 'webauthn'], - // deprecation in description rather than field, because not every value - // is deprecated + type: ['legacy', 'web'], description: ` - NOTE: auth-type values "sso", "saml", "oauth", and "webauthn" will be - removed in a future version. - What authentication strategy to use with \`login\`. `, - flatten (key, obj, flatOptions) { - flatOptions.authType = obj[key] - if (obj[key] === 'sso') { - // no need to deprecate saml/oauth here, as sso-type will be set by these in - // lib/auth/ and is deprecated already - log.warn('config', - '--auth-type=sso is will be removed in a future version.') - } - }, + flatten, }) define('before', { @@ -2004,33 +1990,6 @@ define('sign-git-tag', { flatten, }) -define('sso-poll-frequency', { - default: 500, - type: Number, - deprecated: ` - The --auth-type method of SSO/SAML/OAuth will be removed in a future - version of npm in favor of web-based login. - `, - description: ` - When used with SSO-enabled \`auth-type\`s, configures how regularly the - registry should be polled while the user is completing authentication. - `, - flatten, -}) - -define('sso-type', { - default: 'oauth', - type: [null, 'oauth', 'saml'], - deprecated: ` - The --auth-type method of SSO/SAML/OAuth will be removed in a future - version of npm in favor of web-based login. - `, - description: ` - If \`--auth-type=sso\`, the type of SSO type to use. - `, - flatten, -}) - define('strict-peer-deps', { default: false, type: Boolean, diff --git a/lib/utils/otplease.js b/lib/utils/otplease.js index e40ef57730c30..b4aa167469255 100644 --- a/lib/utils/otplease.js +++ b/lib/utils/otplease.js @@ -35,10 +35,10 @@ async function otplease (npm, opts, fn) { } function isWebOTP (err) { - if (!err.code === 'EOTP' || !err.body) { - return false + if (err.code === 'EOTP' && err.body) { + return err.body.authUrl && err.body.doneUrl } - return err.body.authUrl && err.body.doneUrl + return false } function isClassicOTP (err) { diff --git a/tap-snapshots/test/lib/commands/adduser.js.test.cjs b/tap-snapshots/test/lib/commands/adduser.js.test.cjs deleted file mode 100644 index ba27a6a781ab0..0000000000000 --- a/tap-snapshots/test/lib/commands/adduser.js.test.cjs +++ /dev/null @@ -1,17 +0,0 @@ -/* IMPORTANT - * This snapshot file is auto-generated, but designed for humans. - * It should be checked into source control and tracked carefully. - * Re-generate by setting TAP_SNAPSHOT=1 and running tests. - * Make sure to inspect the output below. Do not ignore changes! - */ -'use strict' -exports[`test/lib/commands/adduser.js TAP auth-type sso warning > warning 1`] = ` -Object { - "warn": Array [ - Array [ - "config", - "--auth-type=sso is will be removed in a future version.", - ], - ], -} -` diff --git a/tap-snapshots/test/lib/commands/completion.js.test.cjs b/tap-snapshots/test/lib/commands/completion.js.test.cjs index 85a883bd58b26..3e7125bc33ba9 100644 --- a/tap-snapshots/test/lib/commands/completion.js.test.cjs +++ b/tap-snapshots/test/lib/commands/completion.js.test.cjs @@ -109,7 +109,6 @@ Array [ version view whoami - login author home issues diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index 6ed14ae5b2546..043dccd9ceab4 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -140,8 +140,6 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna "shrinkwrap": true, "sign-git-commit": false, "sign-git-tag": false, - "sso-poll-frequency": 500, - "sso-type": "oauth", "strict-peer-deps": false, "strict-ssl": true, "tag": "latest", @@ -297,8 +295,6 @@ shell = "{SHELL}" shrinkwrap = true sign-git-commit = false sign-git-tag = false -sso-poll-frequency = 500 -sso-type = "oauth" strict-peer-deps = false strict-ssl = true tag = "latest" diff --git a/tap-snapshots/test/lib/load-all-commands.js.test.cjs b/tap-snapshots/test/lib/load-all-commands.js.test.cjs index 038121be95435..e3d3d02fc4395 100644 --- a/tap-snapshots/test/lib/load-all-commands.js.test.cjs +++ b/tap-snapshots/test/lib/load-all-commands.js.test.cjs @@ -30,10 +30,9 @@ Usage: npm adduser Options: -[--registry ] [--scope <@scope>] -[--auth-type ] +[--registry ] [--scope <@scope>] [--auth-type ] -aliases: login, add-user +alias: add-user Run "npm help adduser" for more info ` @@ -479,18 +478,15 @@ Run "npm help ll" for more info ` exports[`test/lib/load-all-commands.js TAP load each command login > must match snapshot 1`] = ` -Add a registry user account +Login to a registry user account Usage: -npm adduser +npm login Options: -[--registry ] [--scope <@scope>] -[--auth-type ] - -aliases: login, add-user +[--registry ] [--scope <@scope>] [--auth-type ] -Run "npm help adduser" for more info +Run "npm help login" for more info ` exports[`test/lib/load-all-commands.js TAP load each command logout > must match snapshot 1`] = ` diff --git a/tap-snapshots/test/lib/npm.js.test.cjs b/tap-snapshots/test/lib/npm.js.test.cjs index 1c3dbe39bd4ae..35a5ee4da3e64 100644 --- a/tap-snapshots/test/lib/npm.js.test.cjs +++ b/tap-snapshots/test/lib/npm.js.test.cjs @@ -187,10 +187,9 @@ All commands: npm adduser Options: - [--registry ] [--scope <@scope>] - [--auth-type ] + [--registry ] [--scope <@scope>] [--auth-type ] - aliases: login, add-user + alias: add-user Run "npm help adduser" for more info @@ -568,18 +567,15 @@ All commands: Run "npm help ll" for more info - login Add a registry user account + login Login to a registry user account Usage: - npm adduser + npm login Options: - [--registry ] [--scope <@scope>] - [--auth-type ] + [--registry ] [--scope <@scope>] [--auth-type ] - aliases: login, add-user - - Run "npm help adduser" for more info + Run "npm help login" for more info logout Log out of the registry diff --git a/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs b/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs index e76f890140b8b..574b0855bc456 100644 --- a/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs +++ b/tap-snapshots/test/lib/utils/cmd-list.js.test.cjs @@ -381,7 +381,6 @@ Object { "la": "ll", "list": "ls", "ln": "link", - "login": "adduser", "ogr": "org", "r": "uninstall", "rb": "rebuild", diff --git a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index 6eac545b2ce2d..8eff450e7a926 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -135,8 +135,6 @@ Array [ "shrinkwrap", "sign-git-commit", "sign-git-tag", - "sso-poll-frequency", - "sso-type", "strict-peer-deps", "strict-ssl", "tag", @@ -254,10 +252,7 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for auth- #### \`auth-type\` * Default: "legacy" -* Type: "legacy", "web", "sso", "saml", "oauth", or "webauthn" - -NOTE: auth-type values "sso", "saml", "oauth", and "webauthn" will be -removed in a future version. +* Type: "legacy" or "web" What authentication strategy to use with \`login\`. ` @@ -1697,29 +1692,6 @@ Note that git requires you to have set up GPG keys in your git configs for this to work properly. ` -exports[`test/lib/utils/config/definitions.js TAP > config description for sso-poll-frequency 1`] = ` -#### \`sso-poll-frequency\` - -* Default: 500 -* Type: Number -* DEPRECATED: The --auth-type method of SSO/SAML/OAuth will be removed in a - future version of npm in favor of web-based login. - -When used with SSO-enabled \`auth-type\`s, configures how regularly the -registry should be polled while the user is completing authentication. -` - -exports[`test/lib/utils/config/definitions.js TAP > config description for sso-type 1`] = ` -#### \`sso-type\` - -* Default: "oauth" -* Type: null, "oauth", or "saml" -* DEPRECATED: The --auth-type method of SSO/SAML/OAuth will be removed in a - future version of npm in favor of web-based login. - -If \`--auth-type=sso\`, the type of SSO type to use. -` - exports[`test/lib/utils/config/definitions.js TAP > config description for strict-peer-deps 1`] = ` #### \`strict-peer-deps\` diff --git a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 46910d1282e03..633b2da8e0472 100644 --- a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -91,10 +91,7 @@ exit code. #### \`auth-type\` * Default: "legacy" -* Type: "legacy", "web", "sso", "saml", "oauth", or "webauthn" - -NOTE: auth-type values "sso", "saml", "oauth", and "webauthn" will be -removed in a future version. +* Type: "legacy" or "web" What authentication strategy to use with \`login\`. @@ -1957,31 +1954,6 @@ Alias for --package-lock -#### \`sso-poll-frequency\` - -* Default: 500 -* Type: Number -* DEPRECATED: The --auth-type method of SSO/SAML/OAuth will be removed in a - future version of npm in favor of web-based login. - -When used with SSO-enabled \`auth-type\`s, configures how regularly the -registry should be polled while the user is completing authentication. - - - - -#### \`sso-type\` - -* Default: "oauth" -* Type: null, "oauth", or "saml" -* DEPRECATED: The --auth-type method of SSO/SAML/OAuth will be removed in a - future version of npm in favor of web-based login. - -If \`--auth-type=sso\`, the type of SSO type to use. - - - - #### \`tmp\` * Default: The value returned by the Node.js \`os.tmpdir()\` method diff --git a/test/fixtures/mock-registry.js b/test/fixtures/mock-registry.js index 65d4759627aa6..d978929b6b0d8 100644 --- a/test/fixtures/mock-registry.js +++ b/test/fixtures/mock-registry.js @@ -111,17 +111,12 @@ class MockRegistry { } } - couchlogin ({ username, password, email, otp, token = 'npm_default-test-token' }) { - this.nock = this.nock - .post('/-/v1/login').reply(401, { error: 'You must be logged in to publish packages.' }) - if (otp) { - // TODO otp failure results in a 401 with - // {"ok":false,"error":"failed to authenticate: Could not authenticate ${username}: bad otp"} - } + couchadduser ({ username, email, password, token = 'npm_default-test-token' }) { this.nock = this.nock.put(`/-/user/org.couchdb.user:${username}`, body => { this.#tap.match(body, { _id: `org.couchdb.user:${username}`, name: username, + email, // Sole difference from couchlogin password, type: 'user', roles: [], @@ -131,13 +126,59 @@ class MockRegistry { } return true }).reply(201, { - ok: true, id: 'org.couchdb.user:undefined', rev: '_we_dont_use_revs_any_more', token, }) } + couchlogin ({ username, password, token = 'npm_default-test-token' }) { + this.nock = this.nock.put(`/-/user/org.couchdb.user:${username}`, body => { + this.#tap.match(body, { + _id: `org.couchdb.user:${username}`, + name: username, + password, + type: 'user', + roles: [], + }) + if (!body.date) { + return false + } + return true + }).reply(201, { + id: 'org.couchdb.user:undefined', + rev: '_we_dont_use_revs_any_more', + token, + }) + } + + webadduser ({ username, password, token = 'npm_default-test-token' }) { + const doneUrl = new URL('/npm-cli-test/done', this.#registry).href + const loginUrl = new URL('/npm-cli-test/login', this.#registry).href + this.nock = this.nock + .post('/-/v1/login', body => { + this.#tap.ok(body.create) // Sole difference from weblogin + this.#tap.ok(body.hostname) + return true + }) + .reply(200, { doneUrl, loginUrl }) + .get('/npm-cli-test/done') + .reply(200, { token }) + } + + weblogin ({ token = 'npm_default-test-token' }) { + const doneUrl = new URL('/npm-cli-test/done', this.#registry).href + const loginUrl = new URL('/npm-cli-test/login', this.#registry).href + this.nock = this.nock + .post('/-/v1/login', body => { + this.#tap.ok(body.hostname) + return true + }) + .reply(200, { doneUrl, loginUrl }) + .get('/npm-cli-test/done') + .reply(200, { token }) + } + // team can be a team or a username getPackages ({ team, packages = {}, times = 1 }) { if (team.startsWith('@')) { diff --git a/test/lib/auth/legacy.js b/test/lib/auth/legacy.js deleted file mode 100644 index 39d977d436b5e..0000000000000 --- a/test/lib/auth/legacy.js +++ /dev/null @@ -1,429 +0,0 @@ -const t = require('tap') - -let log = '' - -const token = '24528a24f240' -const profile = {} -const read = {} -const legacy = t.mock('../../../lib/auth/legacy.js', { - 'proc-log': { - info: (...msgs) => { - log += msgs.join(' ') - }, - }, - 'npm-profile': profile, - '../../../lib/utils/open-url-prompt.js': (_npm, url) => { - if (!url) { - throw Object.assign(new Error('failed open url'), { code: 'ERROR' }) - } - }, - '../../../lib/utils/read-user-info.js': read, -}) - -const npm = { - config: { - get: () => null, - }, -} - -t.test('login using username/password with token result', async (t) => { - profile.login = () => { - return { token } - } - - const { - message, - newCreds, - } = await legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - message, - 'Logged in as u on https://registry.npmjs.org/.', - 'should have correct message result' - ) - - t.equal( - log, - 'login Authorized user u', - 'should have correct message result' - ) - - t.same( - newCreds, - { token }, - 'should return expected obj from profile.login' - ) - - log = '' - delete profile.login -}) - -t.test('login using username/password with user info result', async (t) => { - profile.login = () => { - return null - } - - const { - message, - newCreds, - } = await legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - message, - 'Logged in as u on https://registry.npmjs.org/.', - 'should have correct message result' - ) - - t.same( - newCreds, - { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - 'should return used credentials' - ) - - log = '' - delete profile.login -}) - -t.test('login otp requested', async (t) => { - t.plan(5) - - profile.login = () => Promise.reject(Object.assign( - new Error('needs otp'), - { code: 'EOTP' } - )) - profile.loginCouch = (username, password, { otp }) => { - t.equal(username, 'u', 'should use provided username to loginCouch') - t.equal(password, 'p', 'should use provided password to loginCouch') - t.equal(otp, '1234', 'should use provided otp code to loginCouch') - - return { token } - } - read.otp = () => Promise.resolve('1234') - - const { - message, - newCreds, - } = await legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - message, - 'Logged in as u on https://registry.npmjs.org/.', - 'should have correct message result' - ) - - t.same( - newCreds, - { token }, - 'should return token from loginCouch result' - ) - - log = '' - delete profile.login - delete profile.loginCouch - delete read.otp -}) - -t.test('login missing basic credential info', async (t) => { - profile.login = () => Promise.reject(Object.assign( - new Error('missing info'), - { code: 'ERROR' } - )) - - await t.rejects( - legacy(npm, { - creds: { - username: 'u', - password: 'p', - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }), - { code: 'ERROR' }, - 'should throw server response error' - ) - - log = '' - delete profile.login -}) - -t.test('create new user when user not found', async (t) => { - t.plan(6) - - profile.login = () => Promise.reject(Object.assign( - new Error('User does not exist'), - { code: 'ERROR' } - )) - profile.adduserCouch = (username, email, password) => { - t.equal(username, 'u', 'should use provided username to adduserCouch') - t.equal(email, 'u@npmjs.org', 'should use provided email to adduserCouch') - t.equal(password, 'p', 'should use provided password to adduserCouch') - - return { token } - } - - const { - message, - newCreds, - } = await legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - message, - 'Logged in as u on https://registry.npmjs.org/.', - 'should have correct message result' - ) - - t.equal( - log, - 'login Authorized user u', - 'should have correct message result' - ) - - t.same( - newCreds, - { token }, - 'should return expected obj from profile.login' - ) - - log = '' - delete profile.adduserCouch - delete profile.login -}) - -t.test('prompts for user info if required', async (t) => { - t.plan(4) - - profile.login = async (opener, prompt, opts) => { - t.equal(opts.creds.alwaysAuth, true, 'should have refs to creds if any') - await opener('https://registry.npmjs.org/-/v1/login') - const creds = await prompt(opts.creds) - return creds - } - read.username = () => Promise.resolve('foo') - read.password = () => Promise.resolve('pass') - read.email = () => Promise.resolve('foo@npmjs.org') - - const { - message, - newCreds, - } = await legacy(npm, { - creds: { - alwaysAuth: true, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - message, - 'Logged in as foo on https://registry.npmjs.org/.', - 'should have correct message result' - ) - - t.equal( - log, - 'login Authorized user foo', - 'should have correct message result' - ) - - t.same( - newCreds, - { - username: 'foo', - password: 'pass', - email: 'foo@npmjs.org', - alwaysAuth: true, - }, - 'should return result from profile.login containing prompt info' - ) - - log = '' - delete profile.login - delete read.username - delete read.password - delete read.email -}) - -t.test('request otp when creating new user', async (t) => { - t.plan(3) - - profile.login = () => Promise.reject(Object.assign( - new Error('User does not exist'), - { code: 'ERROR' } - )) - profile.adduserCouch = () => Promise.reject(Object.assign( - new Error('needs otp'), - { code: 'EOTP' } - )) - profile.loginCouch = (username, password, { otp }) => { - t.equal(username, 'u', 'should use provided username to loginCouch') - t.equal(password, 'p', 'should use provided password to loginCouch') - t.equal(otp, '1234', 'should now use provided otp code to loginCouch') - - return { token } - } - read.otp = () => Promise.resolve('1234') - - await legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - log = '' - delete profile.adduserCouch - delete profile.login - delete profile.loginCouch - delete read.otp -}) - -t.test('unknown error during user creation', async (t) => { - profile.login = () => Promise.reject(Object.assign( - new Error('missing info'), - { code: 'ERROR' } - )) - profile.adduserCouch = () => Promise.reject(Object.assign( - new Error('unkown error'), - { code: 'ERROR' } - )) - - await t.rejects( - legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }), - { code: 'ERROR' }, - 'should throw unknown error' - ) - - log = '' - delete profile.adduserCouch - delete profile.login -}) - -t.test('open url error', async (t) => { - profile.login = async (opener, prompt, opts) => { - await opener() - } - - await t.rejects( - legacy(npm, { - creds: { - username: 'u', - password: 'p', - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }), - { message: 'failed open url', code: 'ERROR' }, - 'should throw unknown error' - ) - - log = '' - delete profile.login -}) - -t.test('login no credentials provided', async (t) => { - profile.login = () => ({ token }) - - await legacy(npm, { - creds: { - username: undefined, - password: undefined, - email: undefined, - alwaysAuth: undefined, - }, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - log, - 'login Authorized', - 'should have correct message result' - ) - - log = '' - delete profile.login -}) - -t.test('scoped login', async (t) => { - profile.login = () => ({ token }) - - const { message } = await legacy(npm, { - creds: { - username: 'u', - password: 'p', - email: 'u@npmjs.org', - alwaysAuth: false, - }, - registry: 'https://diff-registry.npmjs.org/', - scope: 'myscope', - }) - - t.equal( - message, - 'Logged in as u to scope myscope on https://diff-registry.npmjs.org/.', - 'should have correct message result' - ) - - t.equal( - log, - 'login Authorized user u', - 'should have correct message result' - ) - - log = '' - delete profile.login -}) diff --git a/test/lib/auth/oauth.js b/test/lib/auth/oauth.js deleted file mode 100644 index 0c317fb9a130e..0000000000000 --- a/test/lib/auth/oauth.js +++ /dev/null @@ -1,28 +0,0 @@ -const t = require('tap') - -t.test('oauth login', (t) => { - t.plan(3) - const oauthOpts = { - creds: {}, - registry: 'https://diff-registry.npmjs.org/', - scope: 'myscope', - } - - const npm = { - config: { - set: (key, value) => { - t.equal(key, 'sso-type', 'should define sso-type') - t.equal(value, 'oauth', 'should set sso-type to oauth') - }, - }, - } - const oauth = t.mock('../../../lib/auth/oauth.js', { - '../../../lib/auth/sso.js': (npm, opts) => { - t.equal(opts, oauthOpts, 'should forward opts') - }, - }) - - oauth(npm, oauthOpts) - - t.end() -}) diff --git a/test/lib/auth/saml.js b/test/lib/auth/saml.js deleted file mode 100644 index 1558e0db8eb29..0000000000000 --- a/test/lib/auth/saml.js +++ /dev/null @@ -1,28 +0,0 @@ -const t = require('tap') - -t.test('saml login', (t) => { - t.plan(3) - const samlOpts = { - creds: {}, - registry: 'https://diff-registry.npmjs.org/', - scope: 'myscope', - } - - const npm = { - config: { - set: (key, value) => { - t.equal(key, 'sso-type', 'should define sso-type') - t.equal(value, 'saml', 'should set sso-type to saml') - }, - }, - } - const saml = t.mock('../../../lib/auth/saml.js', { - '../../../lib/auth/sso.js': (npm, opts) => { - t.equal(opts, samlOpts, 'should forward opts') - }, - }) - - saml(npm, samlOpts) - - t.end() -}) diff --git a/test/lib/auth/sso.js b/test/lib/auth/sso.js deleted file mode 100644 index 8d70077ad205f..0000000000000 --- a/test/lib/auth/sso.js +++ /dev/null @@ -1,236 +0,0 @@ -const t = require('tap') - -let log = '' - -const _flatOptions = { - ssoType: 'oauth', -} -const token = '24528a24f240' -const SSO_URL = 'https://registry.npmjs.org/%7BSSO_URL%7D' -const profile = {} -const npmFetch = {} -const sso = t.mock('../../../lib/auth/sso.js', { - 'proc-log': { - info: (...msgs) => { - log += msgs.join(' ') + '\n' - }, - }, - 'npm-profile': profile, - 'npm-registry-fetch': npmFetch, - '../../../lib/utils/open-url.js': async (npm, url, msg) => { - if (!url) { - throw Object.assign( - new Error('failed open url'), - { code: 'ERROR' } - ) - } - }, -}) - -const npm = { - flatOptions: _flatOptions, -} - -t.test('empty login', async (t) => { - _flatOptions.ssoType = false - - await t.rejects( - sso(npm, {}), - { message: 'Missing option: sso-type' }, - 'should throw if no sso-type defined in flatOptions' - ) - - _flatOptions.ssoType = 'oauth' - log = '' -}) - -t.test('simple login', async (t) => { - t.plan(6) - - profile.loginCouch = (username, password, opts) => { - t.equal(username, 'npm_oauth_auth_dummy_user', 'should use dummy user') - t.equal(password, 'placeholder', 'should use dummy password') - t.same( - opts, - { - creds: {}, - registry: 'https://registry.npmjs.org/', - scope: '', - ssoType: 'oauth', - }, - 'should use dummy password' - ) - - return { token, sso: SSO_URL } - } - npmFetch.json = () => Promise.resolve({ username: 'foo' }) - - const { - message, - newCreds, - } = await sso(npm, { - creds: {}, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - t.equal( - message, - 'Logged in as foo on https://registry.npmjs.org/.', - 'should have correct message result' - ) - - t.equal( - log, - 'adduser Polling for validated SSO session\nadduser Authorized user foo\n', - 'should have correct logged info msg' - ) - - t.same( - newCreds, - { token }, - 'should return expected resulting credentials' - ) - - log = '' - delete profile.loginCouch - delete npmFetch.json -}) - -t.test('polling retry', async (t) => { - t.plan(3) - - profile.loginCouch = () => ({ token, sso: SSO_URL }) - npmFetch.json = () => { - // assert expected values during retry - npmFetch.json = (url, { registry, forceAuth: { token: expected } }) => { - t.equal( - url, - '/-/whoami', - 'should reach for expected endpoint' - ) - - t.equal( - registry, - 'https://registry.npmjs.org/', - 'should use expected registry value' - ) - - t.equal( - expected, - token, - 'should use expected token retrieved from initial loginCouch' - ) - - return Promise.resolve({ username: 'foo' }) - } - - // initial fetch returns retry code - return Promise.reject(Object.assign( - new Error('nothing yet'), - { code: 'E401' } - )) - } - - await sso(npm, { - creds: {}, - registry: 'https://registry.npmjs.org/', - scope: '', - }) - - log = '' - delete profile.loginCouch - delete npmFetch.json -}) - -t.test('polling error', async (t) => { - profile.loginCouch = () => ({ token, sso: SSO_URL }) - npmFetch.json = () => Promise.reject(Object.assign( - new Error('unknown error'), - { code: 'ERROR' } - )) - - await t.rejects( - sso(npm, { - creds: {}, - registry: 'https://registry.npmjs.org/', - scope: '', - }), - { message: 'unknown error', code: 'ERROR' }, - 'should throw unknown error' - ) - - log = '' - delete profile.loginCouch - delete npmFetch.json -}) - -t.test('no token retrieved from loginCouch', async (t) => { - profile.loginCouch = () => ({}) - - await t.rejects( - sso(npm, { - creds: {}, - registry: 'https://registry.npmjs.org/', - scope: '', - }), - { message: 'no SSO token returned' }, - 'should throw no SSO token returned error' - ) - - log = '' - delete profile.loginCouch -}) - -t.test('no sso url retrieved from loginCouch', async (t) => { - profile.loginCouch = () => Promise.resolve({ token }) - - await t.rejects( - sso(npm, { - creds: {}, - registry: 'https://registry.npmjs.org/', - scope: '', - }), - { message: 'no SSO URL returned by services' }, - 'should throw no SSO url returned error' - ) - - log = '' - delete profile.loginCouch -}) - -t.test('scoped login', async (t) => { - profile.loginCouch = () => ({ token, sso: SSO_URL }) - npmFetch.json = () => Promise.resolve({ username: 'foo' }) - - const { - message, - newCreds, - } = await sso(npm, { - creds: {}, - registry: 'https://diff-registry.npmjs.org/', - scope: 'myscope', - }) - - t.equal( - message, - 'Logged in as foo to scope myscope on https://diff-registry.npmjs.org/.', - 'should have correct message result' - ) - - t.equal( - log, - 'adduser Polling for validated SSO session\nadduser Authorized user foo\n', - 'should have correct logged info msg' - ) - - t.same( - newCreds, - { token }, - 'should return expected resulting credentials' - ) - - log = '' - delete profile.loginCouch - delete npmFetch.json -}) diff --git a/test/lib/commands/adduser.js b/test/lib/commands/adduser.js index 94e58a6d3cb0e..4ff65e57f30dd 100644 --- a/test/lib/commands/adduser.js +++ b/test/lib/commands/adduser.js @@ -1,7 +1,7 @@ const t = require('tap') -const path = require('path') const fs = require('fs') -const os = require('os') +const path = require('path') +const ini = require('ini') const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') const mockGlobals = require('../../fixtures/mock-globals.js') @@ -14,170 +14,169 @@ t.test('usage', async t => { t.match(adduser.usage, 'adduser', 'usage has command name in it') }) -t.test('simple login', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { - homeDir: { - // These all get cleaned up by config.setCredentialsByURI - '.npmrc': [ - '_token=user', - '_password=user', - 'username=user', - '_auth=user', - '_authtoken=user', - '-authtoken=user', - '_authToken=user', - '//registry.npmjs.org/:_authToken=user', - '//registry.npmjs.org/:always-auth=user', - '//registry.npmjs.org/:email=test-email-old@npmjs.org', - ].join('\n'), - }, - }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), +t.test('legacy', async t => { + t.test('simple adduser', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + stdin.write('test-email@npmjs.org\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm, home } = await loadMockNpm(t, { + homeDir: { + // These all get cleaned up by config.setCredentialsByURI + '.npmrc': [ + '_token=user', + '_password=user', + 'username=user', + '_auth=user', + '_authtoken=user', + '-authtoken=user', + '_authToken=user', + '//registry.npmjs.org/:_authToken=user', + '//registry.npmjs.org/:always-auth=user', + '//registry.npmjs.org/:email=test-email-old@npmjs.org', + ].join('\n'), + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.couchadduser({ + username: 'test-user', + password: 'test-password', + email: 'test-email@npmjs.org', + token: 'npm_test-token', + }) + await npm.exec('adduser', []) + t.same(npm.config.get('email'), 'test-email-old@npmjs.org') + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '//registry.npmjs.org/:_authToken': 'npm_test-token', + email: 'test-email-old@npmjs.org', + }, 'should only have token and un-nerfed old email') }) - registry.couchlogin({ - username: 'test-user', - password: 'test-password', - email: 'test-email@npmjs.org', - token: 'npm_test-token', - }) - await npm.exec('adduser', []) - t.same(npm.config.get('email'), 'test-email-old@npmjs.org') - t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') - const rc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8') - t.same( - rc.trim().split(os.EOL), [ - '//registry.npmjs.org/:_authToken=npm_test-token', - 'email=test-email-old@npmjs.org', - ], 'should only have token and un-nerfed old email' - ) -}) -t.test('bad auth type', async t => { - const { npm } = await loadMockNpm(t, { - config: { - 'auth-type': 'foo', - }, + t.test('scoped adduser', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + stdin.write('test-email@npmjs.org\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm, home } = await loadMockNpm(t, { + config: { + scope: '@myscope', + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.couchadduser({ + username: 'test-user', + password: 'test-password', + email: 'test-email@npmjs.org', + token: 'npm_test-token', + }) + await npm.exec('adduser', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + t.same(npm.config.get('@myscope:registry'), 'https://registry.npmjs.org/') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '//registry.npmjs.org/:_authToken': 'npm_test-token', + '@myscope:registry': 'https://registry.npmjs.org/', + }, 'should only have token and scope:registry') }) - await t.rejects(npm.exec('adduser', []), { - message: 'no such auth module', - }) -}) -t.test('auth-type sso warning', async t => { - const { logs } = await loadMockNpm(t, { - config: { - 'auth-type': 'sso', - }, + t.test('scoped adduser with valid scoped registry config', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + stdin.write('test-email@npmjs.org\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm, home } = await loadMockNpm(t, { + homeDir: { + '.npmrc': '@myscope:registry=https://diff-registry.npmjs.org', + }, + config: { + scope: '@myscope', + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: 'https://diff-registry.npmjs.org/', + }) + registry.couchadduser({ + username: 'test-user', + password: 'test-password', + email: 'test-email@npmjs.org', + token: 'npm_test-token', + }) + await npm.exec('adduser', []) + t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token') + t.same(npm.config.get('@myscope:registry'), 'https://diff-registry.npmjs.org/') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '@myscope:registry': 'https://diff-registry.npmjs.org/', + '//diff-registry.npmjs.org/:_authToken': 'npm_test-token', + }, 'should only have token and scope:registry') }) - t.matchSnapshot({ warn: logs.warn }, 'warning') -}) -t.test('scoped login', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { - config: { - scope: '@myscope', - }, - }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), + t.test('save config failure', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + stdin.write('test-email@npmjs.org\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm } = await loadMockNpm(t, { + homeDir: { + '.npmrc': {}, + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.couchadduser({ + username: 'test-user', + password: 'test-password', + email: 'test-email@npmjs.org', + token: 'npm_test-token', + }) + await t.rejects(npm.exec('adduser', [])) }) - registry.couchlogin({ - username: 'test-user', - password: 'test-password', - email: 'test-email@npmjs.org', - token: 'npm_test-token', - }) - await npm.exec('adduser', []) - t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') - t.same(npm.config.get('@myscope:registry'), 'https://registry.npmjs.org/') - const rc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8') - t.same( - rc.trim().split(os.EOL), [ - '//registry.npmjs.org/:_authToken=npm_test-token', - '@myscope:registry=https://registry.npmjs.org/', - ], 'should only have token and scope:registry') -}) - -t.test('scoped login with valid scoped registry config', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm, home } = await loadMockNpm(t, { - homeDir: { - '.npmrc': '@myscope:registry=https://diff-registry.npmjs.org', - }, - config: { - scope: '@myscope', - }, - }) - const registry = new MockRegistry({ - tap: t, - registry: 'https://diff-registry.npmjs.org/', - }) - registry.couchlogin({ - username: 'test-user', - password: 'test-password', - email: 'test-email@npmjs.org', - token: 'npm_test-token', - }) - await npm.exec('adduser', []) - t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token') - t.same(npm.config.get('@myscope:registry'), 'https://diff-registry.npmjs.org/') - const rc = fs.readFileSync(path.join(home, '.npmrc'), 'utf8') - t.same(rc.trim().split(os.EOL), - [ - '@myscope:registry=https://diff-registry.npmjs.org', - '//diff-registry.npmjs.org/:_authToken=npm_test-token', - ], 'should only have token and scope:registry') + t.end() }) -t.test('save config failure', async t => { - const stdin = new stream.PassThrough() - stdin.write('test-user\n') - stdin.write('test-password\n') - stdin.write('test-email@npmjs.org\n') - mockGlobals(t, { - 'process.stdin': stdin, - 'process.stdout': new stream.PassThrough(), // to quiet readline - }, { replace: true }) - const { npm } = await loadMockNpm(t, { - homeDir: { - '.npmrc': {}, - }, - }) - const registry = new MockRegistry({ - tap: t, - registry: npm.config.get('registry'), - }) - registry.couchlogin({ - username: 'test-user', - password: 'test-password', - email: 'test-email@npmjs.org', - token: 'npm_test-token', +t.test('web', t => { + t.test('basic adduser', async t => { + const { npm, home } = await loadMockNpm(t, { + config: { 'auth-type': 'web' }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.webadduser({ token: 'npm_test-token' }) + await npm.exec('adduser', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '//registry.npmjs.org/:_authToken': 'npm_test-token', + }) }) - await t.rejects(npm.exec('adduser', [])) + t.end() }) diff --git a/test/lib/commands/login.js b/test/lib/commands/login.js new file mode 100644 index 0000000000000..8d27421313406 --- /dev/null +++ b/test/lib/commands/login.js @@ -0,0 +1,151 @@ +const t = require('tap') +const fs = require('fs') +const path = require('path') +const ini = require('ini') + +const { load: loadMockNpm } = require('../../fixtures/mock-npm.js') +const mockGlobals = require('../../fixtures/mock-globals.js') +const MockRegistry = require('../../fixtures/mock-registry.js') +const stream = require('stream') + +t.test('usage', async t => { + const { npm } = await loadMockNpm(t) + const login = await npm.cmd('login') + t.match(login.usage, 'login', 'usage has command name in it') +}) + +t.test('legacy', t => { + t.test('basic login', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm, home } = await loadMockNpm(t, { + config: { 'auth-type': 'legacy' }, + homeDir: { + // These all get cleaned up by config.setCredentialsByURI + '.npmrc': [ + '_token=user', + '_password=user', + 'username=user', + '_auth=user', + '_authtoken=user', + '-authtoken=user', + '_authToken=user', + '//registry.npmjs.org/:_authToken=user', + '//registry.npmjs.org/:always-auth=user', + '//registry.npmjs.org/:email=test-email-old@npmjs.org', + ].join('\n'), + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.couchlogin({ + username: 'test-user', + password: 'test-password', + token: 'npm_test-token', + }) + await npm.exec('login', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '//registry.npmjs.org/:_authToken': 'npm_test-token', + email: 'test-email-old@npmjs.org', + }, 'should only have token and un-nerfed old email') + }) + + t.test('scoped login default registry', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm, home } = await loadMockNpm(t, { + config: { + 'auth-type': 'legacy', + scope: '@npmcli', + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.couchlogin({ + username: 'test-user', + password: 'test-password', + token: 'npm_test-token', + }) + await npm.exec('login', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + t.same(npm.config.get('@npmcli:registry'), 'https://registry.npmjs.org/') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '//registry.npmjs.org/:_authToken': 'npm_test-token', + '@npmcli:registry': 'https://registry.npmjs.org/', + }, 'should only have token and scope:registry') + }) + + t.test('scoped login scoped registry', async t => { + const stdin = new stream.PassThrough() + stdin.write('test-user\n') + stdin.write('test-password\n') + mockGlobals(t, { + 'process.stdin': stdin, + 'process.stdout': new stream.PassThrough(), // to quiet readline + }, { replace: true }) + const { npm, home } = await loadMockNpm(t, { + config: { + 'auth-type': 'legacy', + scope: '@npmcli', + }, + homeDir: { + '.npmrc': '@npmcli:registry=https://diff-registry.npmjs.org', + }, + }) + const registry = new MockRegistry({ + tap: t, + registry: 'https://diff-registry.npmjs.org/', + }) + registry.couchlogin({ + username: 'test-user', + password: 'test-password', + token: 'npm_test-token', + }) + await npm.exec('login', []) + t.same(npm.config.get('//diff-registry.npmjs.org/:_authToken'), 'npm_test-token') + t.same(npm.config.get('@npmcli:registry'), 'https://diff-registry.npmjs.org/') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '@npmcli:registry': 'https://diff-registry.npmjs.org/', + '//diff-registry.npmjs.org/:_authToken': 'npm_test-token', + }, 'should only have token and scope:registry') + }) + t.end() +}) + +t.test('web', t => { + t.test('basic login', async t => { + const { npm, home } = await loadMockNpm(t, { + config: { 'auth-type': 'web' }, + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + }) + registry.weblogin({ token: 'npm_test-token' }) + await npm.exec('login', []) + t.same(npm.config.get('//registry.npmjs.org/:_authToken'), 'npm_test-token') + const rc = ini.parse(fs.readFileSync(path.join(home, '.npmrc'), 'utf8')) + t.same(rc, { + '//registry.npmjs.org/:_authToken': 'npm_test-token', + }) + }) + t.end() +}) From d030f10fd535433e5a824df1b099f500a71075dd Mon Sep 17 00:00:00 2001 From: nlf Date: Tue, 20 Sep 2022 13:11:42 -0700 Subject: [PATCH 14/40] deps: @npmcli/query@2.0.0 --- node_modules/@npmcli/query/lib/index.js | 9 +++++++++ node_modules/@npmcli/query/package.json | 17 ++++++++++------- package-lock.json | 10 +++++----- workspaces/arborist/package.json | 2 +- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/node_modules/@npmcli/query/lib/index.js b/node_modules/@npmcli/query/lib/index.js index 44f539ee0a125..09cff0f591d4d 100644 --- a/node_modules/@npmcli/query/lib/index.js +++ b/node_modules/@npmcli/query/lib/index.js @@ -168,6 +168,13 @@ const fixupPaths = astNode => { astNode.nodes.length = 0 } +const fixupOutdated = astNode => { + if (astNode.nodes.length) { + astNode.outdatedKind = String(astNode.nodes[0]) + astNode.nodes.length = 0 + } +} + // a few of the supported ast nodes need to be tweaked in order to properly be // interpreted as proper arborist query selectors, namely semver ranges from // both ids and :semver pseudo-class selectors need to be translated from what @@ -196,6 +203,8 @@ const transformAst = selector => { return fixupSemverSpecs(nextAstNode) case ':type': return fixupTypes(nextAstNode) + case ':outdated': + return fixupOutdated(nextAstNode) } }) } diff --git a/node_modules/@npmcli/query/package.json b/node_modules/@npmcli/query/package.json index 610d0b7189182..1e2ce917cef75 100644 --- a/node_modules/@npmcli/query/package.json +++ b/node_modules/@npmcli/query/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/query", - "version": "1.2.0", + "version": "2.0.0", "description": "npm query parser and tools", "main": "lib/index.js", "scripts": { @@ -9,9 +9,6 @@ "postlint": "template-oss-check", "template-oss-apply": "template-oss-apply --force", "lintfix": "npm run lint -- --fix", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "snap": "tap", "posttest": "npm run lint" }, @@ -38,15 +35,15 @@ "lib/" ], "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" + "version": "4.3.2" }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", + "@npmcli/template-oss": "4.3.2", "tap": "^16.2.0" }, "dependencies": { @@ -57,5 +54,11 @@ "repository": { "type": "git", "url": "https://github.com/npm/query.git" + }, + "tap": { + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] } } diff --git a/package-lock.json b/package-lock.json index 2fabe79b6bbf4..069cf6dc0bd53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2334,16 +2334,16 @@ } }, "node_modules/@npmcli/query": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-1.2.0.tgz", - "integrity": "sha512-uWglsUM3PjBLgTSmZ3/vygeGdvWEIZ3wTUnzGFbprC/RtvQSaT+GAXu1DXmSFj2bD3oOZdcRm1xdzsV2z1YWdw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-2.0.0.tgz", + "integrity": "sha512-ef3fUALbojBvtCi6wpogwnrtChBcK8Pdso5Vbz2EU0cud7VW1jcMGqwSNeSMU8V4cjpqVgudKQ+dosKO7N903g==", "dependencies": { "npm-package-arg": "^9.1.0", "postcss-selector-parser": "^6.0.10", "semver": "^7.3.7" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/run-script": { @@ -13875,7 +13875,7 @@ "@npmcli/name-from-folder": "^1.0.1", "@npmcli/node-gyp": "^2.0.0", "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.2.0", + "@npmcli/query": "^2.0.0", "@npmcli/run-script": "^4.1.3", "bin-links": "^3.0.3", "cacache": "^16.1.3", diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 4c685676da09a..58a156da8ce6b 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -11,7 +11,7 @@ "@npmcli/name-from-folder": "^1.0.1", "@npmcli/node-gyp": "^2.0.0", "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.2.0", + "@npmcli/query": "^2.0.0", "@npmcli/run-script": "^4.1.3", "bin-links": "^3.0.3", "cacache": "^16.1.3", From ebf167b621ed14933826f617077ab5890e72bf83 Mon Sep 17 00:00:00 2001 From: nlf Date: Tue, 20 Sep 2022 13:12:23 -0700 Subject: [PATCH 15/40] feat: add `:outdated` pseudo selector --- workspaces/arborist/lib/node.js | 7 +- workspaces/arborist/lib/query-selector-all.js | 207 ++++++++++++++- .../tap-snapshots/test/link.js.test.cjs | 4 + .../tap-snapshots/test/node.js.test.cjs | 248 ++++++++++++++++++ .../arborist/test/query-selector-all.js | 154 ++++++++++- 5 files changed, 598 insertions(+), 22 deletions(-) diff --git a/workspaces/arborist/lib/node.js b/workspaces/arborist/lib/node.js index 60ce3eda0eb42..b90a2acf8f8ae 100644 --- a/workspaces/arborist/lib/node.js +++ b/workspaces/arborist/lib/node.js @@ -103,6 +103,9 @@ class Node { dummy = false, sourceReference = null, } = options + // this object gives querySelectorAll somewhere to stash context about a node + // while processing a query + this.queryContext = {} // true if part of a global install this[_global] = global @@ -1455,8 +1458,8 @@ class Node { // maybe accept both string value or array of strings // seems to be what dom API does - querySelectorAll (query) { - return querySelectorAll(this, query) + querySelectorAll (query, opts) { + return querySelectorAll(this, query, opts) } toJSON () { diff --git a/workspaces/arborist/lib/query-selector-all.js b/workspaces/arborist/lib/query-selector-all.js index 64b280d58a23a..87a67bbed1885 100644 --- a/workspaces/arborist/lib/query-selector-all.js +++ b/workspaces/arborist/lib/query-selector-all.js @@ -6,6 +6,7 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const log = require('proc-log') const minimatch = require('minimatch') const npa = require('npm-package-arg') +const pacote = require('pacote') const semver = require('semver') // handle results for parsed query asts, results are stored in a map that has a @@ -16,6 +17,7 @@ class Results { #currentAstSelector #initialItems #inventory + #outdatedCache = new Map() #pendingCombinator #results = new Map() #targetNode @@ -28,6 +30,9 @@ class Results { this.currentResults = this.#initialItems + // We get this when first called and need to pass it to pacote + this.flatOptions = opts.flatOptions || {} + // reset by rootAstNode walker this.currentAstNode = opts.rootAstNode } @@ -58,6 +63,7 @@ class Results { if (firstParsed) { return this.#initialItems } + if (this.currentAstNode.prev().type === 'combinator') { return this.#inventory } @@ -125,7 +131,7 @@ class Results { } // pseudo selectors (prefixed with :) - pseudoType () { + async pseudoType () { const pseudoFn = `${this.currentAstNode.value.slice(1)}Pseudo` if (!this[pseudoFn]) { throw Object.assign( @@ -134,7 +140,7 @@ class Results { { code: 'EQUERYNOPSEUDO' } ) } - const nextResults = this[pseudoFn]() + const nextResults = await this[pseudoFn]() this.processPendingCombinator(nextResults) } @@ -195,11 +201,12 @@ class Results { return this.initialItems.filter(node => node.extraneous) } - hasPseudo () { + async hasPseudo () { const found = [] for (const item of this.initialItems) { - const res = retrieveNodesFromParsedAst({ - // This is the one time initialItems differs from inventory + // This is the one time initialItems differs from inventory + const res = await retrieveNodesFromParsedAst({ + flatOptions: this.flatOptions, initialItems: [item], inventory: this.#inventory, rootAstNode: this.currentAstNode.nestedNode, @@ -225,8 +232,9 @@ class Results { return found } - isPseudo () { - const res = retrieveNodesFromParsedAst({ + async isPseudo () { + const res = await retrieveNodesFromParsedAst({ + flatOptions: this.flatOptions, initialItems: this.initialItems, inventory: this.#inventory, rootAstNode: this.currentAstNode.nestedNode, @@ -251,8 +259,9 @@ class Results { }, []) } - notPseudo () { - const res = retrieveNodesFromParsedAst({ + async notPseudo () { + const res = await retrieveNodesFromParsedAst({ + flatOptions: this.flatOptions, initialItems: this.initialItems, inventory: this.#inventory, rootAstNode: this.currentAstNode.nestedNode, @@ -422,6 +431,135 @@ class Results { dedupedPseudo () { return this.initialItems.filter(node => node.target.edgesIn.size > 1) } + + async outdatedPseudo () { + const { outdatedKind = 'any' } = this.currentAstNode + + // filter the initialItems + // NOTE: this uses a Promise.all around a map without in-line concurrency handling + // since the only async action taken is retrieving the packument, which is limited + // based on the max-sockets config in make-fetch-happen + const initialResults = await Promise.all(this.initialItems.map(async (node) => { + // the root can't be outdated, skip it + if (node.isProjectRoot) { + return false + } + + // we cache the promise representing the full versions list, this helps reduce the + // number of requests we send by keeping population of the cache in a single tick + // making it less likely that multiple requests for the same package will be inflight + if (!this.#outdatedCache.has(node.name)) { + this.#outdatedCache.set(node.name, getPackageVersions(node.name, this.flatOptions)) + } + const availableVersions = await this.#outdatedCache.get(node.name) + + // we attach _all_ versions to the queryContext to allow consumers to do their own + // filtering and comparisons + node.queryContext.versions = availableVersions + + // next we further reduce the set to versions that are greater than the current one + const greaterVersions = availableVersions.filter((available) => { + return semver.gt(available, node.version) + }) + + // no newer versions than the current one, drop this node from the result set + if (!greaterVersions.length) { + return false + } + + // if we got here, we know that newer versions exist, if the kind is 'any' we're done + if (outdatedKind === 'any') { + return node + } + + // look for newer versions that differ from current by a specific part of the semver version + if (['major', 'minor', 'patch'].includes(outdatedKind)) { + // filter the versions greater than our current one based on semver.diff + const filteredVersions = greaterVersions.filter((version) => { + return semver.diff(node.version, version) === outdatedKind + }) + + // no available versions are of the correct diff type + if (!filteredVersions.length) { + return false + } + + return node + } + + // look for newer versions that satisfy at least one edgeIn to this node + if (outdatedKind === 'in-range') { + const inRangeContext = [] + for (const edge of node.edgesIn) { + const inRangeVersions = greaterVersions.filter((version) => { + return semver.satisfies(version, edge.spec) + }) + + // this edge has no in-range candidates, just move on + if (!inRangeVersions.length) { + continue + } + + inRangeContext.push({ + from: edge.from.location, + versions: inRangeVersions, + }) + } + + // if we didn't find at least one match, drop this node + if (!inRangeContext.length) { + return false + } + + // now add to the context each version that is in-range for each edgeIn + node.queryContext.outdated = { + ...node.queryContext.outdated, + inRange: inRangeContext, + } + + return node + } + + // look for newer versions that _do not_ satisfy at least one edgeIn + if (outdatedKind === 'out-of-range') { + const outOfRangeContext = [] + for (const edge of node.edgesIn) { + const outOfRangeVersions = greaterVersions.filter((version) => { + return !semver.satisfies(version, edge.spec) + }) + + // this edge has no out-of-range candidates, skip it + if (!outOfRangeVersions.length) { + continue + } + + outOfRangeContext.push({ + from: edge.from.location, + versions: outOfRangeVersions, + }) + } + + // if we didn't add at least one thing to the context, this node is not a match + if (!outOfRangeContext.length) { + return false + } + + // attach the out-of-range context to the node + node.queryContext.outdated = { + ...node.queryContext.outdated, + outOfRange: outOfRangeContext, + } + + return node + } + + // any other outdatedKind is unknown and will never match + return false + })) + + // return an array with the holes for non-matching nodes removed + return initialResults.filter(Boolean) + } } // operators for attribute selectors @@ -622,7 +760,41 @@ const combinators = { }, } -const retrieveNodesFromParsedAst = (opts) => { +// get a list of available versions of a package filtered to respect --before +// NOTE: this runs over each node and should not throw +const getPackageVersions = async (name, opts) => { + let packument + try { + packument = await pacote.packument(name, { + ...opts, + fullMetadata: false, // we only need the corgi + }) + } catch (err) { + // if the fetch fails, log a warning and pretend there are no versions + log.warn('query', `could not retrieve packument for ${name}: ${err.message}`) + return [] + } + + // start with a sorted list of all versions (lowest first) + let candidates = Object.keys(packument.versions).sort(semver.compare) + + // if the packument has a time property, and the user passed a before flag, then + // we filter this list down to only those versions that existed before the specified date + if (packument.time && opts.before) { + candidates = candidates.filter((version) => { + // this version isn't found in the times at all, drop it + if (!packument.time[version]) { + return false + } + + return Date.parse(packument.time[version]) <= opts.before + }) + } + + return candidates +} + +const retrieveNodesFromParsedAst = async (opts) => { // when we first call this it's the parsed query. all other times it's // results.currentNode.nestedNode const rootAstNode = opts.rootAstNode @@ -633,7 +805,13 @@ const retrieveNodesFromParsedAst = (opts) => { const results = new Results(opts) + const astNodeQueue = new Set() + // walk is sync, so we have to build up our async functions and then await them later rootAstNode.walk((nextAstNode) => { + astNodeQueue.add(nextAstNode) + }) + + for (const nextAstNode of astNodeQueue) { // This is the only place we reset currentAstNode results.currentAstNode = nextAstNode const updateFn = `${results.currentAstNode.type}Type` @@ -643,23 +821,24 @@ const retrieveNodesFromParsedAst = (opts) => { { code: 'EQUERYNOSELECTOR' } ) } - results[updateFn]() - }) + await results[updateFn]() + } return results.collect(rootAstNode) } // We are keeping this async in the event that we do add async operators, we // won't have to have a breaking change on this function signature. -const querySelectorAll = async (targetNode, query) => { +const querySelectorAll = async (targetNode, query, flatOptions) => { // This never changes ever we just pass it around. But we can't scope it to // this whole file if we ever want to support concurrent calls to this // function. const inventory = [...targetNode.root.inventory.values()] // res is a Set of items returned for each parsed css ast selector - const res = retrieveNodesFromParsedAst({ + const res = await retrieveNodesFromParsedAst({ initialItems: inventory, inventory, + flatOptions, rootAstNode: parser(query), targetNode, }) diff --git a/workspaces/arborist/tap-snapshots/test/link.js.test.cjs b/workspaces/arborist/tap-snapshots/test/link.js.test.cjs index 71d4414c33c56..adffc182b23b0 100644 --- a/workspaces/arborist/tap-snapshots/test/link.js.test.cjs +++ b/workspaces/arborist/tap-snapshots/test/link.js.test.cjs @@ -26,6 +26,7 @@ Link { "optional": true, "path": "/home/user/some/other/path", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/some/kind/of/path", "sourceReference": null, "tops": Set {}, @@ -70,6 +71,7 @@ exports[`test/link.js TAP > instantiate without providing target 1`] = ` "optional": true, "path": "/home/user/projects/some/kind/of/path", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/some/kind/of/path", "resolved": null, "sourceReference": null, @@ -83,6 +85,7 @@ exports[`test/link.js TAP > instantiate without providing target 1`] = ` "optional": true, "path": "/home/user/some/other/path", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/some/kind/of/path", "sourceReference": null, "tops": Set { @@ -109,6 +112,7 @@ exports[`test/link.js TAP > instantiate without providing target 1`] = ` "optional": true, "path": "/home/user/projects/some/kind/of/path", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/some/kind/of/path", "resolved": null, "sourceReference": null, diff --git a/workspaces/arborist/tap-snapshots/test/node.js.test.cjs b/workspaces/arborist/tap-snapshots/test/node.js.test.cjs index 08705aca6f8eb..5c7918a762364 100644 --- a/workspaces/arborist/tap-snapshots/test/node.js.test.cjs +++ b/workspaces/arborist/tap-snapshots/test/node.js.test.cjs @@ -42,6 +42,7 @@ exports[`test/node.js TAP basic instantiation > just a lone root node 1`] = ` }, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -215,6 +216,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "sourceReference": null, "tops": Set {}, @@ -239,6 +241,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "sourceReference": null, "tops": Set {}, @@ -299,6 +302,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "sourceReference": null, "tops": Set {}, @@ -309,6 +313,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "resolved": null, "sourceReference": null, @@ -350,6 +355,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "sourceReference": null, "tops": Set {}, @@ -360,6 +366,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "resolved": null, "sourceReference": null, @@ -395,6 +402,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "sourceReference": null, "tops": Set {}, @@ -439,6 +447,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "sourceReference": null, "tops": Set {}, @@ -449,6 +458,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "resolved": null, "sourceReference": null, @@ -474,6 +484,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "sourceReference": null, "tops": Set {}, @@ -514,6 +525,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "sourceReference": null, "tops": Set {}, @@ -524,6 +536,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "resolved": null, "sourceReference": null, @@ -537,6 +550,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root", "resolved": null, "sourceReference": null, @@ -581,6 +595,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "sourceReference": null, "tops": Set {}, @@ -591,6 +606,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/foo", "resolved": null, "sourceReference": null, @@ -632,6 +648,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/node_modules/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "sourceReference": null, "tops": Set {}, @@ -642,6 +659,7 @@ exports[`test/node.js TAP set workspaces > should setup edges out for each works "optional": true, "path": "/home/user/projects/workspaces_root/unknown", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/workspaces_root/unknown", "resolved": null, "sourceReference": null, @@ -678,6 +696,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -713,6 +732,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -763,6 +783,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -780,6 +801,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -817,6 +839,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -847,6 +870,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -877,6 +901,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -907,6 +932,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -933,6 +959,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -982,6 +1009,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -992,6 +1020,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -1057,6 +1086,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -1092,6 +1122,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -1142,6 +1173,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -1159,6 +1191,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -1189,6 +1222,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -1226,6 +1260,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -1256,6 +1291,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -1286,6 +1322,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -1316,6 +1353,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -1342,6 +1380,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -1391,6 +1430,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -1401,6 +1441,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -1428,6 +1469,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -1463,6 +1505,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -1488,6 +1531,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -1500,6 +1544,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -1529,6 +1574,7 @@ exports[`test/node.js TAP testing with dep tree with meta > add new meta under p "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -1575,6 +1621,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -1625,6 +1672,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -1642,6 +1690,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -1679,6 +1728,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -1709,6 +1759,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -1739,6 +1790,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -1769,6 +1821,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -1795,6 +1848,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -1870,6 +1924,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -1920,6 +1975,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -1937,6 +1993,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -1967,6 +2024,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2004,6 +2062,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -2041,6 +2100,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -2071,6 +2131,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -2101,6 +2162,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -2131,6 +2193,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -2157,6 +2220,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -2170,6 +2234,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -2199,6 +2264,7 @@ exports[`test/node.js TAP testing with dep tree with meta > initial load with so "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2257,6 +2323,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2274,6 +2341,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -2311,6 +2379,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -2341,6 +2410,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -2371,6 +2441,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -2401,6 +2472,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -2427,6 +2499,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -2467,6 +2540,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -2554,6 +2628,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2571,6 +2646,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -2601,6 +2677,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2638,6 +2715,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -2668,6 +2746,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -2698,6 +2777,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -2728,6 +2808,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -2754,6 +2835,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -2794,6 +2876,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -2807,6 +2890,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -2836,6 +2920,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move meta to top lev "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2894,6 +2979,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -2911,6 +2997,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -2945,6 +3032,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -2975,6 +3063,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -3005,6 +3094,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -3035,6 +3125,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -3061,6 +3152,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -3088,6 +3180,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3141,6 +3234,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3151,6 +3245,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -3238,6 +3333,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -3255,6 +3351,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -3285,6 +3382,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -3319,6 +3417,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -3349,6 +3448,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -3379,6 +3479,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -3409,6 +3510,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -3435,6 +3537,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -3460,6 +3563,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3486,6 +3590,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3539,6 +3644,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3549,6 +3655,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -3562,6 +3669,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -3591,6 +3699,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -3649,6 +3758,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -3666,6 +3776,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -3700,6 +3811,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -3730,6 +3842,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -3760,6 +3873,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -3790,6 +3904,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -3816,6 +3931,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -3843,6 +3959,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3896,6 +4013,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -3906,6 +4024,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -3993,6 +4112,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -4010,6 +4130,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -4040,6 +4161,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -4074,6 +4196,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -4104,6 +4227,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -4134,6 +4258,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -4164,6 +4289,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -4190,6 +4316,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -4215,6 +4342,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -4241,6 +4369,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -4294,6 +4423,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -4304,6 +4434,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -4317,6 +4448,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -4346,6 +4478,7 @@ exports[`test/node.js TAP testing with dep tree with meta > move new meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -4382,6 +4515,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -4417,6 +4551,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -4467,6 +4602,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -4484,6 +4620,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -4521,6 +4658,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -4551,6 +4689,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -4581,6 +4720,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -4611,6 +4751,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -4637,6 +4778,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -4686,6 +4828,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -4696,6 +4839,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -4761,6 +4905,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -4796,6 +4941,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -4846,6 +4992,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -4863,6 +5010,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -4893,6 +5041,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -4930,6 +5079,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -4960,6 +5110,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -4990,6 +5141,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -5020,6 +5172,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -5046,6 +5199,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -5095,6 +5249,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -5105,6 +5260,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -5132,6 +5288,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -5167,6 +5324,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -5192,6 +5350,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -5204,6 +5363,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -5233,6 +5393,7 @@ exports[`test/node.js TAP testing with dep tree without meta > add new meta unde "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -5279,6 +5440,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -5329,6 +5491,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -5346,6 +5509,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -5383,6 +5547,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -5413,6 +5578,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -5443,6 +5609,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -5473,6 +5640,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -5499,6 +5667,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -5574,6 +5743,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -5624,6 +5794,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -5641,6 +5812,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -5671,6 +5843,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -5708,6 +5881,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -5745,6 +5919,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -5775,6 +5950,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -5805,6 +5981,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -5835,6 +6012,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -5861,6 +6039,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -5874,6 +6053,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -5903,6 +6083,7 @@ exports[`test/node.js TAP testing with dep tree without meta > initial load with "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -5961,6 +6142,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -5978,6 +6160,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -6015,6 +6198,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -6045,6 +6229,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -6075,6 +6260,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -6105,6 +6291,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -6131,6 +6318,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -6171,6 +6359,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -6258,6 +6447,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -6275,6 +6465,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -6305,6 +6496,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -6342,6 +6534,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -6372,6 +6565,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -6402,6 +6596,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -6432,6 +6627,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -6458,6 +6654,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -6498,6 +6695,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "meta", "sourceReference": null, @@ -6511,6 +6709,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -6540,6 +6739,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move meta to top "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -6598,6 +6798,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -6615,6 +6816,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -6649,6 +6851,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -6679,6 +6882,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -6709,6 +6913,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -6739,6 +6944,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -6765,6 +6971,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -6792,6 +6999,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -6845,6 +7053,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -6855,6 +7064,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -6942,6 +7152,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -6959,6 +7170,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -6989,6 +7201,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -7023,6 +7236,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -7053,6 +7267,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -7083,6 +7298,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -7113,6 +7329,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -7139,6 +7356,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -7164,6 +7382,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7190,6 +7409,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7243,6 +7463,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7253,6 +7474,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -7266,6 +7488,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -7295,6 +7518,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -7353,6 +7577,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -7370,6 +7595,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -7404,6 +7630,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -7434,6 +7661,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -7464,6 +7692,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -7494,6 +7723,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -7520,6 +7750,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -7547,6 +7778,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7600,6 +7832,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7610,6 +7843,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -7697,6 +7931,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -7714,6 +7949,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod", "resolved": "prod", "sourceReference": null, @@ -7744,6 +7980,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, @@ -7778,6 +8015,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/bundled", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/bundled", "resolved": "bundled", "sourceReference": null, @@ -7808,6 +8046,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/dev", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/dev", "resolved": "dev", "sourceReference": null, @@ -7838,6 +8077,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/optional", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/optional", "resolved": "opt", "sourceReference": null, @@ -7868,6 +8108,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/peer", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/peer", "resolved": "peer", "sourceReference": null, @@ -7894,6 +8135,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/extraneous", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/extraneous", "resolved": "extraneous", "sourceReference": null, @@ -7919,6 +8161,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7945,6 +8188,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -7998,6 +8242,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta/node_modules/metameta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "sourceReference": null, "tops": Set {}, @@ -8008,6 +8253,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/meta", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/meta", "resolved": "newMeta", "sourceReference": null, @@ -8021,6 +8267,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root", "resolved": null, "sourceReference": null, @@ -8050,6 +8297,7 @@ exports[`test/node.js TAP testing with dep tree without meta > move new meta to "optional": true, "path": "/home/user/projects/root/node_modules/prod/foo", "peer": true, + "queryContext": Object {}, "realpath": "/home/user/projects/root/node_modules/prod/foo", "resolved": null, "sourceReference": null, diff --git a/workspaces/arborist/test/query-selector-all.js b/workspaces/arborist/test/query-selector-all.js index 6ad5a69565e67..2adf526dee9a2 100644 --- a/workspaces/arborist/test/query-selector-all.js +++ b/workspaces/arborist/test/query-selector-all.js @@ -1,5 +1,6 @@ 'use strict' +const nock = require('nock') const t = require('tap') const Arborist = require('..') @@ -7,8 +8,8 @@ const q = require('../lib/query-selector-all.js') // test helper that spits out pkgid for readability // and deduplicates link/target from results -const querySelectorAll = async (tree, query) => { - const res = await q(tree, query) +const querySelectorAll = async (tree, query, options) => { + const res = await q(tree, query, options) return [...new Set(res.map(i => i.pkgid))] } @@ -36,6 +37,76 @@ t.test('query-selector-all', async t => { └── recur@1.0.0 (recursive production dep of recur, deduped) */ + + const now = Date.now() + const today = new Date(now) + const yesterday = new Date(now - (1000 * 60 * 60 * 24)) + const dayBeforeYesterday = new Date(now - (1000 * 60 * 60 * 24 * 2)) + // @npmcli/abbrev is deliberately left out of this list to cover the case when + // fetching a packument fails + const packumentStubs = { + a: { + '1.0.0': today, + }, + abbrev: { + '1.1.1': dayBeforeYesterday, + '1.2.0': yesterday, + }, + b: { + '1.0.0': today, + }, + bar: { + '1.4.0': dayBeforeYesterday, + '2.0.0': today, + }, + baz: { + // undefined for coverage in --before mode + '1.0.0': undefined, + '1.0.1': yesterday, + }, + 'dash-separated-pkg': { + '1.0.0': dayBeforeYesterday, + '2.0.0': yesterday, + }, + dasher: { + '2.0.0': today, + }, + foo: { + '2.2.2': today, + }, + lorem: { + '1.0.0': today, + }, + moo: { + '3.0.0': today, + }, + recur: { + '1.0.0': today, + }, + sive: { + '1.0.0': today, + }, + } + + nock.disableNetConnect() + t.teardown(() => { + nock.enableNetConnect() + }) + + for (const [pkg, versions] of Object.entries(packumentStubs)) { + nock('https://registry.npmjs.org/') + .persist() + .get(`/${pkg}`) + .reply(200, { + time: Object.entries(versions).reduce((final, [version, time]) => { + return { ...final, [version]: time } + }, {}), + versions: Object.keys(versions).reduce((final, next) => { + return { ...final, [next]: {} } + }, {}), + }) + } + const path = t.testdir({ node_modules: { '@npmcli': { @@ -288,13 +359,22 @@ t.test('query-selector-all', async t => { ], ':scope > *') const runSpecParsing = async testCase => { - for (const [selector, expected] of testCase) { - t.test(selector, async t => { - const res = await querySelectorAll(tree, selector) + for (const [selector, expected, options = {}] of testCase) { + let title = selector + if (options.before) { + const friendlyTime = options.before === today + ? 'today' + : options.before === yesterday + ? 'yesterday' + : options.before + title += ` before ${friendlyTime}` + } + t.test(title, async t => { + const res = await querySelectorAll(tree, selector, options) t.same( res, expected, - selector + title ) }) } @@ -668,6 +748,68 @@ t.test('query-selector-all', async t => { 'moo@3.0.0', ]], + // outdated pseudo + [':outdated', [ + 'abbrev@1.1.1', // 1.2.0 is available + 'baz@1.0.0', // 1.0.1 is available + 'dash-separated-pkg@1.0.0', // 2.0.0 is available + 'bar@1.4.0', // 2.0.0 is available + ]], + [':outdated(any)', [ + 'abbrev@1.1.1', // 1.2.0 is available + 'baz@1.0.0', // 1.0.1 is available + 'dash-separated-pkg@1.0.0', // 2.0.0 is available + 'bar@1.4.0', // 2.0.0 is available + ]], + [':outdated(major)', [ + 'dash-separated-pkg@1.0.0', // 2.0.0 is available + 'bar@1.4.0', // 2.0.0 is available + ]], + [':outdated(minor)', [ + 'abbrev@1.1.1', // 1.2.0 is available + ]], + [':outdated(patch)', [ + 'baz@1.0.0', // 1.0.1 is available + ]], + [':outdated(in-range)', [ + 'abbrev@1.1.1', // 1.2.0 is available and in-range + 'baz@1.0.0', // 1.0.1 is available and in-range + ]], + [':outdated(out-of-range)', [ + 'dash-separated-pkg@1.0.0', // 2.0.0 is available + 'bar@1.4.0', // 2.0.0 is available and out-of-range + ]], + [':outdated(nonsense)', []], // invalid, no results ever + + // :outdated combined with --before + [':outdated', [ + 'abbrev@1.1.1', // 1.2.0 is available and published yesterday + 'baz@1.0.0', // 1.0.1 is available and published yesterday + 'dash-separated-pkg@1.0.0', // 2.0.0 is available and published yesterday + ], { before: yesterday }], + [':outdated(any)', [ + 'abbrev@1.1.1', // 1.2.0 is available and published yesterday + 'baz@1.0.0', // 1.0.1 is available and published yesterday + 'dash-separated-pkg@1.0.0', // 2.0.0 is available and published yesterday + ], { before: yesterday }], + [':outdated(major)', [ + 'dash-separated-pkg@1.0.0', // 2.0.0 is available and published yesterday + ], { before: yesterday }], + [':outdated(minor)', [ + 'abbrev@1.1.1', // 1.2.0 is available and published yesterday + ], { before: yesterday }], + [':outdated(patch)', [ + 'baz@1.0.0', // 1.0.1 is available and published yesterday + ], { before: yesterday }], + [':outdated(in-range)', [ + 'abbrev@1.1.1', // 1.2.0 is available, in-range and published yesterday + 'baz@1.0.0', // 1.0.1 is available, in-range and published yesterday + ], { before: yesterday }], + [':outdated(out-of-range)', [ + 'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday + ], { before: yesterday }], + [':outdated(nonsense)', [], { before: yesterday }], // again, no results here ever + // attr pseudo [':attr([name=dasher])', ['dasher@2.0.0']], [':attr(dependencies, [bar="^1.0.0"])', ['foo@2.2.2']], From 6ee5b320d2eab58c18d50b861b3cfabe7f24124a Mon Sep 17 00:00:00 2001 From: nlf Date: Tue, 20 Sep 2022 13:13:10 -0700 Subject: [PATCH 16/40] feat(query): display `queryContext` in results --- lib/commands/query.js | 5 +-- .../test/lib/commands/query.js.test.cjs | 33 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/commands/query.js b/lib/commands/query.js index 231329b19b5c8..5f05ab3164d7c 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -21,6 +21,7 @@ class QuerySelectorItem { this.inBundle = node.target.inBundle this.deduped = this.from.length > 1 this.overridden = node.overridden + this.queryContext = node.queryContext for (const edge of node.target.edgesIn) { this.from.push(edge.from.location) } @@ -63,7 +64,7 @@ class Query extends BaseCommand { } const arb = new Arborist(opts) const tree = await arb.loadActual(opts) - const items = await tree.querySelectorAll(args[0]) + const items = await tree.querySelectorAll(args[0], this.npm.flatOptions) this.buildResponse(items) this.npm.output(this.parsedResponse) @@ -84,7 +85,7 @@ class Query extends BaseCommand { items = await tree.querySelectorAll(args[0]) } else { const [workspace] = await tree.querySelectorAll(`.workspace:path(${workspacePath})`) - items = await workspace.target.querySelectorAll(args[0]) + items = await workspace.target.querySelectorAll(args[0], this.npm.flatOptions) } this.buildResponse(items) } diff --git a/tap-snapshots/test/lib/commands/query.js.test.cjs b/tap-snapshots/test/lib/commands/query.js.test.cjs index d827b62eef740..9ad6e2e38084e 100644 --- a/tap-snapshots/test/lib/commands/query.js.test.cjs +++ b/tap-snapshots/test/lib/commands/query.js.test.cjs @@ -23,7 +23,8 @@ exports[`test/lib/commands/query.js TAP global > should return global package 1` "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} } ] ` @@ -53,7 +54,8 @@ exports[`test/lib/commands/query.js TAP include-workspace-root > should return w "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} }, { "name": "c", @@ -69,7 +71,8 @@ exports[`test/lib/commands/query.js TAP include-workspace-root > should return w "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} } ] ` @@ -90,7 +93,8 @@ exports[`test/lib/commands/query.js TAP linked node > should return linked node "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} } ] ` @@ -116,7 +120,8 @@ exports[`test/lib/commands/query.js TAP recursive tree > should return everythin "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} }, { "pkgid": "a@", @@ -131,7 +136,8 @@ exports[`test/lib/commands/query.js TAP recursive tree > should return everythin "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} }, { "pkgid": "b@", @@ -146,7 +152,8 @@ exports[`test/lib/commands/query.js TAP recursive tree > should return everythin "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} } ] ` @@ -175,7 +182,8 @@ exports[`test/lib/commands/query.js TAP simple query > should return root object "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} }, { "pkgid": "a@", @@ -190,7 +198,8 @@ exports[`test/lib/commands/query.js TAP simple query > should return root object "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} }, { "pkgid": "b@", @@ -205,7 +214,8 @@ exports[`test/lib/commands/query.js TAP simple query > should return root object "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} } ] ` @@ -226,7 +236,8 @@ exports[`test/lib/commands/query.js TAP workspace query > should return workspac "dev": false, "inBundle": false, "deduped": false, - "overridden": false + "overridden": false, + "queryContext": {} } ] ` From 8402fd8780c5e0461850da882dca024f7df1a681 Mon Sep 17 00:00:00 2001 From: nlf Date: Tue, 20 Sep 2022 13:26:26 -0700 Subject: [PATCH 17/40] docs: add `:outdated` pseudo selector to docs --- .../content/using-npm/dependency-selectors.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/content/using-npm/dependency-selectors.md b/docs/content/using-npm/dependency-selectors.md index 29ce2b82f7eed..5fb20bad5f80f 100644 --- a/docs/content/using-npm/dependency-selectors.md +++ b/docs/content/using-npm/dependency-selectors.md @@ -61,6 +61,7 @@ The [`npm query`](/commands/npm-query) commmand exposes a new dependency selecto - `:semver(, [selector], [function])` match a valid [`node-semver`](https://github.com/npm/node-semver) version or range to a selector - `:path()` [glob](https://www.npmjs.com/package/glob) matching based on dependencies path relative to the project - `:type()` [based on currently recognized types](https://github.com/npm/npm-package-arg#result-object) +- `:outdated()` when a dependency is outdated ##### `:semver(, [selector], [function])` @@ -78,6 +79,28 @@ Some examples: - `:semver(16.0.0, :attr(engines, [node]))` returns every node which has an `engines.node` property satisfying the version `16.0.0` - `:semver(1.0.0, [version], lt)` every node with a `version` less than `1.0.0` +##### `:outdated()` + +The `:outdated` pseudo selector retrieves data from the registry and returns information about which of your dependencies are outdated. The type parameter may be one of the following: + +- `any` (default) a version exists that is greater than the current one +- `in-range` a version exists that is greater than the current one, and satisfies at least one if its dependents +- `out-of-range` a version exists that is greater than the current one, does not satisfy at least one of its dependents +- `major` a version exists that is a semver major greater than the current one +- `minor` a version exists that is a semver minor greater than the current one +- `patch` a version exists that is a semver patch greater than the current one + +In addition to the filtering performed by the pseudo selector, some extra data is added to the resulting objects. The following data can be found under the `queryContext` property of each node. + +- `versions` an array of every available version of the given node +- `outdated.inRange` an array of objects, each with a `from` and `versions`, where `from` is the on-disk location of the node that depends on the current node and `versions` is an array of all available versions that satisfies that dependency. This is only populated if `:outdated(in-range)` is used. +- `outdated.outOfRange` an array of objects, identical in shape to `inRange`, but where the `versions` array is every available version that does not satisfy the dependency. This is only populated if `:outdated(out-of-range)` is used. + +Some examples: + +- `:root > :outdated(major)` returns every direct dependency that has a new semver major release +- `.prod:outdated(in-range)` returns production dependencies that have a new release that satisfies at least one of its edges in + #### [Attribute Selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) The attribute selector evaluates the key/value pairs in `package.json` if they are `String`s. From 19762b4ac4b10741ff53ddd315be1fd23d9b1e28 Mon Sep 17 00:00:00 2001 From: Hafizur046 Date: Thu, 22 Sep 2022 02:09:24 +0600 Subject: [PATCH 18/40] docs: modify misleading doc about package.json:bin (#5529) docs: modify Misleading doc about bins closes #3788 --- docs/content/configuring-npm/package-json.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/content/configuring-npm/package-json.md b/docs/content/configuring-npm/package-json.md index 5b4acf187f777..39d672124ba25 100644 --- a/docs/content/configuring-npm/package-json.md +++ b/docs/content/configuring-npm/package-json.md @@ -339,12 +339,14 @@ install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the "npm" executable.) To use this, supply a `bin` field in your package.json which is a map of -command name to local file name. When this package is installed -globally, that file will be linked where global bins go so it is -available to run by name. When this package is installed as a -dependency in another package, the file will be linked where it will be -available to that package either directly by `npm exec` or by name in other -scripts when invoking them via `npm run-script`. +command name to local file name. When this package is installed globally, +that file will be either linked inside the global bins directory or +a cmd (Windows Command File) will be created which executes the specified +file in the `bin` field, so it is available to run by `name` or `name.cmd` (on +Windows PowerShell). When this package is installed as a dependency in another +package, the file will be linked where it will be available to that package +either directly by `npm exec` or by name in other scripts when invoking them +via `npm run-script`. For example, myapp could have this: @@ -357,8 +359,10 @@ For example, myapp could have this: } ``` -So, when you install myapp, it'll create a symlink from the `cli.js` script -to `/usr/local/bin/myapp`. +So, when you install myapp, in case of unix-like OS it'll create a symlink +from the `cli.js` script to `/usr/local/bin/myapp` and in case of windows it +will create a cmd file usually at `C:\Users\{Username}\AppData\Roaming\npm\myapp.cmd` +which runs the `cli.js` script. If you have a single executable, and its name should be the name of the package, then you can just supply it as a string. For example: From 5645c51410a730c4b9c6831cf81ab22efbe8c0ce Mon Sep 17 00:00:00 2001 From: Michael Rienstra Date: Wed, 21 Sep 2022 13:27:12 -0700 Subject: [PATCH 19/40] docs: link mentions of config parameters (#5521) --- docs/content/commands/npm-audit.md | 8 ++++---- docs/content/commands/npm-bugs.md | 5 +++-- docs/content/commands/npm-dist-tag.md | 4 ++-- docs/content/commands/npm-docs.md | 8 ++++---- docs/content/commands/npm-exec.md | 9 +++++---- docs/content/commands/npm-fund.md | 10 ++++++---- docs/content/commands/npm-pkg.md | 3 ++- docs/content/commands/npm-repo.md | 7 ++++--- docs/content/commands/npm-run-script.md | 9 ++++++--- docs/content/commands/npm-update.md | 6 +++--- docs/content/commands/npm-version.md | 14 +++++++------- docs/content/configuring-npm/folders.md | 16 ++++++++-------- docs/content/configuring-npm/package-json.md | 7 ++++--- docs/content/using-npm/logging.md | 3 ++- docs/content/using-npm/registry.md | 8 +++++--- 15 files changed, 65 insertions(+), 52 deletions(-) diff --git a/docs/content/commands/npm-audit.md b/docs/content/commands/npm-audit.md index 6a5c3e6be676e..dda1c31c864c4 100644 --- a/docs/content/commands/npm-audit.md +++ b/docs/content/commands/npm-audit.md @@ -109,9 +109,9 @@ the path `/-/npm/v1/security/advisories/bulk`. Any packages in the tree that do not have a `version` field in their package.json file will be ignored. If any `--omit` options are specified -(either via the `--omit` config, or one of the shorthands such as -`--production`, `--only=dev`, and so on), then packages will be omitted -from the submitted payload as appropriate. +(either via the [`--omit` config](/using-npm/config#omit), or one of the +shorthands such as `--production`, `--only=dev`, and so on), then packages will +be omitted from the submitted payload as appropriate. If the registry responds with an error, or with an invalid response, then npm will attempt to load advisory data from the `Quick Audit` endpoint. @@ -188,7 +188,7 @@ vulnerabilities are found _or_ if the remediation is able to successfully fix all vulnerabilities. If vulnerabilities were found the exit code will depend on the -`audit-level` configuration setting. +[`audit-level` config](/using-npm/config#audit-level). ### Examples diff --git a/docs/content/commands/npm-bugs.md b/docs/content/commands/npm-bugs.md index 6b45f1f18ac66..af52548389c92 100644 --- a/docs/content/commands/npm-bugs.md +++ b/docs/content/commands/npm-bugs.md @@ -25,8 +25,9 @@ alias: issues This command tries to guess at the likely location of a package's bug tracker URL or the `mailto` URL of the support email, and then tries to -open it using the `--browser` config param. If no package name is provided, it -will search for a `package.json` in the current folder and use the `name` property. +open it using the [`--browser` config](/using-npm/config#browser) param. If no +package name is provided, it will search for a `package.json` in the current +folder and use the `name` property. ### Configuration diff --git a/docs/content/commands/npm-dist-tag.md b/docs/content/commands/npm-dist-tag.md index 123e67dbf3b23..e505fba36414b 100644 --- a/docs/content/commands/npm-dist-tag.md +++ b/docs/content/commands/npm-dist-tag.md @@ -28,8 +28,8 @@ alias: dist-tags Add, remove, and enumerate distribution tags on a package: * add: Tags the specified version of the package with the specified tag, - or the `--tag` config if not specified. If you have two-factor - authentication on auth-and-writes then you’ll need to include a + or the [`--tag` config](/using-npm/config#tag) if not specified. If you have + two-factor authentication on auth-and-writes then you’ll need to include a one-time password on the command line with `--otp `, or at the OTP prompt. diff --git a/docs/content/commands/npm-docs.md b/docs/content/commands/npm-docs.md index 790d563bdb1fb..e48695ced005a 100644 --- a/docs/content/commands/npm-docs.md +++ b/docs/content/commands/npm-docs.md @@ -24,10 +24,10 @@ alias: home ### Description This command tries to guess at the likely location of a package's -documentation URL, and then tries to open it using the `--browser` config -param. You can pass multiple package names at once. If no package name is -provided, it will search for a `package.json` in the current folder and use -the `name` property. +documentation URL, and then tries to open it using the +[`--browser` config](/using-npm/config#browser) param. You can pass multiple +package names at once. If no package name is provided, it will search for a +`package.json` in the current folder and use the `name` property. ### Configuration diff --git a/docs/content/commands/npm-exec.md b/docs/content/commands/npm-exec.md index 3d8de1ea54ad6..7a66fbc27eb08 100644 --- a/docs/content/commands/npm-exec.md +++ b/docs/content/commands/npm-exec.md @@ -240,7 +240,8 @@ $ npx -c 'eslint && say "hooray, lint passed"' ### Workspaces support -You may use the `workspace` or `workspaces` configs in order to run an +You may use the [`workspace`](/using-npm/config#workspace) or +[`workspaces`](/using-npm/config#workspaces) configs in order to run an arbitrary command from an npm package (either one installed locally, or fetched remotely) in the context of the specified workspaces. If no positional argument or `--call` option is provided, it will open an @@ -271,9 +272,9 @@ Assuming the workspace configuration is properly set up at the root level ``` You can execute an arbitrary command from a package in the context of each of -the configured workspaces when using the `workspaces` configuration options, -in this example we're using **eslint** to lint any js file found within each -workspace folder: +the configured workspaces when using the +[`workspaces` config options](/using-npm/config#workspace), in this example +we're using **eslint** to lint any js file found within each workspace folder: ``` npm exec --ws -- eslint ./*.js diff --git a/docs/content/commands/npm-fund.md b/docs/content/commands/npm-fund.md index 8db0ce910de96..53100f6716537 100644 --- a/docs/content/commands/npm-fund.md +++ b/docs/content/commands/npm-fund.md @@ -25,9 +25,10 @@ This command retrieves information on how to fund the dependencies of a given project. If no package name is provided, it will list all dependencies that are looking for funding in a tree structure, listing the type of funding and the url to visit. If a package name is provided -then it tries to open its funding url using the `--browser` config -param; if there are multiple funding sources for the package, the user -will be instructed to pass the `--which` option to disambiguate. +then it tries to open its funding url using the +[`--browser` config](/using-npm/config#browser) param; if there are multiple +funding sources for the package, the user will be instructed to pass the +`--which` option to disambiguate. The list will avoid duplicated entries and will stack all packages that share the same url as a single entry. Thus, the list does not have the @@ -38,7 +39,8 @@ same shape of the output from `npm ls`. ### Workspaces support It's possible to filter the results to only include a single workspace -and its dependencies using the `workspace` config option. +and its dependencies using the +[`workspace` config](/using-npm/config#workspace) option. #### Example: diff --git a/docs/content/commands/npm-pkg.md b/docs/content/commands/npm-pkg.md index deff7e82c694d..32772ae080a8b 100644 --- a/docs/content/commands/npm-pkg.md +++ b/docs/content/commands/npm-pkg.md @@ -153,7 +153,8 @@ Returned values are always in **json** format. ### Workspaces support You can set/get/delete items across your configured workspaces by using the -`workspace` or `workspaces` config options. +[`workspace`](/using-npm/config#workspace) or +[`workspaces`](/using-npm/config#workspaces) config options. For example, setting a `funding` value across all configured workspaces of a project: diff --git a/docs/content/commands/npm-repo.md b/docs/content/commands/npm-repo.md index fc540a9382b23..4d69a922c63a9 100644 --- a/docs/content/commands/npm-repo.md +++ b/docs/content/commands/npm-repo.md @@ -22,9 +22,10 @@ npm repo [ [ ...]] ### Description This command tries to guess at the likely location of a package's -repository URL, and then tries to open it using the `--browser` config -param. If no package name is provided, it will search for a `package.json` -in the current folder and use the `repository` property. +repository URL, and then tries to open it using the +[`--browser` config](/using-npm/config#browser) param. If no package name is +provided, it will search for a `package.json` in the current folder and use the +`repository` property. ### Configuration diff --git a/docs/content/commands/npm-run-script.md b/docs/content/commands/npm-run-script.md index f606ec6bf59e5..a68b9b65dcd4f 100644 --- a/docs/content/commands/npm-run-script.md +++ b/docs/content/commands/npm-run-script.md @@ -68,7 +68,8 @@ The actual shell your script is run within is platform dependent. By default, on Unix-like systems it is the `/bin/sh` command, on Windows it is `cmd.exe`. The actual shell referred to by `/bin/sh` also depends on the system. -You can customize the shell with the `script-shell` configuration. +You can customize the shell with the +[`script-shell` config](/using-npm/config#script-shell). Scripts are run from the root of the package folder, regardless of what the current working directory is when `npm run` is called. If you want your @@ -85,7 +86,8 @@ forgotten. ### Workspaces support -You may use the `workspace` or `workspaces` configs in order to run an +You may use the [`workspace`](/using-npm/config#workspace) or +[`workspaces`](/using-npm/config#workspaces) configs in order to run an arbitrary command from a package's `"scripts"` object in the context of the specified workspaces. If no `"command"` is provided, it will list the available scripts for each of these configured workspaces. @@ -114,7 +116,8 @@ Assuming the workspace configuration is properly set up at the root level ``` And that each of the configured workspaces has a configured `test` script, -we can run tests in all of them using the `workspaces` config: +we can run tests in all of them using the +[`workspaces` config](/using-npm/config#workspaces): ``` npm test --workspaces diff --git a/docs/content/commands/npm-update.md b/docs/content/commands/npm-update.md index cd77b7baddf19..5e21bdeebbb99 100644 --- a/docs/content/commands/npm-update.md +++ b/docs/content/commands/npm-update.md @@ -24,9 +24,9 @@ aliases: up, upgrade, udpate ### Description This command will update all the packages listed to the latest version -(specified by the `tag` config), respecting the semver constraints of -both your package and its dependencies (if they also require the same -package). +(specified by the [`tag` config](/using-npm/config#tag)), respecting the semver +constraints of both your package and its dependencies (if they also require the +same package). It will also install missing packages. diff --git a/docs/content/commands/npm-version.md b/docs/content/commands/npm-version.md index 8e3334d788984..3c6b24d7d9ad8 100644 --- a/docs/content/commands/npm-version.md +++ b/docs/content/commands/npm-version.md @@ -192,18 +192,18 @@ disabled on the command line by running `npm --no-git-tag-version version`. It will fail if the working directory is not clean, unless the `-f` or `--force` flag is set. -If supplied with `-m` or `--message` config option, npm will use it as a -commit message when creating a version commit. If the `message` config -contains `%s` then that will be replaced with the resulting version number. -For example: +If supplied with `-m` or [`--message` config](/using-npm/config#message) option, +npm will use it as a commit message when creating a version commit. If the +`message` config contains `%s` then that will be replaced with the resulting +version number. For example: ```bash npm version patch -m "Upgrade to %s for reasons" ``` -If the `sign-git-tag` config is set, then the tag will be signed using the -`-s` flag to git. Note that you must have a default GPG key set up in your -git config for this to work properly. For example: +If the [`sign-git-tag` config](/using-npm/config#sign-git-tag) is set, then the +tag will be signed using the `-s` flag to git. Note that you must have a default +GPG key set up in your git config for this to work properly. For example: ```bash $ npm config set sign-git-tag true diff --git a/docs/content/configuring-npm/folders.md b/docs/content/configuring-npm/folders.md index 5bab80ec169c5..aa1c5738e3a4e 100644 --- a/docs/content/configuring-npm/folders.md +++ b/docs/content/configuring-npm/folders.md @@ -22,10 +22,10 @@ This document will tell you what it puts where. #### prefix Configuration -The `prefix` config defaults to the location where node is installed. -On most systems, this is `/usr/local`. On Windows, it's `%AppData%\npm`. -On Unix systems, it's one level up, since node is typically installed at -`{prefix}/bin/node` rather than `{prefix}/node.exe`. +The [`prefix` config](/using-npm/config#prefix) defaults to the location where +node is installed. On most systems, this is `/usr/local`. On Windows, it's +`%AppData%\npm`. On Unix systems, it's one level up, since node is typically +installed at `{prefix}/bin/node` rather than `{prefix}/node.exe`. When the `global` flag is set, npm installs things into this prefix. When it is not set, it uses the root of the current package, or the @@ -74,13 +74,13 @@ Man pages are not installed on Windows systems. See [`npm cache`](/commands/npm-cache). Cache files are stored in `~/.npm` on Posix, or `%AppData%/npm-cache` on Windows. -This is controlled by the `cache` configuration param. +This is controlled by the [`cache` config](/using-npm/config#cache) param. #### Temp Files Temporary files are stored by default in the folder specified by the -`tmp` config, which defaults to the TMPDIR, TMP, or TEMP environment -variables, or `/tmp` on Unix and `c:\windows\temp` on Windows. +[`tmp` config](/using-npm/config#tmp), which defaults to the TMPDIR, TMP, or +TEMP environment variables, or `/tmp` on Unix and `c:\windows\temp` on Windows. Temp files are given a unique folder under this root for each run of the program, and are deleted upon successful exit. @@ -111,7 +111,7 @@ be found by npm scripts when necessary. #### Global Installation -If the `global` configuration is set to true, then npm will +If the [`global` config](/using-npm/config#global) is set to true, then npm will install packages "globally". For global installation, packages are installed roughly the same way, diff --git a/docs/content/configuring-npm/package-json.md b/docs/content/configuring-npm/package-json.md index 39d672124ba25..68a4a62d2ae0a 100644 --- a/docs/content/configuring-npm/package-json.md +++ b/docs/content/configuring-npm/package-json.md @@ -1032,9 +1032,10 @@ capable of properly installing your program. For example: } ``` -Unless the user has set the `engine-strict` config flag, this field is -advisory only and will only produce warnings when your package is installed -as a dependency. +Unless the user has set the +[`engine-strict` config](/using-npm/config#engine-strict) flag, this field is +advisory only and will only produce warnings when your package is installed as a +dependency. ### os diff --git a/docs/content/using-npm/logging.md b/docs/content/using-npm/logging.md index eb83b167e698b..d699c8dca6ccc 100644 --- a/docs/content/using-npm/logging.md +++ b/docs/content/using-npm/logging.md @@ -58,7 +58,8 @@ The `npm` CLI began hiding the output of lifecycle scripts for `npm install` as ### Timing Information -The `--timing` config can be set which does two things: +The [`--timing` config](/using-npm/config#timing) can be set which does two +things: 1. Always shows the full path to the debug log regardless of command exit status 1. Write timing information to a timing file in the cache or `logs-dir` diff --git a/docs/content/using-npm/registry.md b/docs/content/using-npm/registry.md index fd7e44de48eba..5fab60ff4d49c 100644 --- a/docs/content/using-npm/registry.md +++ b/docs/content/using-npm/registry.md @@ -26,9 +26,11 @@ The npm public registry is powered by a CouchDB database, of which there is a public mirror at . The registry URL used is determined by the scope of the package (see -[`scope`](/using-npm/scope). If no scope is specified, the default registry is used, which is -supplied by the `registry` config parameter. See [`npm config`](/commands/npm-config), -[`npmrc`](/configuring-npm/npmrc), and [`config`](/using-npm/config) for more on managing npm's configuration. +[`scope`](/using-npm/scope). If no scope is specified, the default registry is +used, which is supplied by the [`registry` config](/using-npm/config#registry) +parameter. See [`npm config`](/commands/npm-config), +[`npmrc`](/configuring-npm/npmrc), and [`config`](/using-npm/config) for more on +managing npm's configuration. When the default registry is used in a package-lock or shrinkwrap is has the special meaning of "the currently configured registry". If you create a lock From 874336699681ac37857167b2438fac19c059511c Mon Sep 17 00:00:00 2001 From: Michael Rienstra Date: Wed, 21 Sep 2022 13:27:42 -0700 Subject: [PATCH 20/40] docs: add hash to "tag" config link (#5519) * docs: add hash to "tag" config link Minor change. [using-npm/config](https://docs.npmjs.com/cli/v8/using-npm/config) is a long page -- heck, the subtitle is "More than you probably want to know about npm configuration" -- so instead of dumping people at the top of it when they follow the link to learn about the "tag" config, let's send 'em right to the relevant bit. Aside from it being a long page, one more motivation: trying to get to the section by searching is also slow, it's the 16th (of 24) occurrence of "tag" on the page. (though to be fair, only the 4th if they catch it in the table of contents) * docs: fix some nonstandard formatting * docs: more useful link Co-authored-by: Luke Karrys --- docs/content/commands/npm-adduser.md | 2 +- docs/content/commands/npm-config.md | 2 +- docs/content/commands/npm-install.md | 2 +- docs/content/using-npm/package-spec.md | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/content/commands/npm-adduser.md b/docs/content/commands/npm-adduser.md index 91f1195afbbee..ea6654e98865d 100644 --- a/docs/content/commands/npm-adduser.md +++ b/docs/content/commands/npm-adduser.md @@ -27,7 +27,7 @@ Note: This command is unaware of workspaces. Create a new user in the specified registry, and save the credentials to the `.npmrc` file. If no registry is specified, the default registry -will be used (see [`config`](/using-npm/config)). +will be used (see [`registry`](/using-npm/registry)). When using `legacy` for your `auth-type`, the username, password, and email are read in from prompts. diff --git a/docs/content/commands/npm-config.md b/docs/content/commands/npm-config.md index 28c6003571de5..6e0c0b682d724 100644 --- a/docs/content/commands/npm-config.md +++ b/docs/content/commands/npm-config.md @@ -35,7 +35,7 @@ variables, `npmrc` files, and in some cases, the `package.json` file. See [npmrc](/configuring-npm/npmrc) for more information about the npmrc files. -See [config(7)](/using-npm/config) for a more thorough explanation of the +See [config](/using-npm/config) for a more thorough explanation of the mechanisms involved, and a full list of config options available. The `npm config` command can be used to update and edit the contents diff --git a/docs/content/commands/npm-install.md b/docs/content/commands/npm-install.md index 0cf2eea83edb9..72bd93fff9ba8 100644 --- a/docs/content/commands/npm-install.md +++ b/docs/content/commands/npm-install.md @@ -127,7 +127,7 @@ into a tarball (b). * `npm install [<@scope>/]`: Do a `@` install, where `` is the "tag" config. (See - [`config`](/using-npm/config). The config's default value is `latest`.) + [`config`](/using-npm/config#tag). The config's default value is `latest`.) In most cases, this will install the version of the modules tagged as `latest` on the npm registry. diff --git a/docs/content/using-npm/package-spec.md b/docs/content/using-npm/package-spec.md index 0d3741018f036..1ace780019fb3 100644 --- a/docs/content/using-npm/package-spec.md +++ b/docs/content/using-npm/package-spec.md @@ -101,6 +101,6 @@ Examples: ### See also -[npm-package-arg](https://npm.im/npm-package-arg) -[scope](/using-npm/scope) -[config](/using-npm/config) +* [npm-package-arg](https://npm.im/npm-package-arg) +* [scope](/using-npm/scope) +* [config](/using-npm/config) From 0d90a011fff411c878ba4b44582f14ef7dbdceb1 Mon Sep 17 00:00:00 2001 From: Juan Heyns Date: Wed, 21 Sep 2022 16:46:00 -0400 Subject: [PATCH 21/40] fix(audit): add a condition to allow third-party registries returning E400 (#5480) * Add a condition to fix third-party registries returning E400 * changed to a separate test. Co-authored-by: Juan Heyns --- lib/commands/audit.js | 2 +- test/lib/commands/audit.js | 31 ++++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/commands/audit.js b/lib/commands/audit.js index 6ec870f03a8a5..feccefda0c904 100644 --- a/lib/commands/audit.js +++ b/lib/commands/audit.js @@ -156,7 +156,7 @@ class VerifySignatures { ...key, pemkey: `-----BEGIN PUBLIC KEY-----\n${key.key}\n-----END PUBLIC KEY-----`, }))).catch(err => { - if (err.code === 'E404') { + if (err.code === 'E404' || err.code === 'E400') { return null } else { throw err diff --git a/test/lib/commands/audit.js b/test/lib/commands/audit.js index b6c6c77a2b40a..bfa68955c5c7b 100644 --- a/test/lib/commands/audit.js +++ b/test/lib/commands/audit.js @@ -1171,7 +1171,7 @@ t.test('audit signatures', async t => { t.matchSnapshot(joinedOutput()) }) - t.test('third-party registry without keys does not verify', async t => { + t.test('third-party registry without keys (E404) does not verify', async t => { const registryUrl = 'https://verdaccio-clone2.org/' const { npm } = await loadMockNpm(t, { prefixDir: installWithThirdPartyRegistry, @@ -1200,6 +1200,35 @@ t.test('audit signatures', async t => { ) }) + t.test('third-party registry without keys (E400) does not verify', async t => { + const registryUrl = 'https://verdaccio-clone2.org/' + const { npm } = await loadMockNpm(t, { + prefixDir: installWithThirdPartyRegistry, + config: { + '@npmcli:registry': registryUrl, + }, + }) + const registry = new MockRegistry({ tap: t, registry: registryUrl }) + const manifest = registry.manifest({ + name: '@npmcli/arborist', + packuments: [{ + version: '1.0.14', + dist: { + tarball: 'https://registry.npmjs.org/@npmcli/arborist/-/@npmcli/arborist-1.0.14.tgz', + integrity: 'sha512-caa8hv5rW9VpQKk6tyNRvSaVDySVjo9GkI7Wj/wcsFyxPm3tYrE' + + 'sFyTjSnJH8HCIfEGVQNjqqKXaXLFVp7UBag==', + }, + }], + }) + await registry.package({ manifest }) + registry.nock.get('/-/npm/v1/keys').reply(400) + + await t.rejects( + npm.exec('audit', ['signatures']), + /found no dependencies to audit that where installed from a supported registry/ + ) + }) + t.test('third-party registry with keys and signatures', async t => { const registryUrl = 'https://verdaccio-clone.org/' const { npm, joinedOutput } = await loadMockNpm(t, { From 66ed58454418dd69c4cd8196ad8499e73f7e46e1 Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 21 Sep 2022 13:46:35 -0700 Subject: [PATCH 22/40] feat: default auth-type to web (#5551) BREAKING CHANGE: the default `auth-type` config value is now `web` --- docs/content/commands/npm-adduser.md | 2 +- docs/content/commands/npm-login.md | 2 +- docs/content/using-npm/config.md | 2 +- lib/utils/config/definitions.js | 2 +- tap-snapshots/test/lib/commands/config.js.test.cjs | 4 ++-- tap-snapshots/test/lib/utils/config/definitions.js.test.cjs | 2 +- tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs | 2 +- test/lib/commands/adduser.js | 4 ++++ 8 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/content/commands/npm-adduser.md b/docs/content/commands/npm-adduser.md index ea6654e98865d..710060f838ff7 100644 --- a/docs/content/commands/npm-adduser.md +++ b/docs/content/commands/npm-adduser.md @@ -82,7 +82,7 @@ npm init --scope=@foo --yes #### `auth-type` -* Default: "legacy" +* Default: "web" * Type: "legacy" or "web" What authentication strategy to use with `login`. diff --git a/docs/content/commands/npm-login.md b/docs/content/commands/npm-login.md index 4f821c903b168..a3772dc882a9d 100644 --- a/docs/content/commands/npm-login.md +++ b/docs/content/commands/npm-login.md @@ -89,7 +89,7 @@ npm init --scope=@foo --yes #### `auth-type` -* Default: "legacy" +* Default: "web" * Type: "legacy" or "web" What authentication strategy to use with `login`. diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index 2b704bda2df4e..2b05c842f1190 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -217,7 +217,7 @@ exit code. #### `auth-type` -* Default: "legacy" +* Default: "web" * Type: "legacy" or "web" What authentication strategy to use with `login`. diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index 5f10bd5e38898..fc39bddc70a42 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -237,7 +237,7 @@ define('audit-level', { }) define('auth-type', { - default: 'legacy', + default: 'web', type: ['legacy', 'web'], description: ` What authentication strategy to use with \`login\`. diff --git a/tap-snapshots/test/lib/commands/config.js.test.cjs b/tap-snapshots/test/lib/commands/config.js.test.cjs index 043dccd9ceab4..116ccea3a12ef 100644 --- a/tap-snapshots/test/lib/commands/config.js.test.cjs +++ b/tap-snapshots/test/lib/commands/config.js.test.cjs @@ -20,7 +20,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna "also": null, "audit": true, "audit-level": null, - "auth-type": "legacy", + "auth-type": "web", "before": null, "bin-links": true, "browser": null, @@ -173,7 +173,7 @@ allow-same-version = false also = null audit = true audit-level = null -auth-type = "legacy" +auth-type = "web" before = null bin-links = true browser = null diff --git a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index 8eff450e7a926..ddf2396a6fe00 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -251,7 +251,7 @@ exit code. exports[`test/lib/utils/config/definitions.js TAP > config description for auth-type 1`] = ` #### \`auth-type\` -* Default: "legacy" +* Default: "web" * Type: "legacy" or "web" What authentication strategy to use with \`login\`. diff --git a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 633b2da8e0472..2c51efec54afe 100644 --- a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -90,7 +90,7 @@ exit code. #### \`auth-type\` -* Default: "legacy" +* Default: "web" * Type: "legacy" or "web" What authentication strategy to use with \`login\`. diff --git a/test/lib/commands/adduser.js b/test/lib/commands/adduser.js index 4ff65e57f30dd..04fe8dc8c3147 100644 --- a/test/lib/commands/adduser.js +++ b/test/lib/commands/adduser.js @@ -25,6 +25,7 @@ t.test('legacy', async t => { 'process.stdout': new stream.PassThrough(), // to quiet readline }, { replace: true }) const { npm, home } = await loadMockNpm(t, { + config: { 'auth-type': 'legacy' }, homeDir: { // These all get cleaned up by config.setCredentialsByURI '.npmrc': [ @@ -72,6 +73,7 @@ t.test('legacy', async t => { }, { replace: true }) const { npm, home } = await loadMockNpm(t, { config: { + 'auth-type': 'legacy', scope: '@myscope', }, }) @@ -109,6 +111,7 @@ t.test('legacy', async t => { '.npmrc': '@myscope:registry=https://diff-registry.npmjs.org', }, config: { + 'auth-type': 'legacy', scope: '@myscope', }, }) @@ -142,6 +145,7 @@ t.test('legacy', async t => { 'process.stdout': new stream.PassThrough(), // to quiet readline }, { replace: true }) const { npm } = await loadMockNpm(t, { + config: { 'auth-type': 'legacy' }, homeDir: { '.npmrc': {}, }, From 9f5e6bd7a22f4fbe29ae1b57fb07d38fec8458db Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 21 Sep 2022 15:21:37 -0700 Subject: [PATCH 23/40] chore(ci): run link before testing --- .github/workflows/ci-docs.yml | 3 +++ .github/workflows/ci-libnpmaccess.yml | 3 +++ .github/workflows/ci-libnpmdiff.yml | 3 +++ .github/workflows/ci-libnpmexec.yml | 3 +++ .github/workflows/ci-libnpmfund.yml | 3 +++ .github/workflows/ci-libnpmhook.yml | 3 +++ .github/workflows/ci-libnpmorg.yml | 3 +++ .github/workflows/ci-libnpmpack.yml | 3 +++ .github/workflows/ci-libnpmpublish.yml | 3 +++ .github/workflows/ci-libnpmsearch.yml | 3 +++ .github/workflows/ci-libnpmteam.yml | 3 +++ .github/workflows/ci-libnpmversion.yml | 3 +++ .github/workflows/ci-npmcli-arborist.yml | 3 +++ .github/workflows/ci-release.yml | 3 +++ .github/workflows/ci-smoke-tests.yml | 3 +++ .github/workflows/ci.yml | 3 +++ docs/test/index.js | 2 +- scripts/release-manager.js | 1 + scripts/template-oss/_step-test.yml | 7 +++++++ 19 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 scripts/template-oss/_step-test.yml diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index b79c9f5b8077a..b22eb08f3ff5e 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -82,5 +82,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w docs diff --git a/.github/workflows/ci-libnpmaccess.yml b/.github/workflows/ci-libnpmaccess.yml index 5cbe173c1dba8..538f468534daf 100644 --- a/.github/workflows/ci-libnpmaccess.yml +++ b/.github/workflows/ci-libnpmaccess.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmaccess diff --git a/.github/workflows/ci-libnpmdiff.yml b/.github/workflows/ci-libnpmdiff.yml index cd7623243f427..06efb53b9988c 100644 --- a/.github/workflows/ci-libnpmdiff.yml +++ b/.github/workflows/ci-libnpmdiff.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmdiff diff --git a/.github/workflows/ci-libnpmexec.yml b/.github/workflows/ci-libnpmexec.yml index 644d04ce445a6..14e0dd8383ccc 100644 --- a/.github/workflows/ci-libnpmexec.yml +++ b/.github/workflows/ci-libnpmexec.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmexec diff --git a/.github/workflows/ci-libnpmfund.yml b/.github/workflows/ci-libnpmfund.yml index ea50c49e63524..ec57e387474ec 100644 --- a/.github/workflows/ci-libnpmfund.yml +++ b/.github/workflows/ci-libnpmfund.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmfund diff --git a/.github/workflows/ci-libnpmhook.yml b/.github/workflows/ci-libnpmhook.yml index 250fb2f5a47aa..70ea396c6dc49 100644 --- a/.github/workflows/ci-libnpmhook.yml +++ b/.github/workflows/ci-libnpmhook.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmhook diff --git a/.github/workflows/ci-libnpmorg.yml b/.github/workflows/ci-libnpmorg.yml index dc901e4f3e74b..b02097c6a28ec 100644 --- a/.github/workflows/ci-libnpmorg.yml +++ b/.github/workflows/ci-libnpmorg.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmorg diff --git a/.github/workflows/ci-libnpmpack.yml b/.github/workflows/ci-libnpmpack.yml index fac63daf6690e..6bbb81aa318b6 100644 --- a/.github/workflows/ci-libnpmpack.yml +++ b/.github/workflows/ci-libnpmpack.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmpack diff --git a/.github/workflows/ci-libnpmpublish.yml b/.github/workflows/ci-libnpmpublish.yml index 7947dc61a5230..4673ab5ba02f1 100644 --- a/.github/workflows/ci-libnpmpublish.yml +++ b/.github/workflows/ci-libnpmpublish.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmpublish diff --git a/.github/workflows/ci-libnpmsearch.yml b/.github/workflows/ci-libnpmsearch.yml index 95a8d30bfa1a5..753f723546e42 100644 --- a/.github/workflows/ci-libnpmsearch.yml +++ b/.github/workflows/ci-libnpmsearch.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmsearch diff --git a/.github/workflows/ci-libnpmteam.yml b/.github/workflows/ci-libnpmteam.yml index aa82f5a7a7ea8..6abdc44267b2c 100644 --- a/.github/workflows/ci-libnpmteam.yml +++ b/.github/workflows/ci-libnpmteam.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmteam diff --git a/.github/workflows/ci-libnpmversion.yml b/.github/workflows/ci-libnpmversion.yml index 1bb0219fc6795..c8f73603e7745 100644 --- a/.github/workflows/ci-libnpmversion.yml +++ b/.github/workflows/ci-libnpmversion.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w libnpmversion diff --git a/.github/workflows/ci-npmcli-arborist.yml b/.github/workflows/ci-npmcli-arborist.yml index 7d571a608c5d9..e34099cee31fc 100644 --- a/.github/workflows/ci-npmcli-arborist.yml +++ b/.github/workflows/ci-npmcli-arborist.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w @npmcli/arborist diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 8e07a57fea5ef..41442f9f2ad8d 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -123,6 +123,9 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -ws -iwr --if-present - name: Conclude Check diff --git a/.github/workflows/ci-smoke-tests.yml b/.github/workflows/ci-smoke-tests.yml index 346335a72a18c..9251e0cbf8aef 100644 --- a/.github/workflows/ci-smoke-tests.yml +++ b/.github/workflows/ci-smoke-tests.yml @@ -87,5 +87,8 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -w smoke-tests diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb34dca3262f9..f0725516211d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -161,6 +161,9 @@ jobs: run: node . run resetdeps - name: Add Problem Matcher run: echo "::add-matcher::.github/matchers/tap.json" + - name: Link + if: matrix + run: node . link -f --ignore-scripts - name: Test run: node . test --ignore-scripts -iwr - name: Check Git Status diff --git a/docs/test/index.js b/docs/test/index.js index 57524327bfcbf..1eac4438cf8a7 100644 --- a/docs/test/index.js +++ b/docs/test/index.js @@ -21,7 +21,7 @@ const spawnNpm = (cmd, ...args) => { }) } -t.before(() => spawnNpm('npm', 'rebuild', 'cmark-gfm')) +t.before(() => spawnNpm('node', '..', 'rebuild', 'cmark-gfm')) t.beforeEach(() => rmOutput()) t.test('docs', async (t) => { diff --git a/scripts/release-manager.js b/scripts/release-manager.js index 27968e80b7891..47a2f9a99814f 100644 --- a/scripts/release-manager.js +++ b/scripts/release-manager.js @@ -166,6 +166,7 @@ const main = async (env) => { const releaseTitle = `### Release Checklist for ${release.tag}` const releaseChecklist = releaseItems .join('\n\n') + .replace(//g, RELEASE_PR_NUMBER) .replace(//g, pr.head.ref) .replace(//g, pr.base.ref) .replace(//g, release.major) diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml new file mode 100644 index 0000000000000..8df6696aedc01 --- /dev/null +++ b/scripts/template-oss/_step-test.yml @@ -0,0 +1,7 @@ +- name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" +- name: Link + if: matrix + run: {{ rootNpmPath }} link -f --ignore-scripts +- name: Test + run: {{ rootNpmPath }} test --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}} From a1ef180380f1b4f55cd3dfe468d23a658b114e6d Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 21 Sep 2022 16:17:01 -0700 Subject: [PATCH 24/40] chore(ci): rebuild cmark-gfm only before tests --- .github/workflows/ci-docs.yml | 2 ++ .github/workflows/ci-libnpmaccess.yml | 2 ++ .github/workflows/ci-libnpmdiff.yml | 2 ++ .github/workflows/ci-libnpmexec.yml | 2 ++ .github/workflows/ci-libnpmfund.yml | 2 ++ .github/workflows/ci-libnpmhook.yml | 2 ++ .github/workflows/ci-libnpmorg.yml | 2 ++ .github/workflows/ci-libnpmpack.yml | 2 ++ .github/workflows/ci-libnpmpublish.yml | 2 ++ .github/workflows/ci-libnpmsearch.yml | 2 ++ .github/workflows/ci-libnpmteam.yml | 2 ++ .github/workflows/ci-libnpmversion.yml | 2 ++ .github/workflows/ci-npmcli-arborist.yml | 2 ++ .github/workflows/ci-release.yml | 2 ++ .github/workflows/ci-smoke-tests.yml | 2 ++ .github/workflows/ci.yml | 2 ++ docs/test/index.js | 16 ++++------------ scripts/template-oss/_step-test.yml | 2 ++ 18 files changed, 38 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index b22eb08f3ff5e..ac92fead94a8b 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -85,5 +85,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w docs diff --git a/.github/workflows/ci-libnpmaccess.yml b/.github/workflows/ci-libnpmaccess.yml index 538f468534daf..4b30b54b1ef95 100644 --- a/.github/workflows/ci-libnpmaccess.yml +++ b/.github/workflows/ci-libnpmaccess.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmaccess diff --git a/.github/workflows/ci-libnpmdiff.yml b/.github/workflows/ci-libnpmdiff.yml index 06efb53b9988c..f1a8fd846d2c0 100644 --- a/.github/workflows/ci-libnpmdiff.yml +++ b/.github/workflows/ci-libnpmdiff.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmdiff diff --git a/.github/workflows/ci-libnpmexec.yml b/.github/workflows/ci-libnpmexec.yml index 14e0dd8383ccc..eccbd943d6a32 100644 --- a/.github/workflows/ci-libnpmexec.yml +++ b/.github/workflows/ci-libnpmexec.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmexec diff --git a/.github/workflows/ci-libnpmfund.yml b/.github/workflows/ci-libnpmfund.yml index ec57e387474ec..acd8a5e00afd3 100644 --- a/.github/workflows/ci-libnpmfund.yml +++ b/.github/workflows/ci-libnpmfund.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmfund diff --git a/.github/workflows/ci-libnpmhook.yml b/.github/workflows/ci-libnpmhook.yml index 70ea396c6dc49..e2f6eb8c263a6 100644 --- a/.github/workflows/ci-libnpmhook.yml +++ b/.github/workflows/ci-libnpmhook.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmhook diff --git a/.github/workflows/ci-libnpmorg.yml b/.github/workflows/ci-libnpmorg.yml index b02097c6a28ec..05ab19a41f0b9 100644 --- a/.github/workflows/ci-libnpmorg.yml +++ b/.github/workflows/ci-libnpmorg.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmorg diff --git a/.github/workflows/ci-libnpmpack.yml b/.github/workflows/ci-libnpmpack.yml index 6bbb81aa318b6..12a17c594a7b3 100644 --- a/.github/workflows/ci-libnpmpack.yml +++ b/.github/workflows/ci-libnpmpack.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmpack diff --git a/.github/workflows/ci-libnpmpublish.yml b/.github/workflows/ci-libnpmpublish.yml index 4673ab5ba02f1..ad28f216d86d7 100644 --- a/.github/workflows/ci-libnpmpublish.yml +++ b/.github/workflows/ci-libnpmpublish.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmpublish diff --git a/.github/workflows/ci-libnpmsearch.yml b/.github/workflows/ci-libnpmsearch.yml index 753f723546e42..51243c33b4034 100644 --- a/.github/workflows/ci-libnpmsearch.yml +++ b/.github/workflows/ci-libnpmsearch.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmsearch diff --git a/.github/workflows/ci-libnpmteam.yml b/.github/workflows/ci-libnpmteam.yml index 6abdc44267b2c..d69e4bdb1e8fd 100644 --- a/.github/workflows/ci-libnpmteam.yml +++ b/.github/workflows/ci-libnpmteam.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmteam diff --git a/.github/workflows/ci-libnpmversion.yml b/.github/workflows/ci-libnpmversion.yml index c8f73603e7745..23ec19dd12541 100644 --- a/.github/workflows/ci-libnpmversion.yml +++ b/.github/workflows/ci-libnpmversion.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w libnpmversion diff --git a/.github/workflows/ci-npmcli-arborist.yml b/.github/workflows/ci-npmcli-arborist.yml index e34099cee31fc..07caf1ec63339 100644 --- a/.github/workflows/ci-npmcli-arborist.yml +++ b/.github/workflows/ci-npmcli-arborist.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w @npmcli/arborist diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 41442f9f2ad8d..3aa582dbcb84c 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -126,6 +126,8 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -ws -iwr --if-present - name: Conclude Check diff --git a/.github/workflows/ci-smoke-tests.yml b/.github/workflows/ci-smoke-tests.yml index 9251e0cbf8aef..29033c6c462ad 100644 --- a/.github/workflows/ci-smoke-tests.yml +++ b/.github/workflows/ci-smoke-tests.yml @@ -90,5 +90,7 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -w smoke-tests diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0725516211d9..c13550bd14a5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -164,6 +164,8 @@ jobs: - name: Link if: matrix run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm - name: Test run: node . test --ignore-scripts -iwr - name: Check Git Status diff --git a/docs/test/index.js b/docs/test/index.js index 1eac4438cf8a7..17710c00a0339 100644 --- a/docs/test/index.js +++ b/docs/test/index.js @@ -9,19 +9,11 @@ const output = join(cwd, 'output') const rmOutput = () => fs.rm(output, { recursive: true, force: true }).catch(() => {}) -const spawnNpm = (cmd, ...args) => { - // remove npm config when spawning so config set by test commands don't interfere - const env = Object.entries(process.env) - .filter(([k]) => k.toLowerCase() !== 'npm_config_ignore_scripts') - - return spawn(which(cmd), args, { - env: Object.fromEntries(env), - stdioString: true, - cwd, - }) -} +const spawnNpm = (cmd, ...args) => spawn(which(cmd), args, { + stdioString: true, + cwd, +}) -t.before(() => spawnNpm('node', '..', 'rebuild', 'cmark-gfm')) t.beforeEach(() => rmOutput()) t.test('docs', async (t) => { diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml index 8df6696aedc01..195dc2991e6c3 100644 --- a/scripts/template-oss/_step-test.yml +++ b/scripts/template-oss/_step-test.yml @@ -3,5 +3,7 @@ - name: Link if: matrix run: {{ rootNpmPath }} link -f --ignore-scripts +- name: Rebuild cmark-gfm + run: {{ rootNpmPath }} rebuild cmark-gfm - name: Test run: {{ rootNpmPath }} test --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}} From 2d756cbb05125dcb769f2ca4c1687e42568d5882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kurowski?= Date: Thu, 22 Sep 2022 02:51:46 +0200 Subject: [PATCH 25/40] docs: add instruction to query objects with npm view (#5527) * add instruction to query objects with npm view * fix package version in example command in npm-view docs --- docs/content/commands/npm-view.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/content/commands/npm-view.md b/docs/content/commands/npm-view.md index d9d1daac0cda7..9e07619c204cf 100644 --- a/docs/content/commands/npm-view.md +++ b/docs/content/commands/npm-view.md @@ -72,6 +72,12 @@ contributor in the list, you can run: npm view express contributors[0].email ``` +If the field value you are querying for is a property of an object, you should run: + +```bash +npm view express time'[4.8.0]' +``` + Multiple fields may be specified, and will be printed one after another. For example, to get all the contributor names and email addresses, you can do this: From 9e05ecde86e5d760f0dd930c0d6b80576928780d Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 21 Sep 2022 18:34:35 -0700 Subject: [PATCH 26/40] chore(ci): use globally installed npm executable (#5555) --- .github/workflows/ci-release.yml | 9 ++++++--- docs/package.json | 3 ++- package-lock.json | 2 +- scripts/template-oss/ci-release.yml | 9 ++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 3aa582dbcb84c..e818fc6b49703 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -202,14 +202,17 @@ jobs: node . version $NPM_VERSION --ignore-scripts node . run resetdeps git clean -fd - node . ls --production >/dev/null - node . prune --production --no-save --no-audit --no-fund + node . ls --omit=dev >/dev/null + node . prune --omit=dev --no-save --no-audit --no-fund node scripts/git-dirty.js node . pack --pack-destination=$RUNNER_TEMP node . install -g $RUNNER_TEMP/npm-$NPM_VERSION.tgz node . install -w smoke-tests --ignore-scripts --no-audit --no-fund rm -rf {lib,bin,index.js} - SMOKE_PUBLISH_NPM=1 node . test -w smoke-tests --ignore-scripts + # this one should be npm since we explicitly installed our packed + # tarball globally and the next test will make sure our the new + # globally installed version contains the git sha + SMOKE_PUBLISH_NPM=1 npm test -w smoke-tests --ignore-scripts - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 if: always() diff --git a/docs/package.json b/docs/package.json index 768c7318e4cec..1ea9f668d2008 100644 --- a/docs/package.json +++ b/docs/package.json @@ -39,7 +39,7 @@ "nav.yml" ], "engines": { - "node": ">=18.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "tap": { "statements": 81, @@ -63,6 +63,7 @@ "/nav.yml" ], "ciVersions": "latest", + "engines": "^14.17.0 || ^16.13.0 || >=18.0.0", "version": "4.3.2", "content": "../scripts/template-oss/index.js" } diff --git a/package-lock.json b/package-lock.json index 069cf6dc0bd53..36a2761bc4627 100644 --- a/package-lock.json +++ b/package-lock.json @@ -199,7 +199,7 @@ "yaml": "^1.10.0" }, "engines": { - "node": ">=18.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@actions/core": { diff --git a/scripts/template-oss/ci-release.yml b/scripts/template-oss/ci-release.yml index 93dd4f1edeed3..b486ad411b565 100644 --- a/scripts/template-oss/ci-release.yml +++ b/scripts/template-oss/ci-release.yml @@ -12,12 +12,15 @@ {{ rootNpmPath }} version $NPM_VERSION --ignore-scripts {{ rootNpmPath }} run resetdeps git clean -fd - {{ rootNpmPath }} ls --production >/dev/null - {{ rootNpmPath }} prune --production --no-save --no-audit --no-fund + {{ rootNpmPath }} ls --omit=dev >/dev/null + {{ rootNpmPath }} prune --omit=dev --no-save --no-audit --no-fund node scripts/git-dirty.js {{ rootNpmPath }} pack --pack-destination=$RUNNER_TEMP {{ rootNpmPath }} install -g $RUNNER_TEMP/npm-$NPM_VERSION.tgz {{ rootNpmPath }} install -w smoke-tests --ignore-scripts --no-audit --no-fund rm -rf {lib,bin,index.js} - SMOKE_PUBLISH_NPM=1 {{ rootNpmPath }} test -w smoke-tests --ignore-scripts + # this one should be npm since we explicitly installed our packed + # tarball globally and the next test will make sure our the new + # globally installed version contains the git sha + SMOKE_PUBLISH_NPM=1 npm test -w smoke-tests --ignore-scripts {{> stepChecks jobCheck=true }} From 07922e9362170ac804b4bca978bc5d2b1ea7b6d0 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 21 Sep 2022 19:34:54 -0700 Subject: [PATCH 27/40] chore(ci): turn off smoke publish that test doesnt work on windows (#5557) --- .github/workflows/ci-release.yml | 3 --- scripts/template-oss/ci-release.yml | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index e818fc6b49703..293f07defd039 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -151,9 +151,6 @@ jobs: - name: macOS os: macos-latest shell: bash - - name: Windows - os: windows-latest - shell: cmd node-version: - 14.17.0 - 14.x diff --git a/scripts/template-oss/ci-release.yml b/scripts/template-oss/ci-release.yml index b486ad411b565..6d30953715fb7 100644 --- a/scripts/template-oss/ci-release.yml +++ b/scripts/template-oss/ci-release.yml @@ -5,6 +5,7 @@ jobName="Smoke Publish" jobCheck=(obj sha="${{ inputs.check-sha }}") jobCheckout=(obj ref="${{ inputs.ref }}") + windowsCI=false }} - name: Pack run: | From 83fd0a8cde591c03c5b0888e34cb71e3e1e29e66 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 21 Sep 2022 21:57:21 -0700 Subject: [PATCH 28/40] chore: @npmcli/template-oss@4.4.1 (#5559) --- .github/workflows/audit.yml | 2 +- .github/workflows/ci-docs.yml | 30 ++++++++++++++++++++ .github/workflows/ci-libnpmaccess.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmdiff.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmexec.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmfund.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmhook.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmorg.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmpack.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmpublish.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmsearch.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmteam.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-libnpmversion.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-npmcli-arborist.yml | 33 ++++++++++++++++++++++ .github/workflows/ci-smoke-tests.yml | 33 ++++++++++++++++++++++ .github/workflows/ci.yml | 6 ++++ .github/workflows/post-dependabot.yml | 35 ++++++++++++++++++++--- docs/package.json | 4 +-- package-lock.json | 36 ++++++++++++------------ package.json | 6 ++-- scripts/resetdeps.sh | 2 +- scripts/template-oss/_step-deps.yml | 2 +- smoke-tests/package.json | 4 +-- workspaces/arborist/package.json | 4 +-- workspaces/libnpmaccess/package.json | 4 +-- workspaces/libnpmdiff/package.json | 4 +-- workspaces/libnpmexec/package.json | 4 +-- workspaces/libnpmfund/package.json | 4 +-- workspaces/libnpmhook/package.json | 4 +-- workspaces/libnpmorg/package.json | 4 +-- workspaces/libnpmpack/package.json | 4 +-- workspaces/libnpmpublish/package.json | 4 +-- workspaces/libnpmsearch/package.json | 4 +-- workspaces/libnpmteam/package.json | 4 +-- workspaces/libnpmversion/package.json | 4 +-- 35 files changed, 548 insertions(+), 56 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 1eca24a409ce3..281331a54adc4 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -29,6 +29,6 @@ jobs: node-version: 18.x cache: npm - name: Reset Deps - run: node . run resetdeps + run: node . run resetdeps -- --package-lock - name: Run Audit run: node . audit diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index ac92fead94a8b..de61207772fb4 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -18,6 +18,36 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmaccess.yml b/.github/workflows/ci-libnpmaccess.yml index 4b30b54b1ef95..14184d8348249 100644 --- a/.github/workflows/ci-libnpmaccess.yml +++ b/.github/workflows/ci-libnpmaccess.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmdiff.yml b/.github/workflows/ci-libnpmdiff.yml index f1a8fd846d2c0..b6aced374ea0e 100644 --- a/.github/workflows/ci-libnpmdiff.yml +++ b/.github/workflows/ci-libnpmdiff.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmexec.yml b/.github/workflows/ci-libnpmexec.yml index eccbd943d6a32..ac48176a8e027 100644 --- a/.github/workflows/ci-libnpmexec.yml +++ b/.github/workflows/ci-libnpmexec.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmfund.yml b/.github/workflows/ci-libnpmfund.yml index acd8a5e00afd3..1a626c1075a50 100644 --- a/.github/workflows/ci-libnpmfund.yml +++ b/.github/workflows/ci-libnpmfund.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmhook.yml b/.github/workflows/ci-libnpmhook.yml index e2f6eb8c263a6..a7cd58450ed98 100644 --- a/.github/workflows/ci-libnpmhook.yml +++ b/.github/workflows/ci-libnpmhook.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmorg.yml b/.github/workflows/ci-libnpmorg.yml index 05ab19a41f0b9..7a1b556aee2f4 100644 --- a/.github/workflows/ci-libnpmorg.yml +++ b/.github/workflows/ci-libnpmorg.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmpack.yml b/.github/workflows/ci-libnpmpack.yml index 12a17c594a7b3..1718b28c22904 100644 --- a/.github/workflows/ci-libnpmpack.yml +++ b/.github/workflows/ci-libnpmpack.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmpublish.yml b/.github/workflows/ci-libnpmpublish.yml index ad28f216d86d7..73036ee7a097c 100644 --- a/.github/workflows/ci-libnpmpublish.yml +++ b/.github/workflows/ci-libnpmpublish.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmsearch.yml b/.github/workflows/ci-libnpmsearch.yml index 51243c33b4034..7f2f9d01df682 100644 --- a/.github/workflows/ci-libnpmsearch.yml +++ b/.github/workflows/ci-libnpmsearch.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmteam.yml b/.github/workflows/ci-libnpmteam.yml index d69e4bdb1e8fd..b318301db7172 100644 --- a/.github/workflows/ci-libnpmteam.yml +++ b/.github/workflows/ci-libnpmteam.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-libnpmversion.yml b/.github/workflows/ci-libnpmversion.yml index 23ec19dd12541..ce01e5fcae40e 100644 --- a/.github/workflows/ci-libnpmversion.yml +++ b/.github/workflows/ci-libnpmversion.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-npmcli-arborist.yml b/.github/workflows/ci-npmcli-arborist.yml index 07caf1ec63339..9ee54d5ed88c0 100644 --- a/.github/workflows/ci-npmcli-arborist.yml +++ b/.github/workflows/ci-npmcli-arborist.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci-smoke-tests.yml b/.github/workflows/ci-smoke-tests.yml index 29033c6c462ad..a075d0cb8b6c1 100644 --- a/.github/workflows/ci-smoke-tests.yml +++ b/.github/workflows/ci-smoke-tests.yml @@ -18,6 +18,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c13550bd14a5d..bfbec9a2fd324 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,11 +6,17 @@ on: workflow_dispatch: pull_request: paths-ignore: + - docs/** + - smoke-tests/** + - workspaces/** push: branches: - main - latest paths-ignore: + - docs/** + - smoke-tests/** + - workspaces/** schedule: # "At 09:00 UTC (02:00 PT) on Monday" https://crontab.guru/#0_9_*_*_1 - cron: "0 9 * * 1" diff --git a/.github/workflows/post-dependabot.yml b/.github/workflows/post-dependabot.yml index 1302c7a80d31a..f488974da3f63 100644 --- a/.github/workflows/post-dependabot.yml +++ b/.github/workflows/post-dependabot.yml @@ -57,6 +57,15 @@ jobs: if [[ `git status --porcelain` ]]; then echo "::set-output name=changes::true" fi + # This only sets the conventional commit prefix. This workflow can't reliably determine + # what the breaking change is though. If a BREAKING CHANGE message is required then + # this PR check will fail and the commit will be amended with stafftools + if [[ "${{ steps.dependabot-metadata.outputs.update-type }}" == "version-update:semver-major" ]]; then + prefix='feat!' + else + prefix='chore!' + fi + echo "::set-output name=message::$prefix: postinstall for dependabot template-oss PR" # This step will fail if template-oss has made any workflow updates. It is impossible # for a workflow to update other workflows. In the case it does fail, we continue @@ -68,21 +77,39 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - git commit -am "chore: postinstall for dependabot template-oss PR" + git commit -am "${{ steps.apply.outputs.message }}" git push - - name: Push All Changes Except Workflows - if: steps.push.outcome == 'failure' + # If the previous step failed, then reset the commit and remove any workflow changes + # and attempt to commit and push again. This is helpful because we will have a commit + # with the correct prefix that we can then --amend with @npmcli/stafftools later. + - name: Commit and push all changes except workflows + if: steps.apply.outputs.changes && steps.push-all.outcome == 'failure' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git reset HEAD~ git checkout HEAD -- .github/workflows/ git clean -fd .github/workflows/ - git commit -am "chore: postinstall for dependabot template-oss PR" + git commit -am "${{ steps.apply.outputs.message }}" git push + # Check if all the necessary template-oss changes were applied. Since we continued + # on errors in one of the previous steps, this check will fail if our follow up + # only applied a portion of the changes and we need to followup manually. + # + # Note that this used to run `lint` and `postlint` but that will fail this action + # if we've also shipped any linting changes separate from template-oss. We do + # linting in another action, so we want to fail this one only if there are + # template-oss changes that could not be applied. - name: Check Changes if: steps.apply.outputs.changes run: | node . exec --offline ${{ steps.flags.outputs.workspace }} -- template-oss-check + + - name: Fail on Breaking Change + if: steps.apply.outputs.changes && startsWith(steps.apply.outputs.message, 'feat!') + run: | + echo "This PR has a breaking change. Run 'npx -p @npmcli/stafftools gh template-oss-fix'" + echo "for more information on how to fix this with a BREAKING CHANGE footer." + exit 1 diff --git a/docs/package.json b/docs/package.json index 1ea9f668d2008..adcf96d571507 100644 --- a/docs/package.json +++ b/docs/package.json @@ -22,7 +22,7 @@ "@npmcli/eslint-config": "^3.1.0", "@npmcli/fs": "^2.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "cmark-gfm": "^0.9.0", "jsdom": "^18.1.0", "marked-man": "^0.7.0", @@ -64,7 +64,7 @@ ], "ciVersions": "latest", "engines": "^14.17.0 || ^16.13.0 || >=18.0.0", - "version": "4.3.2", + "version": "4.4.1", "content": "../scripts/template-oss/index.js" } } diff --git a/package-lock.json b/package-lock.json index 36a2761bc4627..3ae425d6dde70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -169,7 +169,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "@octokit/rest": "^19.0.4", "fs-minipass": "^2.1.0", "licensee": "^8.2.0", @@ -190,7 +190,7 @@ "@npmcli/eslint-config": "^3.1.0", "@npmcli/fs": "^2.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "cmark-gfm": "^0.9.0", "jsdom": "^18.1.0", "marked-man": "^0.7.0", @@ -2363,9 +2363,9 @@ } }, "node_modules/@npmcli/template-oss": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@npmcli/template-oss/-/template-oss-4.3.2.tgz", - "integrity": "sha512-4sVkA9hvoRlGDxZ+UtiE5YEvJWAFUiY3tzi2N8zAxsgf1qS0HkrVBqRJikBRzleUBjmYLrxAI1qqY8Lz/ubupg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@npmcli/template-oss/-/template-oss-4.4.1.tgz", + "integrity": "sha512-HWzfbkCJD2R7LT5gZy6yZJDf+TX+B3j4HkwJ04MWI//QFsKSGiWon37B8vhF84SdCVpRgrCRX9VQmBf2sooePg==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -13852,7 +13852,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "minify-registry-metadata": "^2.2.0", "rimraf": "^3.0.2", "tap": "^16.0.1", @@ -13909,7 +13909,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "benchmark": "^2.1.4", "chalk": "^4.1.0", "minify-registry-metadata": "^2.1.0", @@ -13930,7 +13930,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -13953,7 +13953,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "tap": "^16.0.1" }, "engines": { @@ -13981,7 +13981,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "bin-links": "^3.0.3", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", @@ -13999,7 +13999,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "tap": "^16.0.1" }, "engines": { @@ -14015,7 +14015,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14032,7 +14032,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "minipass": "^3.1.1", "nock": "^13.2.4", "tap": "^16.0.1" @@ -14051,7 +14051,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.0.7", "tap": "^16.0.1" }, @@ -14071,7 +14071,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "libnpmpack": "^5.0.0-pre.0", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", @@ -14089,7 +14089,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14106,7 +14106,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -14126,7 +14126,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "require-inject": "^1.4.4", "tap": "^16.0.1" }, diff --git a/package.json b/package.json index a9e872d7253c6..a78713a136130 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "@octokit/rest": "^19.0.4", "fs-minipass": "^2.1.0", "licensee": "^8.2.0", @@ -254,11 +254,11 @@ "--exclude", "tap-snapshots/**" ], - "test-ignore": "^(docs|smoke-tests|workspaces)/**" + "test-ignore": "^(docs|smoke-tests|workspaces)/" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "./scripts/template-oss/root.js" }, "license": "Artistic-2.0", diff --git a/scripts/resetdeps.sh b/scripts/resetdeps.sh index d73ce845888c7..758edef648bda 100755 --- a/scripts/resetdeps.sh +++ b/scripts/resetdeps.sh @@ -6,6 +6,6 @@ rm -rf docs/node_modules rm -rf smoke-tests/node_modules rm -rf "workspaces/*/node_modules" git checkout node_modules -node . i --ignore-scripts --no-audit --no-fund +node . i --ignore-scripts --no-audit --no-fund "$@" node . rebuild --ignore-scripts node . run dependencies --ignore-scripts diff --git a/scripts/template-oss/_step-deps.yml b/scripts/template-oss/_step-deps.yml index 2f77eabdc4337..22f8d00c7a6fd 100644 --- a/scripts/template-oss/_step-deps.yml +++ b/scripts/template-oss/_step-deps.yml @@ -1,2 +1,2 @@ - name: Reset Deps - run: {{rootNpmPath}} run resetdeps + run: {{rootNpmPath}} run resetdeps {{~#if jobDepFlags}} -- {{ jobDepFlags }}{{/if}} diff --git a/smoke-tests/package.json b/smoke-tests/package.json index 829d81952b2d9..97262585821c4 100644 --- a/smoke-tests/package.json +++ b/smoke-tests/package.json @@ -20,7 +20,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "minify-registry-metadata": "^2.2.0", "rimraf": "^3.0.2", "tap": "^16.0.1", @@ -30,7 +30,7 @@ "license": "ISC", "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 58a156da8ce6b..a93a171bbd895 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "benchmark": "^2.1.4", "chalk": "^4.1.0", "minify-registry-metadata": "^2.1.0", @@ -104,7 +104,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmaccess/package.json b/workspaces/libnpmaccess/package.json index 90370d67d9b95..dcf7e09f37677 100644 --- a/workspaces/libnpmaccess/package.json +++ b/workspaces/libnpmaccess/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -40,7 +40,7 @@ ], "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index cdc9191064f32..6b3e12e4fc3fb 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -43,7 +43,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "tap": "^16.0.1" }, "dependencies": { @@ -58,7 +58,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 3c91e89dc34b0..54b02e44d83e7 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -51,7 +51,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "bin-links": "^3.0.3", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", @@ -75,7 +75,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" } } diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index f6c2406153723..fe4d1b98a4dcd 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -42,7 +42,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "tap": "^16.0.1" }, "dependencies": { @@ -53,7 +53,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmhook/package.json b/workspaces/libnpmhook/package.json index ee4b535ea14fd..63382d3e3f043 100644 --- a/workspaces/libnpmhook/package.json +++ b/workspaces/libnpmhook/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -46,7 +46,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmorg/package.json b/workspaces/libnpmorg/package.json index 23f3a5c8438dd..0e6db28eefde9 100644 --- a/workspaces/libnpmorg/package.json +++ b/workspaces/libnpmorg/package.json @@ -28,7 +28,7 @@ ], "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "minipass": "^3.1.1", "nock": "^13.2.4", "tap": "^16.0.1" @@ -49,7 +49,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index a41236feb4d8e..96c9589a8cad3 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.0.7", "tap": "^16.0.1" }, @@ -44,7 +44,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index cfccf0131b291..ea2fdc181d0c0 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "libnpmpack": "^5.0.0-pre.0", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", @@ -50,7 +50,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmsearch/package.json b/workspaces/libnpmsearch/package.json index 2a8b7a0ef7520..cb670ca35ad63 100644 --- a/workspaces/libnpmsearch/package.json +++ b/workspaces/libnpmsearch/package.json @@ -26,7 +26,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -45,7 +45,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmteam/package.json b/workspaces/libnpmteam/package.json index ea859f4900cce..85849a75a9502 100644 --- a/workspaces/libnpmteam/package.json +++ b/workspaces/libnpmteam/package.json @@ -16,7 +16,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "nock": "^13.2.4", "tap": "^16.0.1" }, @@ -39,7 +39,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" }, "tap": { diff --git a/workspaces/libnpmversion/package.json b/workspaces/libnpmversion/package.json index 83aaf8ab87176..c01e7f6956405 100644 --- a/workspaces/libnpmversion/package.json +++ b/workspaces/libnpmversion/package.json @@ -32,7 +32,7 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "4.3.2", + "@npmcli/template-oss": "4.4.1", "require-inject": "^1.4.4", "tap": "^16.0.1" }, @@ -48,7 +48,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "4.3.2", + "version": "4.4.1", "content": "../../scripts/template-oss/index.js" } } From 578ed5e028f9c343d2852c53add1e9b3f6ea42dc Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Thu, 22 Sep 2022 08:54:47 -0700 Subject: [PATCH 29/40] chore: extend ci and test steps from template-oss (#5560) --- .github/workflows/ci-docs.yml | 7 +- .github/workflows/ci-libnpmaccess.yml | 7 +- .github/workflows/ci-libnpmdiff.yml | 7 +- .github/workflows/ci-libnpmexec.yml | 7 +- .github/workflows/ci-libnpmfund.yml | 7 +- .github/workflows/ci-libnpmhook.yml | 7 +- .github/workflows/ci-libnpmorg.yml | 7 +- .github/workflows/ci-libnpmpack.yml | 7 +- .github/workflows/ci-libnpmpublish.yml | 7 +- .github/workflows/ci-libnpmsearch.yml | 7 +- .github/workflows/ci-libnpmteam.yml | 7 +- .github/workflows/ci-libnpmversion.yml | 7 +- .github/workflows/ci-npmcli-arborist.yml | 7 +- .github/workflows/ci-release.yml | 7 +- .github/workflows/ci-smoke-tests.yml | 7 +- .github/workflows/ci.yml | 139 ++++++++++++++--------- Makefile | 7 +- scripts/template-oss/_step-test.yml | 8 +- scripts/template-oss/ci.yml | 19 +--- 19 files changed, 172 insertions(+), 106 deletions(-) diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index de61207772fb4..dfa32c0ee9ed4 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -110,12 +110,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w docs + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmaccess.yml b/.github/workflows/ci-libnpmaccess.yml index 14184d8348249..412d64f1cefd2 100644 --- a/.github/workflows/ci-libnpmaccess.yml +++ b/.github/workflows/ci-libnpmaccess.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmaccess + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmdiff.yml b/.github/workflows/ci-libnpmdiff.yml index b6aced374ea0e..c0548e19ca470 100644 --- a/.github/workflows/ci-libnpmdiff.yml +++ b/.github/workflows/ci-libnpmdiff.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmdiff + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmexec.yml b/.github/workflows/ci-libnpmexec.yml index ac48176a8e027..4134cc8400bf0 100644 --- a/.github/workflows/ci-libnpmexec.yml +++ b/.github/workflows/ci-libnpmexec.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmexec + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmfund.yml b/.github/workflows/ci-libnpmfund.yml index 1a626c1075a50..5c3c9bdf0041e 100644 --- a/.github/workflows/ci-libnpmfund.yml +++ b/.github/workflows/ci-libnpmfund.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmfund + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmhook.yml b/.github/workflows/ci-libnpmhook.yml index a7cd58450ed98..7204c1b89f428 100644 --- a/.github/workflows/ci-libnpmhook.yml +++ b/.github/workflows/ci-libnpmhook.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmhook + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmorg.yml b/.github/workflows/ci-libnpmorg.yml index 7a1b556aee2f4..68c44992dac28 100644 --- a/.github/workflows/ci-libnpmorg.yml +++ b/.github/workflows/ci-libnpmorg.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmorg + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmpack.yml b/.github/workflows/ci-libnpmpack.yml index 1718b28c22904..d4cbf4107336f 100644 --- a/.github/workflows/ci-libnpmpack.yml +++ b/.github/workflows/ci-libnpmpack.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmpack + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmpublish.yml b/.github/workflows/ci-libnpmpublish.yml index 73036ee7a097c..f0bdcbc4cd732 100644 --- a/.github/workflows/ci-libnpmpublish.yml +++ b/.github/workflows/ci-libnpmpublish.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmpublish + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmsearch.yml b/.github/workflows/ci-libnpmsearch.yml index 7f2f9d01df682..0df5f0932a581 100644 --- a/.github/workflows/ci-libnpmsearch.yml +++ b/.github/workflows/ci-libnpmsearch.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmsearch + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmteam.yml b/.github/workflows/ci-libnpmteam.yml index b318301db7172..7f28450a77b71 100644 --- a/.github/workflows/ci-libnpmteam.yml +++ b/.github/workflows/ci-libnpmteam.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmteam + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-libnpmversion.yml b/.github/workflows/ci-libnpmversion.yml index ce01e5fcae40e..a5e7af85958aa 100644 --- a/.github/workflows/ci-libnpmversion.yml +++ b/.github/workflows/ci-libnpmversion.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w libnpmversion + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-npmcli-arborist.yml b/.github/workflows/ci-npmcli-arborist.yml index 9ee54d5ed88c0..445eba9b50022 100644 --- a/.github/workflows/ci-npmcli-arborist.yml +++ b/.github/workflows/ci-npmcli-arborist.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w @npmcli/arborist + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci-release.yml b/.github/workflows/ci-release.yml index 293f07defd039..8b3a77ea6d19d 100644 --- a/.github/workflows/ci-release.yml +++ b/.github/workflows/ci-release.yml @@ -121,15 +121,18 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -ws -iwr --if-present + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js - name: Conclude Check uses: LouisBrunner/checks-action@v1.3.1 if: always() diff --git a/.github/workflows/ci-smoke-tests.yml b/.github/workflows/ci-smoke-tests.yml index a075d0cb8b6c1..91cc8b6cdd770 100644 --- a/.github/workflows/ci-smoke-tests.yml +++ b/.github/workflows/ci-smoke-tests.yml @@ -118,12 +118,15 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: node . link -f --ignore-scripts - name: Rebuild cmark-gfm run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" - name: Test run: node . test --ignore-scripts -w smoke-tests + - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfbec9a2fd324..13ee90e7e06ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ # This file is automatically added by @npmcli/template-oss. Do not edit. -name: CI - cli +name: CI on: workflow_dispatch: @@ -22,6 +22,39 @@ on: - cron: "0 9 * * 1" jobs: + engines: + name: Engines - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + if: github.repository_owner == 'npm' + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + node-version: + - 14.17.0 + - 16.13.0 + - 18.0.0 + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Git User + run: | + git config --global user.email "npm-cli+bot@github.com" + git config --global user.name "npm CLI robot" + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + cache: npm + - name: Reset Deps + run: node . run resetdeps -- --engines-strict + lint: name: Lint if: github.repository_owner == 'npm' @@ -48,13 +81,33 @@ jobs: - name: Post Lint run: node . run postlint --ignore-scripts - check-docs: - name: Check Docs + test: + name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} if: github.repository_owner == 'npm' - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + platform: + - name: Linux + os: ubuntu-latest + shell: bash + - name: macOS + os: macos-latest + shell: bash + - name: Windows + os: windows-latest + shell: cmd + node-version: + - 14.17.0 + - 14.x + - 16.13.0 + - 16.x + - 18.0.0 + - 18.x + runs-on: ${{ matrix.platform.os }} defaults: run: - shell: bash + shell: ${{ matrix.platform.shell }} steps: - name: Checkout uses: actions/checkout@v3 @@ -65,17 +118,25 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: 18.x + node-version: ${{ matrix.node-version }} cache: npm - name: Reset Deps run: node . run resetdeps - - name: Make Docs - run: make freshdocs + - name: Link + if: matrix + run: node . link -f --ignore-scripts + - name: Rebuild cmark-gfm + run: node . rebuild cmark-gfm + - name: Add Problem Matcher + run: echo "::add-matcher::.github/matchers/tap.json" + - name: Test + run: node . test --ignore-scripts -iwr - name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' run: node scripts/git-dirty.js - licenses: - name: Check Licenses + check-docs: + name: Check Docs if: github.repository_owner == 'npm' runs-on: ubuntu-latest defaults: @@ -95,11 +156,13 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Check Licenses - run: node . run licenses + - name: Make Docs + run: make freshdocs + - name: Check Git Status + run: node scripts/git-dirty.js - smoke-tests: - name: Smoke Tests + licenses: + name: Check Licenses if: github.repository_owner == 'npm' runs-on: ubuntu-latest defaults: @@ -119,38 +182,16 @@ jobs: cache: npm - name: Reset Deps run: node . run resetdeps - - name: Run Smoke Tests - run: node . test -w smoke-tests --ignore-scripts - - name: Check Git Status - run: node scripts/git-dirty.js + - name: Check Licenses + run: node . run licenses - test: - name: Test - ${{ matrix.platform.name }} - ${{ matrix.node-version }} + smoke-tests: + name: Smoke Tests if: github.repository_owner == 'npm' - strategy: - fail-fast: false - matrix: - platform: - - name: Linux - os: ubuntu-latest - shell: bash - - name: macOS - os: macos-latest - shell: bash - - name: Windows - os: windows-latest - shell: cmd - node-version: - - 14.17.0 - - 14.x - - 16.13.0 - - 16.x - - 18.0.0 - - 18.x - runs-on: ${{ matrix.platform.os }} + runs-on: ubuntu-latest defaults: run: - shell: ${{ matrix.platform.shell }} + shell: bash steps: - name: Checkout uses: actions/checkout@v3 @@ -161,19 +202,11 @@ jobs: - name: Setup Node uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: 18.x cache: npm - name: Reset Deps run: node . run resetdeps - - name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - - name: Link - if: matrix - run: node . link -f --ignore-scripts - - name: Rebuild cmark-gfm - run: node . rebuild cmark-gfm - - name: Test - run: node . test --ignore-scripts -iwr + - name: Run Smoke Tests + run: node . test -w smoke-tests --ignore-scripts - name: Check Git Status - if: matrix.platform.os != 'windows-latest' run: node scripts/git-dirty.js diff --git a/Makefile b/Makefile index 5c153511e31af..484c5152f0292 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,9 @@ freshdocs: make docs make mddocs +lint-all: deps + node bin/npm-cli.js run lint-all + test-all: deps node bin/npm-cli.js run test-all @@ -110,10 +113,10 @@ prune: deps node bin/npm-cli.js prune --omit=dev --no-save --no-audit --no-fund node scripts/git-dirty.js -publish: gitclean ls-ok link test-all docs prune +publish: gitclean ls-ok link lint-all test-all docs prune node bin/npm-cli.js publish --tag=$(PUBLISHTAG) release: gitclean ls-ok docs prune @bash scripts/release.sh -.PHONY: all latest install dev link docs mddocs clean uninstall test-all man docsclean release ls-ok deps prune freshdocs +.PHONY: all latest install dev link docs mddocs clean uninstall lint-all test-all man docsclean release ls-ok deps prune freshdocs diff --git a/scripts/template-oss/_step-test.yml b/scripts/template-oss/_step-test.yml index 195dc2991e6c3..3eb0aa8971381 100644 --- a/scripts/template-oss/_step-test.yml +++ b/scripts/template-oss/_step-test.yml @@ -1,9 +1,9 @@ -- name: Add Problem Matcher - run: echo "::add-matcher::.github/matchers/tap.json" - name: Link if: matrix run: {{ rootNpmPath }} link -f --ignore-scripts - name: Rebuild cmark-gfm run: {{ rootNpmPath }} rebuild cmark-gfm -- name: Test - run: {{ rootNpmPath }} test --ignore-scripts {{~#if jobRunFlags}} {{ jobRunFlags }}{{/if}} +{{> defaultStepTest }} +- name: Check Git Status + if: matrix && matrix.platform.os != 'windows-latest' + run: node scripts/git-dirty.js diff --git a/scripts/template-oss/ci.yml b/scripts/template-oss/ci.yml index 0ddffde96eec3..c78efe5e2c560 100644 --- a/scripts/template-oss/ci.yml +++ b/scripts/template-oss/ci.yml @@ -1,12 +1,4 @@ -name: CI - cli - -on: - {{> onCi }} - -jobs: - lint: - {{> job jobName="Lint" }} - {{> stepLint jobRunFlags=pkgFlags }} +{{> ci }} check-docs: {{> job jobName="Check Docs" }} @@ -25,11 +17,4 @@ jobs: - name: Run Smoke Tests run: {{rootNpmPath}} test -w smoke-tests --ignore-scripts - name: Check Git Status - run: node scripts/git-dirty.js - - test: - {{> jobMatrix jobName="Test" }} - {{> stepTest jobRunFlags=pkgFlags }} - - name: Check Git Status - if: matrix.platform.os != 'windows-latest' - run: node scripts/git-dirty.js + run: node scripts/git-dirty.js \ No newline at end of file From 00a36935fbfd5298b048fddbac2a0ec1088212d3 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Thu, 22 Sep 2022 20:49:15 -0700 Subject: [PATCH 30/40] chore(release-manager): get package name for workspace commands (#5562) --- scripts/release-manager.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/release-manager.js b/scripts/release-manager.js index 47a2f9a99814f..2d981ceb93c17 100644 --- a/scripts/release-manager.js +++ b/scripts/release-manager.js @@ -2,6 +2,11 @@ const { Octokit } = require('@octokit/rest') const semver = require('semver') +const mapWorkspaces = require('@npmcli/map-workspaces') +const { join } = require('path') + +const ROOT = process.cwd() +const pkg = require(join(ROOT, 'package.json')) const log = (...logs) => console.error('LOG', ...logs) @@ -33,7 +38,7 @@ const getReleaseProcess = async () => { [Symbol.split] (str) { const [, ...matches] = str.split(RELEASE_LIST_ITEM) log(`Found ${matches.length} release items`) - return matches.map((m, i) => `- [ ] . ${m}`.trim()) + return matches.map((m) => `- [ ] . ${m}`.trim()) }, }) } @@ -43,10 +48,18 @@ const getPrReleases = async (pr) => { const MONO_VERSIONS = /
(?:(.*?):\s)?(.*?)<\/summary>/ const ROOT_VERSION = /\n##\s\[(.*?)\]/ + const workspaces = [...await mapWorkspaces({ pkg: pkg, cwd: ROOT })].reduce((acc, [k]) => { + const wsComponentName = k.startsWith('@') ? k.split('/')[1] : k + acc[wsComponentName] = k + return acc + }, {}) + const getReleaseInfo = ({ name, version: rawVersion }) => { const version = semver.parse(rawVersion) const prerelease = !!version.prerelease.length const tag = `${name ? `${name}-` : ''}v${rawVersion}` + const workspace = workspaces[name] + return { name, tag, @@ -54,7 +67,7 @@ const getPrReleases = async (pr) => { version: rawVersion, major: version.major, url: `https://github.com/${pr.base.repo.full_name}/releases/tag/${tag}`, - flags: name ? `-w ${name} ${prerelease ? `--tag prerelease` : ''}`.trim() : '', + flags: name ? `-w ${workspace} ${prerelease ? `--tag prerelease` : ''}`.trim() : '', } } @@ -79,10 +92,10 @@ const getPrReleases = async (pr) => { const release = getReleaseInfo({ name, version }) if (!name) { - log('Found root', release.tag) + log('Found root', release) acc[0] = release } else { - log('Found workspace', release.tag) + log('Found workspace', release) acc[1].push(release) } From 84598fe2b84d57b812f53ecc0beba9a04e75c069 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 23 Sep 2022 03:50:41 +0000 Subject: [PATCH 31/40] chore: release 9.0.0-pre.2 --- .release-please-manifest.json | 8 +++---- AUTHORS | 4 ++++ CHANGELOG.md | 38 ++++++++++++++++++++++++++++++ package-lock.json | 20 ++++++++-------- package.json | 8 +++---- workspaces/arborist/CHANGELOG.md | 14 +++++++++++ workspaces/arborist/package.json | 2 +- workspaces/libnpmexec/CHANGELOG.md | 6 +++++ workspaces/libnpmexec/package.json | 4 ++-- workspaces/libnpmfund/CHANGELOG.md | 6 +++++ workspaces/libnpmfund/package.json | 4 ++-- 11 files changed, 91 insertions(+), 23 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 78ed38ff80b5b..6a8d9b04e0f32 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,10 +1,10 @@ { - ".": "9.0.0-pre.1", - "workspaces/arborist": "6.0.0-pre.1", + ".": "9.0.0-pre.2", + "workspaces/arborist": "6.0.0-pre.2", "workspaces/libnpmaccess": "7.0.0-pre.1", "workspaces/libnpmdiff": "5.0.0-pre.0", - "workspaces/libnpmexec": "5.0.0-pre.1", - "workspaces/libnpmfund": "4.0.0-pre.1", + "workspaces/libnpmexec": "5.0.0-pre.2", + "workspaces/libnpmfund": "4.0.0-pre.2", "workspaces/libnpmhook": "9.0.0-pre.0", "workspaces/libnpmorg": "5.0.0-pre.0", "workspaces/libnpmpack": "5.0.0-pre.0", diff --git a/AUTHORS b/AUTHORS index 313d036461b52..0742e96b5462d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -854,3 +854,7 @@ Nathan Hughes Sandeep Meduru <73886592+sandeepmeduru@users.noreply.github.com> Kid <44045911+kidonng@users.noreply.github.com> Hugh Lilly +Hafizur046 +Michael Rienstra +Juan Heyns +Michał Kurowski diff --git a/CHANGELOG.md b/CHANGELOG.md index 855e602bc19d3..689f7f19f8832 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # Changelog +## [9.0.0-pre.2](https://github.com/npm/cli/compare/v9.0.0-pre.1...v9.0.0-pre.2) (2022-09-23) + +### ⚠️ BREAKING CHANGES + +* the default `auth-type` config value is now `web` +* `login`, `adduser`, and `auth-type` changes + - This removes all `auth-type` configs except `web` and `legacy`. + - `login` and `adduser` are now separate commands that send different data to the registry. + - `auth-type` config values `web` and `legacy` only try + their respective methods, npm no longer tries them all and waits to see + which one doesn't fail. + +### Features + +* [`66ed584`](https://github.com/npm/cli/commit/66ed58454418dd69c4cd8196ad8499e73f7e46e1) [#5551](https://github.com/npm/cli/pull/5551) default auth-type to web (#5551) (@wraithgar) +* [`6ee5b32`](https://github.com/npm/cli/commit/6ee5b320d2eab58c18d50b861b3cfabe7f24124a) query: display `queryContext` in results (@nlf) +* [`314311c`](https://github.com/npm/cli/commit/314311c61b8f341715c168199d52976ee3237077) [#5550](https://github.com/npm/cli/pull/5550) separate login/adduser, remove auth types (#5550) (@wraithgar) + +### Bug Fixes + +* [`0d90a01`](https://github.com/npm/cli/commit/0d90a011fff411c878ba4b44582f14ef7dbdceb1) [#5480](https://github.com/npm/cli/pull/5480) audit: add a condition to allow third-party registries returning E400 (#5480) (@juanheyns, Juan Heyns) + +### Documentation + +* [`2d756cb`](https://github.com/npm/cli/commit/2d756cbb05125dcb769f2ca4c1687e42568d5882) [#5527](https://github.com/npm/cli/pull/5527) add instruction to query objects with npm view (#5527) (@moonith) +* [`8743366`](https://github.com/npm/cli/commit/874336699681ac37857167b2438fac19c059511c) [#5519](https://github.com/npm/cli/pull/5519) add hash to "tag" config link (#5519) (@mrienstra, @lukekarrys) +* [`5645c51`](https://github.com/npm/cli/commit/5645c51410a730c4b9c6831cf81ab22efbe8c0ce) [#5521](https://github.com/npm/cli/pull/5521) link mentions of config parameters (#5521) (@mrienstra) +* [`19762b4`](https://github.com/npm/cli/commit/19762b4ac4b10741ff53ddd315be1fd23d9b1e28) [#5529](https://github.com/npm/cli/pull/5529) modify Misleading doc about bins (@Hafizur046) +* [`19762b4`](https://github.com/npm/cli/commit/19762b4ac4b10741ff53ddd315be1fd23d9b1e28) [#5529](https://github.com/npm/cli/pull/5529) modify misleading doc about package.json:bin (#5529) (@Hafizur046) +* [`8402fd8`](https://github.com/npm/cli/commit/8402fd8780c5e0461850da882dca024f7df1a681) [#5547](https://github.com/npm/cli/pull/5547) add `:outdated` pseudo selector to docs (@nlf) + +### Dependencies + +* [`d030f10`](https://github.com/npm/cli/commit/d030f10fd535433e5a824df1b099f500a71075dd) `@npmcli/query@2.0.0` +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.1...arborist-v6.0.0-pre.2): `@npmcli/arborist@6.0.0-pre.2` +* [Workspace](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.1...libnpmexec-v5.0.0-pre.2): `libnpmexec@5.0.0-pre.2` +* [Workspace](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.1...libnpmfund-v4.0.0-pre.2): `libnpmfund@4.0.0-pre.2` + ## [9.0.0-pre.1](https://github.com/npm/cli/compare/v9.0.0-pre.0...v9.0.0-pre.1) (2022-09-14) ### ⚠️ BREAKING CHANGES diff --git a/package-lock.json b/package-lock.json index 3ae425d6dde70..43f364e27eb8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "9.0.0-pre.1", + "version": "9.0.0-pre.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npm", - "version": "9.0.0-pre.1", + "version": "9.0.0-pre.2", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -91,7 +91,7 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.0.0-pre.1", + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/ci-detect": "^2.0.0", "@npmcli/config": "^4.2.1", "@npmcli/fs": "^2.1.0", @@ -116,8 +116,8 @@ "json-parse-even-better-errors": "^2.3.1", "libnpmaccess": "^7.0.0-pre.1", "libnpmdiff": "^5.0.0-pre.0", - "libnpmexec": "^5.0.0-pre.1", - "libnpmfund": "^4.0.0-pre.1", + "libnpmexec": "^5.0.0-pre.2", + "libnpmfund": "^4.0.0-pre.2", "libnpmhook": "^9.0.0-pre.0", "libnpmorg": "^5.0.0-pre.0", "libnpmpack": "^5.0.0-pre.0", @@ -13864,7 +13864,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "6.0.0-pre.1", + "version": "6.0.0-pre.2", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -13961,10 +13961,10 @@ } }, "workspaces/libnpmexec": { - "version": "5.0.0-pre.1", + "version": "5.0.0-pre.2", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.1", + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.2.0", @@ -13992,10 +13992,10 @@ } }, "workspaces/libnpmfund": { - "version": "4.0.0-pre.1", + "version": "4.0.0-pre.2", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.1" + "@npmcli/arborist": "^6.0.0-pre.2" }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", diff --git a/package.json b/package.json index a78713a136130..7d0be98833116 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "9.0.0-pre.1", + "version": "9.0.0-pre.2", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -56,7 +56,7 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.0.0-pre.1", + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/ci-detect": "^2.0.0", "@npmcli/config": "^4.2.1", "@npmcli/fs": "^2.1.0", @@ -81,8 +81,8 @@ "json-parse-even-better-errors": "^2.3.1", "libnpmaccess": "^7.0.0-pre.1", "libnpmdiff": "^5.0.0-pre.0", - "libnpmexec": "^5.0.0-pre.1", - "libnpmfund": "^4.0.0-pre.1", + "libnpmexec": "^5.0.0-pre.2", + "libnpmfund": "^4.0.0-pre.2", "libnpmhook": "^9.0.0-pre.0", "libnpmorg": "^5.0.0-pre.0", "libnpmpack": "^5.0.0-pre.0", diff --git a/workspaces/arborist/CHANGELOG.md b/workspaces/arborist/CHANGELOG.md index c96cf00e7a8db..cd8e412efb9e7 100644 --- a/workspaces/arborist/CHANGELOG.md +++ b/workspaces/arborist/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [6.0.0-pre.2](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.1...arborist-v6.0.0-pre.2) (2022-09-23) + +### Features + +* [`ebf167b`](https://github.com/npm/cli/commit/ebf167b621ed14933826f617077ab5890e72bf83) add `:outdated` pseudo selector (@nlf) + +### Documentation + +* [`8402fd8`](https://github.com/npm/cli/commit/8402fd8780c5e0461850da882dca024f7df1a681) [#5547](https://github.com/npm/cli/pull/5547) add `:outdated` pseudo selector to docs (@nlf) + +### Dependencies + +* [`d030f10`](https://github.com/npm/cli/commit/d030f10fd535433e5a824df1b099f500a71075dd) `@npmcli/query@2.0.0` + ## [6.0.0-pre.1](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.0...arborist-v6.0.0-pre.1) (2022-09-14) ### Bug Fixes diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index a93a171bbd895..8082cf820d2f2 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "6.0.0-pre.1", + "version": "6.0.0-pre.2", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", diff --git a/workspaces/libnpmexec/CHANGELOG.md b/workspaces/libnpmexec/CHANGELOG.md index 79486595a645f..972bf585f3cab 100644 --- a/workspaces/libnpmexec/CHANGELOG.md +++ b/workspaces/libnpmexec/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.0-pre.2](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.1...libnpmexec-v5.0.0-pre.2) (2022-09-23) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.1...arborist-v6.0.0-pre.2): `@npmcli/arborist@6.0.0-pre.2` + ## [5.0.0-pre.1](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.0...libnpmexec-v5.0.0-pre.1) (2022-09-14) ### Dependencies diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 54b02e44d83e7..0f2dde78fcc23 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "5.0.0-pre.1", + "version": "5.0.0-pre.2", "files": [ "bin/", "lib/" @@ -58,7 +58,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.1", + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.2.0", diff --git a/workspaces/libnpmfund/CHANGELOG.md b/workspaces/libnpmfund/CHANGELOG.md index e10f4b45bb352..440951a45b302 100644 --- a/workspaces/libnpmfund/CHANGELOG.md +++ b/workspaces/libnpmfund/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.0.0-pre.2](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.1...libnpmfund-v4.0.0-pre.2) (2022-09-23) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.1...arborist-v6.0.0-pre.2): `@npmcli/arborist@6.0.0-pre.2` + ## [4.0.0-pre.1](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.0...libnpmfund-v4.0.0-pre.1) (2022-09-14) ### Dependencies diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index fe4d1b98a4dcd..43a90df172d53 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "4.0.0-pre.1", + "version": "4.0.0-pre.2", "main": "lib/index.js", "files": [ "bin/", @@ -46,7 +46,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.1" + "@npmcli/arborist": "^6.0.0-pre.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" From 3445da0138f9eed9d73d2b3f5f451fcc1fa2e3fe Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Fri, 23 Sep 2022 13:50:57 -0700 Subject: [PATCH 32/40] feat: timings are now written alongside debug log files BREAKING CHANGE: `--timing` file changes: - When run with the `--timing` flag, `npm` now writes timing data to a file alongside the debug log data, respecting the `logs-dir` option and falling back to `/_logs/` dir, instead of directly inside the cache directory. - The timing file data is no longer newline delimited JSON, and instead each run will create a uniquely named `-timing.json` file, with the `` portion being the same as the debug log. - Finally, the data inside the file now has three top level keys, `metadata`, `timers, and `unfinishedTimers` instead of everything being a top level key. Closes https://github.com/npm/statusboard/issues/456 --- docs/content/using-npm/config.md | 7 ++- docs/content/using-npm/logging.md | 8 +-- lib/npm.js | 16 ++---- lib/utils/config/definitions.js | 8 ++- lib/utils/display.js | 29 +++++----- lib/utils/log-file.js | 54 ++++++++----------- lib/utils/run-id.js | 3 ++ lib/utils/timers.js | 43 ++++++++------- .../lib/utils/config/definitions.js.test.cjs | 7 ++- .../lib/utils/config/describe-all.js.test.cjs | 7 ++- test/fixtures/mock-npm.js | 4 +- test/lib/npm.js | 20 ++++--- test/lib/utils/exit-handler.js | 30 ++++++----- test/lib/utils/log-file.js | 3 +- test/lib/utils/timers.js | 10 ++-- 15 files changed, 118 insertions(+), 131 deletions(-) create mode 100644 lib/utils/run-id.js diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index 2b05c842f1190..2de35fa2a46c3 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -1707,12 +1707,11 @@ particular, use care when overriding this setting for public packages. * Default: false * Type: Boolean -If true, writes a debug log to `logs-dir` and timing information to -`_timing.json` in the cache, even if the command completes successfully. -`_timing.json` is a newline delimited list of JSON objects. +If true, writes timing information to a process specific json file in the +cache or `logs-dir`. The file name ends with `-timing.json`. You can quickly view it with this [json](https://npm.im/json) command line: -`npm exec -- json -g < ~/.npm/_timing.json`. +`cat ~/.npm/_logs/*-timing.json | npm exec -- json -g`. diff --git a/docs/content/using-npm/logging.md b/docs/content/using-npm/logging.md index d699c8dca6ccc..e52c19004d542 100644 --- a/docs/content/using-npm/logging.md +++ b/docs/content/using-npm/logging.md @@ -12,8 +12,7 @@ The `npm` CLI has various mechanisms for showing different levels of information All logs are written to a debug log, with the path to that file printed if the execution of a command fails. -The default location of the logs directory is a directory named `_logs` inside the npm cache. This can be changed -with the `logs-dir` config option. +The default location of the logs directory is a directory named `_logs` inside the npm cache. This can be changed with the `logs-dir` config option. Log files will be removed from the `logs-dir` when the number of log files exceeds `logs-max`, with the oldest logs being deleted first. @@ -62,9 +61,10 @@ The [`--timing` config](/using-npm/config#timing) can be set which does two things: 1. Always shows the full path to the debug log regardless of command exit status -1. Write timing information to a timing file in the cache or `logs-dir` +1. Write timing information to a process specific timing file in the cache or `logs-dir` -This file is a newline delimited list of JSON objects that can be inspected to see timing data for each task in a `npm` CLI run. +This file contains a `timers` object where the keys are an identifier for the +portion of the process being timed and the value is the number of milliseconds it took to complete. ### Registry Response Headers diff --git a/lib/npm.js b/lib/npm.js index b116ec5cc68a4..a178dca727e30 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -18,9 +18,11 @@ const replaceInfo = require('./utils/replace-info.js') const updateNotifier = require('./utils/update-notifier.js') const pkg = require('../package.json') const cmdList = require('./utils/cmd-list.js') +const runId = require('./utils/run-id.js') let warnedNonDashArg = false const _load = Symbol('_load') +const RUN_ID = runId() class Npm extends EventEmitter { static get version () { @@ -38,9 +40,10 @@ class Npm extends EventEmitter { #argvClean = [] #chalk = null - #logFile = new LogFile() + #logFile = new LogFile({ id: RUN_ID }) #display = new Display() #timers = new Timers({ + id: RUN_ID, start: 'npm', listener: (name, ms) => { const args = ['timing', name, `Completed in ${ms}ms`] @@ -207,10 +210,6 @@ class Npm extends EventEmitter { writeTimingFile () { this.#timers.writeFile({ command: this.#argvClean, - // We used to only ever report a single log file - // so to be backwards compatible report the last logfile - // XXX: remove this in npm 9 or just keep it forever - logfile: this.logFiles[this.logFiles.length - 1], logfiles: this.logFiles, version: this.version, }) @@ -298,7 +297,7 @@ class Npm extends EventEmitter { this.time('npm:load:timers', () => this.#timers.load({ - dir: this.config.get('timing') ? this.timingDir : null, + dir: this.config.get('timing') ? this.logsDir : null, }) ) @@ -376,11 +375,6 @@ class Npm extends EventEmitter { return this.#timers.file } - get timingDir () { - // XXX(npm9): make this always in logs-dir - return this.config.get('logs-dir') || this.cache - } - get cache () { return this.config.get('cache') } diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index fc39bddc70a42..ae38efc32b5ae 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -2062,13 +2062,11 @@ define('timing', { default: false, type: Boolean, description: ` - If true, writes a debug log to \`logs-dir\` and timing information - to \`_timing.json\` in the cache, even if the command completes - successfully. \`_timing.json\` is a newline delimited list of JSON - objects. + If true, writes timing information to a process specific json file in + the cache or \`logs-dir\`. The file name ends with \`-timing.json\`. You can quickly view it with this [json](https://npm.im/json) command - line: \`npm exec -- json -g < ~/.npm/_timing.json\`. + line: \`cat ~/.npm/_logs/*-timing.json | npm exec -- json -g\`. `, }) diff --git a/lib/utils/display.js b/lib/utils/display.js index a19f72297e838..b23b2467ff4e6 100644 --- a/lib/utils/display.js +++ b/lib/utils/display.js @@ -3,11 +3,6 @@ const npmlog = require('npmlog') const log = require('./log-shim.js') const { explain } = require('./explain-eresolve.js') -const _logHandler = Symbol('logHandler') -const _eresolveWarn = Symbol('eresolveWarn') -const _log = Symbol('log') -const _npmlog = Symbol('npmlog') - class Display { constructor () { // pause by default until config is loaded @@ -16,11 +11,11 @@ class Display { } on () { - process.on('log', this[_logHandler]) + process.on('log', this.#logHandler) } off () { - process.off('log', this[_logHandler]) + process.off('log', this.#logHandler) // Unbalanced calls to enable/disable progress // will leave change listeners on the tracker // This pretty much only happens in tests but @@ -72,16 +67,16 @@ class Display { } log (...args) { - this[_logHandler](...args) + this.#logHandler(...args) } - [_logHandler] = (level, ...args) => { + #logHandler = (level, ...args) => { try { - this[_log](level, ...args) + this.#log(level, ...args) } catch (ex) { try { // if it crashed once, it might again! - this[_npmlog]('verbose', `attempt to log ${inspect(args)} crashed`, ex) + this.#npmlog('verbose', `attempt to log ${inspect(args)} crashed`, ex) } catch (ex2) { // eslint-disable-next-line no-console console.error(`attempt to log ${inspect(args)} crashed`, ex, ex2) @@ -89,13 +84,13 @@ class Display { } } - [_log] (...args) { - return this[_eresolveWarn](...args) || this[_npmlog](...args) + #log (...args) { + return this.#eresolveWarn(...args) || this.#npmlog(...args) } // Explicitly call these on npmlog and not log shim // This is the final place we should call npmlog before removing it. - [_npmlog] (level, ...args) { + #npmlog (level, ...args) { npmlog[level](...args) } @@ -103,13 +98,13 @@ class Display { // log.warn() method so that when we see a peerDep override // explanation from Arborist, we can replace the object with a // highly abbreviated explanation of what's being overridden. - [_eresolveWarn] (level, heading, message, expl) { + #eresolveWarn (level, heading, message, expl) { if (level === 'warn' && heading === 'ERESOLVE' && expl && typeof expl === 'object' ) { - this[_npmlog](level, heading, message) - this[_npmlog](level, '', explain(expl, log.useColor(), 2)) + this.#npmlog(level, heading, message) + this.#npmlog(level, '', explain(expl, log.useColor(), 2)) // Return true to short circuit other log in chain return true } diff --git a/lib/utils/log-file.js b/lib/utils/log-file.js index d62329c8551e2..a18eb2878f0be 100644 --- a/lib/utils/log-file.js +++ b/lib/utils/log-file.js @@ -7,18 +7,11 @@ const MiniPass = require('minipass') const fsMiniPass = require('fs-minipass') const fs = require('@npmcli/fs') const log = require('./log-shim') +const runId = require('./run-id') const padZero = (n, length) => n.toString().padStart(length.toString().length, '0') const globify = pattern => pattern.split('\\').join('/') -const _logHandler = Symbol('logHandler') -const _formatLogItem = Symbol('formatLogItem') -const _getLogFilePath = Symbol('getLogFilePath') -const _openLogFile = Symbol('openLogFile') -const _cleanLogs = Symbol('cleanlogs') -const _endStream = Symbol('endStream') -const _isBuffered = Symbol('isBuffered') - class LogFiles { // If we write multiple log files we want them all to have the same // identifier for sorting and matching purposes @@ -46,19 +39,16 @@ class LogFiles { #files = [] constructor ({ + id = runId(), maxLogsPerFile = 50_000, maxFilesPerProcess = 5, } = {}) { - this.#logId = LogFiles.logId(new Date()) + this.#logId = id this.#MAX_LOGS_PER_FILE = maxLogsPerFile this.#MAX_FILES_PER_PROCESS = maxFilesPerProcess this.on() } - static logId (d) { - return d.toISOString().replace(/[.:]/g, '_') - } - static format (count, level, title, ...args) { let prefix = `${count} ${level}` if (title) { @@ -75,12 +65,12 @@ class LogFiles { on () { this.#logStream = new MiniPass() - process.on('log', this[_logHandler]) + process.on('log', this.#logHandler) } off () { - process.off('log', this[_logHandler]) - this[_endStream]() + process.off('log', this.#logHandler) + this.#endStream() } load ({ dir, logsMax = Infinity } = {}) { @@ -100,7 +90,7 @@ class LogFiles { // set that as the new log logstream for future writes // if logs max is 0 then the user does not want a log file if (this.#logsMax > 0) { - const initialFile = this[_openLogFile]() + const initialFile = this.#openLogFile() if (initialFile) { this.#logStream = this.#logStream.pipe(initialFile) } @@ -109,29 +99,29 @@ class LogFiles { // Kickoff cleaning process, even if we aren't writing a logfile. // This is async but it will always ignore the current logfile // Return the result so it can be awaited in tests - return this[_cleanLogs]() + return this.#cleanLogs() } log (...args) { - this[_logHandler](...args) + this.#logHandler(...args) } get files () { return this.#files } - get [_isBuffered] () { + get #isBuffered () { return this.#logStream instanceof MiniPass } - [_endStream] (output) { + #endStream (output) { if (this.#logStream) { this.#logStream.end(output) this.#logStream = null } } - [_logHandler] = (level, ...args) => { + #logHandler = (level, ...args) => { // Ignore pause and resume events since we // write everything to the log file if (level === 'pause' || level === 'resume') { @@ -143,9 +133,9 @@ class LogFiles { return } - const logOutput = this[_formatLogItem](level, ...args) + const logOutput = this.#formatLogItem(level, ...args) - if (this[_isBuffered]) { + if (this.#isBuffered) { // Cant do anything but buffer the output if we dont // have a file stream yet this.#logStream.write(logOutput) @@ -155,29 +145,29 @@ class LogFiles { // Open a new log file if we've written too many logs to this one if (this.#fileLogCount >= this.#MAX_LOGS_PER_FILE) { // Write last chunk to the file and close it - this[_endStream](logOutput) + this.#endStream(logOutput) if (this.#files.length >= this.#MAX_FILES_PER_PROCESS) { // but if its way too many then we just stop listening this.off() } else { // otherwise we are ready for a new file for the next event - this.#logStream = this[_openLogFile]() + this.#logStream = this.#openLogFile() } } else { this.#logStream.write(logOutput) } } - [_formatLogItem] (...args) { + #formatLogItem (...args) { this.#fileLogCount += 1 return LogFiles.format(this.#totalLogCount++, ...args) } - [_getLogFilePath] (count = '') { + #getLogFilePath (count = '') { return path.resolve(this.#dir, `${this.#logId}-debug-${count}.log`) } - [_openLogFile] () { + #openLogFile () { // Count in filename will be 0 indexed const count = this.#files.length @@ -186,7 +176,7 @@ class LogFiles { // We never want to write files ending in `-9.log` and `-10.log` because // log file cleaning is done by deleting the oldest so in this example // `-10.log` would be deleted next - const f = this[_getLogFilePath](padZero(count, this.#MAX_FILES_PER_PROCESS)) + const f = this.#getLogFilePath(padZero(count, this.#MAX_FILES_PER_PROCESS)) // Some effort was made to make the async, but we need to write logs // during process.on('exit') which has to be synchronous. So in order // to never drop log messages, it is easiest to make it sync all the time @@ -210,7 +200,7 @@ class LogFiles { } } - async [_cleanLogs] () { + async #cleanLogs () { // module to clean out the old log files // this is a best-effort attempt. if a rm fails, we just // log a message about it and move on. We do return a @@ -218,7 +208,7 @@ class LogFiles { // just for the benefit of testing this function properly. try { - const logPath = this[_getLogFilePath]() + const logPath = this.#getLogFilePath() const logGlob = path.join(path.dirname(logPath), path.basename(logPath) // tell glob to only match digits .replace(/\d/g, '[0123456789]') diff --git a/lib/utils/run-id.js b/lib/utils/run-id.js new file mode 100644 index 0000000000000..b7e7cf797da3c --- /dev/null +++ b/lib/utils/run-id.js @@ -0,0 +1,3 @@ +module.exports = (d = new Date()) => { + return d.toISOString().replace(/[.:]/g, '_') +} diff --git a/lib/utils/timers.js b/lib/utils/timers.js index 3336c3b519259..d4f8d8bdedd6d 100644 --- a/lib/utils/timers.js +++ b/lib/utils/timers.js @@ -2,10 +2,7 @@ const EE = require('events') const { resolve } = require('path') const fs = require('@npmcli/fs') const log = require('./log-shim') - -const _timeListener = Symbol('timeListener') -const _timeEndListener = Symbol('timeEndListener') -const _init = Symbol('init') +const runId = require('./run-id') // This is an event emiiter but on/off // only listen on a single internal event that gets @@ -13,17 +10,19 @@ const _init = Symbol('init') class Timers extends EE { file = null + #id = null #unfinished = new Map() #finished = {} #onTimeEnd = Symbol('onTimeEnd') #initialListener = null #initialTimer = null - constructor ({ listener = null, start = 'npm' } = {}) { + constructor ({ id = runId(), listener = null, start = 'npm' } = {}) { super() + this.#id = id this.#initialListener = listener this.#initialTimer = start - this[_init]() + this.#init() } get unfinished () { @@ -34,7 +33,7 @@ class Timers extends EE { return this.#finished } - [_init] () { + #init () { this.on() if (this.#initialListener) { this.on(this.#initialListener) @@ -47,8 +46,8 @@ class Timers extends EE { if (listener) { super.on(this.#onTimeEnd, listener) } else { - process.on('time', this[_timeListener]) - process.on('timeEnd', this[_timeEndListener]) + process.on('time', this.#timeListener) + process.on('timeEnd', this.#timeEndListener) } } @@ -57,8 +56,8 @@ class Timers extends EE { super.off(this.#onTimeEnd, listener) } else { this.removeAllListeners(this.#onTimeEnd) - process.off('time', this[_timeListener]) - process.off('timeEnd', this[_timeEndListener]) + process.off('time', this.#timeListener) + process.off('timeEnd', this.#timeEndListener) } } @@ -74,11 +73,11 @@ class Timers extends EE { load ({ dir } = {}) { if (dir) { - this.file = resolve(dir, '_timing.json') + this.file = resolve(dir, `${this.#id}-timing.json`) } } - writeFile (fileData) { + writeFile (metadata) { if (!this.file) { return } @@ -87,20 +86,20 @@ class Timers extends EE { const globalStart = this.started const globalEnd = this.#finished.npm || Date.now() const content = { - ...fileData, - ...this.#finished, + metadata: { + id: this.#id, + ...metadata, + }, + timers: this.#finished, // add any unfinished timers with their relative start/end - unfinished: [...this.#unfinished.entries()].reduce((acc, [name, start]) => { + unfinishedTimers: [...this.#unfinished.entries()].reduce((acc, [name, start]) => { acc[name] = [start - globalStart, globalEnd - globalStart] return acc }, {}), } - // we append line delimited json to this file...forever - // XXX: should we also write a process specific timing file? - // with similar rules to the debug log (max files, etc) fs.withOwnerSync( this.file, - () => fs.appendFileSync(this.file, JSON.stringify(content) + '\n'), + () => fs.writeFileSync(this.file, JSON.stringify(content) + '\n'), { owner: 'inherit' } ) } catch (e) { @@ -109,11 +108,11 @@ class Timers extends EE { } } - [_timeListener] = (name) => { + #timeListener = (name) => { this.#unfinished.set(name, Date.now()) } - [_timeEndListener] = (name) => { + #timeEndListener = (name) => { if (this.#unfinished.has(name)) { const ms = Date.now() - this.#unfinished.get(name) this.#finished[name] = ms diff --git a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index ddf2396a6fe00..df9313270d056 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -1762,12 +1762,11 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for timin * Default: false * Type: Boolean -If true, writes a debug log to \`logs-dir\` and timing information to -\`_timing.json\` in the cache, even if the command completes successfully. -\`_timing.json\` is a newline delimited list of JSON objects. +If true, writes timing information to a process specific json file in the +cache or \`logs-dir\`. The file name ends with \`-timing.json\`. You can quickly view it with this [json](https://npm.im/json) command line: -\`npm exec -- json -g < ~/.npm/_timing.json\`. +\`cat ~/.npm/_logs/*-timing.json | npm exec -- json -g\`. ` exports[`test/lib/utils/config/definitions.js TAP > config description for tmp 1`] = ` diff --git a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 2c51efec54afe..89ca7c952b182 100644 --- a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -1580,12 +1580,11 @@ particular, use care when overriding this setting for public packages. * Default: false * Type: Boolean -If true, writes a debug log to \`logs-dir\` and timing information to -\`_timing.json\` in the cache, even if the command completes successfully. -\`_timing.json\` is a newline delimited list of JSON objects. +If true, writes timing information to a process specific json file in the +cache or \`logs-dir\`. The file name ends with \`-timing.json\`. You can quickly view it with this [json](https://npm.im/json) command line: -\`npm exec -- json -g < ~/.npm/_timing.json\`. +\`cat ~/.npm/_logs/*-timing.json | npm exec -- json -g\`. diff --git a/test/fixtures/mock-npm.js b/test/fixtures/mock-npm.js index 330c341474da3..72cfa4b0c4beb 100644 --- a/test/fixtures/mock-npm.js +++ b/test/fixtures/mock-npm.js @@ -174,8 +174,8 @@ const LoadMockNpm = async (t, { .join('\n') }, timingFile: async () => { - const data = await fs.readFile(path.resolve(dirs.cache, '_timing.json'), 'utf8') - return JSON.parse(data) // XXX: this fails if multiple timings are written + const data = await fs.readFile(npm.timingFile, 'utf8') + return JSON.parse(data) }, } } diff --git a/test/lib/npm.js b/test/lib/npm.js index 135a02cc98a3d..2bf7f426db409 100644 --- a/test/lib/npm.js +++ b/test/lib/npm.js @@ -513,19 +513,23 @@ t.test('timings', async t => { process.emit('timeEnd', 'foo') process.emit('time', 'bar') npm.writeTimingFile() - t.equal(npm.timingFile, join(cache, '_timing.json')) + t.match(npm.timingFile, cache) + t.match(npm.timingFile, /-timing.json$/) const timings = await timingFile() t.match(timings, { - command: [], - logfile: String, - logfiles: [String], - version: String, - unfinished: { + metadata: { + command: [], + logfiles: [String], + version: String, + }, + unfinishedTimers: { bar: [Number, Number], npm: [Number, Number], }, - foo: Number, - 'npm:load': Number, + timers: { + foo: Number, + 'npm:load': Number, + }, }) }) diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js index 23942cca1c078..de4ce61aaa6af 100644 --- a/test/lib/utils/exit-handler.js +++ b/test/lib/utils/exit-handler.js @@ -326,7 +326,7 @@ t.test('timing with no error', async (t) => { t.match(msg, /Timing info written to:/) t.match( - timingFileData, + timingFileData.timers, Object.keys(npm.finishedTimers).reduce((acc, k) => { acc[k] = Number return acc @@ -334,11 +334,14 @@ t.test('timing with no error', async (t) => { ) t.strictSame(npm.unfinishedTimers, new Map()) t.match(timingFileData, { - command: [], - version: '1.0.0', - npm: Number, - logfile: String, - logfiles: [String], + metadata: { + command: [], + version: '1.0.0', + logfiles: [String], + }, + timers: { + npm: Number, + }, }) }) @@ -356,12 +359,15 @@ t.test('unfinished timers', async (t) => { t.equal(process.exitCode, 0) t.match(npm.unfinishedTimers, new Map([['foo', Number], ['bar', Number]])) t.match(timingFileData, { - command: [], - version: '1.0.0', - npm: Number, - logfile: String, - logfiles: [String], - unfinished: { + metadata: { + command: [], + version: '1.0.0', + logfiles: [String], + }, + timers: { + npm: Number, + }, + unfinishedTimers: { foo: [Number, Number], bar: [Number, Number], }, diff --git a/test/lib/utils/log-file.js b/test/lib/utils/log-file.js index ce6f0bf4cf51f..3c7bb3fe8324a 100644 --- a/test/lib/utils/log-file.js +++ b/test/lib/utils/log-file.js @@ -6,6 +6,7 @@ const os = require('os') const fsMiniPass = require('fs-minipass') const rimraf = require('rimraf') const LogFile = require('../../../lib/utils/log-file.js') +const runId = require('../../../lib/utils/run-id.js') const { cleanCwd } = require('../../fixtures/clean-snapshot') t.cleanSnapshot = (path) => cleanCwd(path) @@ -19,7 +20,7 @@ const makeOldLogs = (count, oldStyle) => { return range(oldStyle ? count : (count / 2)).reduce((acc, i) => { const cloneDate = new Date(d.getTime()) cloneDate.setSeconds(i) - const dateId = LogFile.logId(cloneDate) + const dateId = runId(cloneDate) if (oldStyle) { acc[`${dateId}-debug.log`] = 'hello' } else { diff --git a/test/lib/utils/timers.js b/test/lib/utils/timers.js index 30e54700c63a9..259ecd5dd4893 100644 --- a/test/lib/utils/timers.js +++ b/test/lib/utils/timers.js @@ -68,17 +68,17 @@ t.test('finish unstarted timer', async (t) => { }) t.test('writes file', async (t) => { - const { timers } = mockTimers(t) + const { timers } = mockTimers(t, { id: 'TIMING_FILE' }) const dir = t.testdir() process.emit('time', 'foo') process.emit('timeEnd', 'foo') timers.load({ dir }) timers.writeFile({ some: 'data' }) - const data = JSON.parse(fs.readFileSync(resolve(dir, '_timing.json'))) + const data = JSON.parse(fs.readFileSync(resolve(dir, 'TIMING_FILE-timing.json'))) t.match(data, { - some: 'data', - foo: Number, - unfinished: { + metadata: { some: 'data' }, + timers: { foo: Number }, + unfinishedTimers: { npm: [Number, Number], }, }) From e64d69aedecc0943425605b3a6dc68aec3ad93aa Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Sun, 25 Sep 2022 01:31:56 -0700 Subject: [PATCH 33/40] feat: write eresolve error files to the logs directory Also refactor all files written to the logs directory to use the same code path for file name creation. --- lib/npm.js | 15 +- lib/utils/error-message.js | 10 +- lib/utils/exit-handler.js | 35 +++-- lib/utils/explain-eresolve.js | 35 +++-- lib/utils/log-file.js | 17 +-- lib/utils/run-id.js | 3 - lib/utils/timers.js | 17 +-- .../test/lib/utils/error-message.js.test.cjs | 22 +-- .../test/lib/utils/exit-handler.js.test.cjs | 4 +- .../lib/utils/explain-eresolve.js.test.cjs | 136 +++--------------- .../test/lib/utils/log-file.js.test.cjs | 2 +- test/lib/utils/error-message.js | 19 +-- test/lib/utils/exit-handler.js | 53 ++++++- test/lib/utils/explain-eresolve.js | 37 ++--- test/lib/utils/log-file.js | 15 +- test/lib/utils/timers.js | 6 +- 16 files changed, 192 insertions(+), 234 deletions(-) delete mode 100644 lib/utils/run-id.js diff --git a/lib/npm.js b/lib/npm.js index a178dca727e30..852d91ad3f890 100644 --- a/lib/npm.js +++ b/lib/npm.js @@ -18,11 +18,9 @@ const replaceInfo = require('./utils/replace-info.js') const updateNotifier = require('./utils/update-notifier.js') const pkg = require('../package.json') const cmdList = require('./utils/cmd-list.js') -const runId = require('./utils/run-id.js') let warnedNonDashArg = false const _load = Symbol('_load') -const RUN_ID = runId() class Npm extends EventEmitter { static get version () { @@ -34,16 +32,16 @@ class Npm extends EventEmitter { loadErr = null argv = [] + #runId = new Date().toISOString().replace(/[.:]/g, '_') #loadPromise = null #tmpFolder = null #title = 'npm' #argvClean = [] #chalk = null - #logFile = new LogFile({ id: RUN_ID }) + #logFile = new LogFile() #display = new Display() #timers = new Timers({ - id: RUN_ID, start: 'npm', listener: (name, ms) => { const args = ['timing', name, `Completed in ${ms}ms`] @@ -209,6 +207,7 @@ class Npm extends EventEmitter { writeTimingFile () { this.#timers.writeFile({ + id: this.#runId, command: this.#argvClean, logfiles: this.logFiles, version: this.version, @@ -289,7 +288,7 @@ class Npm extends EventEmitter { this.time('npm:load:logFile', () => { this.#logFile.load({ - dir: this.logsDir, + path: this.logPath, logsMax: this.config.get('logs-max'), }) log.verbose('logfile', this.#logFile.files[0] || 'no logfile created') @@ -297,7 +296,7 @@ class Npm extends EventEmitter { this.time('npm:load:timers', () => this.#timers.load({ - dir: this.config.get('timing') ? this.logsDir : null, + path: this.config.get('timing') ? this.logPath : null, }) ) @@ -371,6 +370,10 @@ class Npm extends EventEmitter { return this.config.get('logs-dir') || join(this.cache, '_logs') } + get logPath () { + return resolve(this.logsDir, `${this.#runId}-`) + } + get timingFile () { return this.#timers.file } diff --git a/lib/utils/error-message.js b/lib/utils/error-message.js index adf10a56f6d66..aee376120ba27 100644 --- a/lib/utils/error-message.js +++ b/lib/utils/error-message.js @@ -8,6 +8,7 @@ const log = require('./log-shim') module.exports = (er, npm) => { const short = [] const detail = [] + const files = [] if (er.message) { er.message = replaceInfo(er.message) @@ -17,14 +18,17 @@ module.exports = (er, npm) => { } switch (er.code) { - case 'ERESOLVE': + case 'ERESOLVE': { short.push(['ERESOLVE', er.message]) detail.push(['', '']) // XXX(display): error messages are logged so we use the logColor since that is based // on stderr. This should be handled solely by the display layer so it could also be // printed to stdout if necessary. - detail.push(['', report(er, !!npm.logColor, resolve(npm.cache, 'eresolve-report.txt'))]) + const { explanation, file } = report(er, !!npm.logColor) + detail.push(['', explanation]) + files.push(['eresolve-report.txt', file]) break + } case 'ENOLOCK': { const cmd = npm.command || '' @@ -398,5 +402,5 @@ module.exports = (er, npm) => { break } - return { summary: short, detail: detail } + return { summary: short, detail, files } } diff --git a/lib/utils/exit-handler.js b/lib/utils/exit-handler.js index d8ae9994dfecc..f1843347bc324 100644 --- a/lib/utils/exit-handler.js +++ b/lib/utils/exit-handler.js @@ -1,4 +1,5 @@ const os = require('os') +const fs = require('@npmcli/fs') const log = require('./log-shim.js') const errorMessage = require('./error-message.js') @@ -18,11 +19,10 @@ process.on('exit', code => { // unfinished timer check below process.emit('timeEnd', 'npm') - const hasNpm = !!npm - const hasLoadedNpm = hasNpm && npm.config.loaded + const hasLoadedNpm = npm?.config.loaded // Unfinished timers can be read before config load - if (hasNpm) { + if (npm) { for (const [name, timer] of npm.unfinishedTimers) { log.verbose('unfinished npm timer', name, timer) } @@ -111,10 +111,9 @@ const exitHandler = err => { log.disableProgress() - const hasNpm = !!npm - const hasLoadedNpm = hasNpm && npm.config.loaded + const hasLoadedNpm = npm?.config.loaded - if (!hasNpm) { + if (!npm) { err = err || new Error('Exit prior to setting npm in exit handler') // eslint-disable-next-line no-console console.error(err.stack || err.message) @@ -181,8 +180,24 @@ const exitHandler = err => { } } - const msg = errorMessage(err, npm) - for (const errline of [...msg.summary, ...msg.detail]) { + const { summary, detail, files = [] } = errorMessage(err, npm) + + for (let [file, content] of files) { + file = `${npm.logPath}${file}` + content = `'Log files:\n${npm.logFiles.join('\n')}\n\n${content.trim()}\n` + try { + fs.withOwnerSync( + file, + () => fs.writeFileSync(file, content), + { owner: 'inherit' } + ) + detail.push(['', `\n\nFor a full report see:\n${file}`]) + } catch (err) { + log.warn('', `Could not write error message to ${file} due to ${err}`) + } + } + + for (const errline of [...summary, ...detail]) { log.error(...errline) } @@ -190,8 +205,8 @@ const exitHandler = err => { const error = { error: { code: err.code, - summary: messageText(msg.summary), - detail: messageText(msg.detail), + summary: messageText(summary), + detail: messageText(detail), }, } npm.outputError(JSON.stringify(error, null, 2)) diff --git a/lib/utils/explain-eresolve.js b/lib/utils/explain-eresolve.js index 7f6a10869c73c..480cd8e5cd4e6 100644 --- a/lib/utils/explain-eresolve.js +++ b/lib/utils/explain-eresolve.js @@ -1,7 +1,6 @@ // this is called when an ERESOLVE error is caught in the exit-handler, // or when there's a log.warn('eresolve', msg, explanation), to turn it // into a human-intelligible explanation of what's wrong and how to fix. -const { writeFileSync } = require('fs') const { explainEdge, explainNode, printNode } = require('./explain-dep.js') // expl is an explanation object that comes from Arborist. It looks like: @@ -45,27 +44,25 @@ const explain = (expl, color, depth) => { } // generate a full verbose report and tell the user how to fix it -const report = (expl, color, fullReport) => { - const orNoStrict = expl.strictPeerDeps ? '--no-strict-peer-deps, ' : '' - const fix = `Fix the upstream dependency conflict, or retry -this command with ${orNoStrict}--force, or --legacy-peer-deps -to accept an incorrect (and potentially broken) dependency resolution.` - - writeFileSync(fullReport, `# npm resolution error report - -${new Date().toISOString()} - -${explain(expl, false, Infinity)} +const report = (expl, color) => { + const flags = [ + expl.strictPeerDeps ? '--no-strict-peer-deps' : '', + '--force', + '--legacy-peer-deps', + ].filter(Boolean) -${fix} + const or = (arr) => arr.length <= 2 + ? arr.join(' or ') : + arr.map((v, i, l) => i + 1 === l.length ? `or ${v}` : v).join(', ') -Raw JSON explanation object: - -${JSON.stringify(expl, null, 2)} -`, 'utf8') + const fix = `Fix the upstream dependency conflict, or retry +this command with ${or(flags)} +to accept an incorrect (and potentially broken) dependency resolution.` - return explain(expl, color, 4) + - `\n\n${fix}\n\nSee ${fullReport} for a full report.` + return { + explanation: `${explain(expl, color, 4)}\n\n${fix}`, + file: `# npm resolution error report\n\n${explain(expl, false, Infinity)}\n\n${fix}`, + } } module.exports = { diff --git a/lib/utils/log-file.js b/lib/utils/log-file.js index a18eb2878f0be..3351ae6cdd3d5 100644 --- a/lib/utils/log-file.js +++ b/lib/utils/log-file.js @@ -7,16 +7,11 @@ const MiniPass = require('minipass') const fsMiniPass = require('fs-minipass') const fs = require('@npmcli/fs') const log = require('./log-shim') -const runId = require('./run-id') const padZero = (n, length) => n.toString().padStart(length.toString().length, '0') const globify = pattern => pattern.split('\\').join('/') class LogFiles { - // If we write multiple log files we want them all to have the same - // identifier for sorting and matching purposes - #logId = null - // Default to a plain minipass stream so we can buffer // initial writes before we know the cache location #logStream = null @@ -34,16 +29,14 @@ class LogFiles { #fileLogCount = 0 #totalLogCount = 0 - #dir = null + #path = null #logsMax = null #files = [] constructor ({ - id = runId(), maxLogsPerFile = 50_000, maxFilesPerProcess = 5, } = {}) { - this.#logId = id this.#MAX_LOGS_PER_FILE = maxLogsPerFile this.#MAX_FILES_PER_PROCESS = maxFilesPerProcess this.on() @@ -73,10 +66,10 @@ class LogFiles { this.#endStream() } - load ({ dir, logsMax = Infinity } = {}) { + load ({ path, logsMax = Infinity } = {}) { // dir is user configurable and is required to exist so // this can error if the dir is missing or not configured correctly - this.#dir = dir + this.#path = path this.#logsMax = logsMax // Log stream has already ended @@ -84,7 +77,7 @@ class LogFiles { return } - log.verbose('logfile', `logs-max:${logsMax} dir:${dir}`) + log.verbose('logfile', `logs-max:${logsMax} dir:${this.#path}`) // Pipe our initial stream to our new file stream and // set that as the new log logstream for future writes @@ -164,7 +157,7 @@ class LogFiles { } #getLogFilePath (count = '') { - return path.resolve(this.#dir, `${this.#logId}-debug-${count}.log`) + return `${this.#path}debug-${count}.log` } #openLogFile () { diff --git a/lib/utils/run-id.js b/lib/utils/run-id.js deleted file mode 100644 index b7e7cf797da3c..0000000000000 --- a/lib/utils/run-id.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = (d = new Date()) => { - return d.toISOString().replace(/[.:]/g, '_') -} diff --git a/lib/utils/timers.js b/lib/utils/timers.js index d4f8d8bdedd6d..c84bbba3819ab 100644 --- a/lib/utils/timers.js +++ b/lib/utils/timers.js @@ -1,8 +1,6 @@ const EE = require('events') -const { resolve } = require('path') const fs = require('@npmcli/fs') const log = require('./log-shim') -const runId = require('./run-id') // This is an event emiiter but on/off // only listen on a single internal event that gets @@ -10,16 +8,14 @@ const runId = require('./run-id') class Timers extends EE { file = null - #id = null #unfinished = new Map() #finished = {} #onTimeEnd = Symbol('onTimeEnd') #initialListener = null #initialTimer = null - constructor ({ id = runId(), listener = null, start = 'npm' } = {}) { + constructor ({ listener = null, start = 'npm' } = {}) { super() - this.#id = id this.#initialListener = listener this.#initialTimer = start this.#init() @@ -71,9 +67,9 @@ class Timers extends EE { return end } - load ({ dir } = {}) { - if (dir) { - this.file = resolve(dir, `${this.#id}-timing.json`) + load ({ path } = {}) { + if (path) { + this.file = `${path}timing.json` } } @@ -86,10 +82,7 @@ class Timers extends EE { const globalStart = this.started const globalEnd = this.#finished.npm || Date.now() const content = { - metadata: { - id: this.#id, - ...metadata, - }, + metadata, timers: this.#finished, // add any unfinished timers with their relative start/end unfinishedTimers: [...this.#unfinished.entries()].reduce((acc, [name, start]) => { diff --git a/tap-snapshots/test/lib/utils/error-message.js.test.cjs b/tap-snapshots/test/lib/utils/error-message.js.test.cjs index 8e772e8691860..de21a46d2f6e8 100644 --- a/tap-snapshots/test/lib/utils/error-message.js.test.cjs +++ b/tap-snapshots/test/lib/utils/error-message.js.test.cjs @@ -509,7 +509,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-false-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -549,7 +549,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -592,7 +592,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -635,7 +635,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-false-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -825,7 +825,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-false-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-false-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -876,7 +876,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-false-cacheDest-true-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -927,7 +927,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-false-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -978,7 +978,7 @@ Array [ ], Array [ "logfile", - "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/_logs", + "logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-error-message-eacces-eperm--windows-true-loaded-true-cachePath-true-cacheDest-true-/cache/_logs/{DATE}-", ], Array [ "logfile", @@ -1176,6 +1176,12 @@ Object { "explanation", ], ], + "files": Array [ + Array [ + "eresolve-report.txt", + "report", + ], + ], "summary": Array [ Array [ "ERESOLVE", diff --git a/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs b/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs index edb7edaa5d5f5..4d52c02d97dd3 100644 --- a/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs +++ b/tap-snapshots/test/lib/utils/exit-handler.js.test.cjs @@ -15,7 +15,7 @@ exports[`test/lib/utils/exit-handler.js TAP handles unknown error with logs and 20 verbose argv 21 timing npm:load:setTitle Completed in {TIME}ms 23 timing npm:load:display Completed in {TIME}ms -24 verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs +24 verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}- 25 verbose logfile {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log 26 timing npm:load:logFile Completed in {TIME}ms 27 timing npm:load:timers Completed in {TIME}ms @@ -47,7 +47,7 @@ verbose title npm verbose argv timing npm:load:setTitle Completed in {TIME}ms timing npm:load:display Completed in {TIME}ms -verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs +verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}- verbose logfile {CWD}/test/lib/utils/tap-testdir-exit-handler-handles-unknown-error-with-logs-and-debug-file/cache/_logs/{DATE}-debug-0.log timing npm:load:logFile Completed in {TIME}ms timing npm:load:timers Completed in {TIME}ms diff --git a/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs b/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs index 354081d110319..99ad5c0f31e90 100644 --- a/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs +++ b/tap-snapshots/test/lib/utils/explain-eresolve.js.test.cjs @@ -29,11 +29,9 @@ node_modules/@isaacs/testing-peer-dep-conflict-chain-c @isaacs/testing-peer-dep-conflict-chain-c@"1" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report from color 1`] = ` # npm resolution error report -\${TIME} - While resolving: project@1.2.3 Found: @isaacs/testing-peer-dep-conflict-chain-d@2.0.0 node_modules/@isaacs/testing-peer-dep-conflict-chain-d @@ -45,16 +43,8 @@ node_modules/@isaacs/testing-peer-dep-conflict-chain-c @isaacs/testing-peer-dep-conflict-chain-c@"1" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "chain-conflict", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report with color 1`] = ` @@ -69,10 +59,8 @@ Could not resolve dependency: @isaacs/testing-peer-dep-conflict-chain-c@"1" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP chain-conflict > report with no color 1`] = ` @@ -87,10 +75,8 @@ node_modules/@isaacs/testing-peer-dep-conflict-chain-c @isaacs/testing-peer-dep-conflict-chain-c@"1" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > explain with color, depth of 2 1`] = ` @@ -130,11 +116,9 @@ node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-a@"1.x" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report from color 1`] = ` # npm resolution error report -\${TIME} - Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @isaacs/peer-dep-cycle-c@"2.x" from the root project @@ -155,14 +139,6 @@ node_modules/@isaacs/peer-dep-cycle-c Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "cycleNested", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report with color 1`] = ` @@ -186,8 +162,6 @@ Conflicting peer dependency: @isaacs/peer-dep-cycle-c@1.0.0[2 Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP cycleNested > report with no color 1`] = ` @@ -211,8 +185,6 @@ node_modules/@isaacs/peer-dep-cycle-c Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > explain with color, depth of 2 1`] = ` @@ -255,11 +227,9 @@ node_modules/eslint dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report from color 1`] = ` # npm resolution error report -\${TIME} - While resolving: eslint-plugin-react@7.24.0 Found: eslint@6.8.0 node_modules/eslint @@ -287,16 +257,8 @@ node_modules/eslint dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "eslint-plugin case", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with color 1`] = ` @@ -319,10 +281,8 @@ Conflicting peer dependency: eslint@7.31.0 dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP eslint-plugin case > report with no color 1`] = ` @@ -345,10 +305,8 @@ node_modules/eslint dev eslint-plugin-eslint-plugin@"^3.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP gatsby > explain with color, depth of 2 1`] = ` @@ -391,11 +349,9 @@ node_modules/ink-box gatsby@"" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report from color 1`] = ` # npm resolution error report -\${TIME} - While resolving: gatsby-recipes@0.2.31 Found: ink@3.0.0-7 node_modules/ink @@ -421,14 +377,6 @@ node_modules/ink-box Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "gatsby", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report with color 1`] = ` @@ -456,8 +404,6 @@ Could not resolve dependency: Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP gatsby > report with no color 1`] = ` @@ -485,8 +431,6 @@ node_modules/ink-box Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > explain with color, depth of 2 1`] = ` @@ -509,11 +453,9 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report from color 1`] = ` # npm resolution error report -\${TIME} - While resolving: eslint@7.22.0 Found: dev eslint@"file:." from the root project @@ -523,16 +465,8 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "no current node, but has current edge", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report with color 1`] = ` @@ -545,10 +479,8 @@ Could not resolve dependency: dev eslint-plugin-jsdoc@"^22.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP no current node, but has current edge > report with no color 1`] = ` @@ -561,10 +493,8 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > explain with color, depth of 2 1`] = ` @@ -591,11 +521,9 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report from color 1`] = ` # npm resolution error report -\${TIME} - While resolving: eslint@7.22.0 Found: peer eslint@"^6.0.0" from eslint-plugin-jsdoc@22.2.0 node_modules/eslint-plugin-jsdoc @@ -607,16 +535,8 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "no current node, no current edge, idk", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with color 1`] = ` @@ -631,10 +551,8 @@ Could not resolve dependency: dev eslint-plugin-jsdoc@"^22.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP no current node, no current edge, idk > report with no color 1`] = ` @@ -649,10 +567,8 @@ node_modules/eslint-plugin-jsdoc dev eslint-plugin-jsdoc@"^22.1.0" from the root project Fix the upstream dependency conflict, or retry -this command with --force, or --legacy-peer-deps +this command with --force or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > explain with color, depth of 2 1`] = ` @@ -682,11 +598,9 @@ node_modules/@isaacs/peer-dep-cycle-b @isaacs/peer-dep-cycle-a@"1.x" from the root project ` -exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report 1`] = ` +exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report from color 1`] = ` # npm resolution error report -\${TIME} - While resolving: @isaacs/peer-dep-cycle-b@1.0.0 Found: @isaacs/peer-dep-cycle-c@2.0.0 node_modules/@isaacs/peer-dep-cycle-c @@ -702,14 +616,6 @@ node_modules/@isaacs/peer-dep-cycle-b Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -Raw JSON explanation object: - -{ - "name": "withShrinkwrap", - "json": true -} - ` exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report with color 1`] = ` @@ -728,8 +634,6 @@ Could not resolve dependency: Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` exports[`test/lib/utils/explain-eresolve.js TAP withShrinkwrap > report with no color 1`] = ` @@ -748,6 +652,4 @@ node_modules/@isaacs/peer-dep-cycle-b Fix the upstream dependency conflict, or retry this command with --no-strict-peer-deps, --force, or --legacy-peer-deps to accept an incorrect (and potentially broken) dependency resolution. - -See \${REPORT} for a full report. ` diff --git a/tap-snapshots/test/lib/utils/log-file.js.test.cjs b/tap-snapshots/test/lib/utils/log-file.js.test.cjs index 7a39184939026..912a4365f6810 100644 --- a/tap-snapshots/test/lib/utils/log-file.js.test.cjs +++ b/tap-snapshots/test/lib/utils/log-file.js.test.cjs @@ -6,7 +6,7 @@ */ 'use strict' exports[`test/lib/utils/log-file.js TAP snapshot > must match snapshot 1`] = ` -0 verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-log-file-snapshot +0 verbose logfile logs-max:10 dir:{CWD}/test/lib/utils/tap-testdir-log-file-snapshot/{DATE}- 1 silly logfile done cleaning log files 2 error no prefix 3 error prefix with prefix diff --git a/test/lib/utils/error-message.js b/test/lib/utils/error-message.js index 3fec501ef9ff7..29753c3039f36 100644 --- a/test/lib/utils/error-message.js +++ b/test/lib/utils/error-message.js @@ -4,6 +4,12 @@ const { load: _loadMockNpm } = require('../../fixtures/mock-npm.js') const mockGlobals = require('../../fixtures/mock-globals.js') const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot.js') +t.formatSnapshot = (p) => { + if (Array.isArray(p.files) && !p.files.length) { + delete p.files + } + return p +} t.cleanSnapshot = p => cleanDate(cleanCwd(p)) mockGlobals(t, { @@ -420,7 +426,7 @@ t.test('bad platform', async t => { }) t.test('explain ERESOLVE errors', async t => { - const npm = await loadMockNpm(t) + const { npm, ...rest } = await loadMockNpm(t) const EXPLAIN_CALLED = [] const er = Object.assign(new Error('could not resolve'), { @@ -428,19 +434,16 @@ t.test('explain ERESOLVE errors', async t => { }) t.matchSnapshot(errorMessage(er, { - ...npm, + npm, + ...rest, mocks: { '../../../lib/utils/explain-eresolve.js': { report: (...args) => { EXPLAIN_CALLED.push(args) - return 'explanation' + return { explanation: 'explanation', file: 'report' } }, }, }, })) - t.match(EXPLAIN_CALLED, [[ - er, - false, - path.resolve(npm.cache, 'eresolve-report.txt'), - ]]) + t.match(EXPLAIN_CALLED, [[er, false]]) }) diff --git a/test/lib/utils/exit-handler.js b/test/lib/utils/exit-handler.js index de4ce61aaa6af..7d2e7e061c365 100644 --- a/test/lib/utils/exit-handler.js +++ b/test/lib/utils/exit-handler.js @@ -1,5 +1,7 @@ const t = require('tap') const os = require('os') +const fs = require('@npmcli/fs') +const { join } = require('path') const EventEmitter = require('events') const { format } = require('../../../lib/utils/log-file') const { load: loadMockNpm } = require('../../fixtures/mock-npm') @@ -45,7 +47,7 @@ mockGlobals(t, { }), }, { replace: true }) -const mockExitHandler = async (t, { init, load, testdir, config, globals, mocks } = {}) => { +const mockExitHandler = async (t, { init, load, testdir, config, mocks, files } = {}) => { const errors = [] const { npm, logMocks, ...rest } = await loadMockNpm(t, { @@ -69,9 +71,9 @@ const mockExitHandler = async (t, { init, load, testdir, config, globals, mocks const exitHandler = t.mock('../../../lib/utils/exit-handler.js', { '../../../lib/utils/error-message.js': (err) => ({ - ...err, summary: [['ERR SUMMARY', err.message]], detail: [['ERR DETAIL', err.message]], + ...(files ? { files } : {}), }), os: { type: () => 'Foo', @@ -311,6 +313,53 @@ t.test('log file error', async (t) => { t.match(logs.error.filter(([t]) => t === ''), [['', `error writing to the directory`]]) }) +t.test('files from error message', async (t) => { + const { exitHandler, logs, cache } = await mockExitHandler(t, { + files: [ + ['error-file.txt', '# error file content'], + ], + }) + + await exitHandler(err('Error message')) + + const logFiles = fs.readdirSync(join(cache, '_logs')) + const errorFileName = logFiles.find(f => f.endsWith('error-file.txt')) + const errorFile = fs.readFileSync(join(cache, '_logs', errorFileName)).toString() + + const [log] = logs.error.filter(([t]) => t === '') + + t.match(log[1], /For a full report see:\n.*-error-file\.txt/) + t.match(errorFile, '# error file content') + t.match(errorFile, 'Log files:') +}) + +t.test('files from error message with error', async (t) => { + const { exitHandler, logs } = await mockExitHandler(t, { + config: { + 'logs-dir': 'LOGS_DIR', + }, + files: [ + ['error-file.txt', '# error file content'], + ], + mocks: { + '@npmcli/fs': { + ...fs, + writeFileSync: (dir) => { + if (dir.includes('LOGS_DIR') && dir.endsWith('error-file.txt')) { + throw new Error('err') + } + }, + }, + }, + }) + + await exitHandler(err('Error message')) + + const [log] = logs.warn.filter(([t]) => t === '') + + t.match(log[1], /Could not write error message to.*error-file\.txt.*err/) +}) + t.test('timing with no error', async (t) => { const { exitHandler, timingFile, npm, logs } = await mockExitHandler(t, { config: { timing: true }, diff --git a/test/lib/utils/explain-eresolve.js b/test/lib/utils/explain-eresolve.js index f9710ee889ab1..2c1fed77899e9 100644 --- a/test/lib/utils/explain-eresolve.js +++ b/test/lib/utils/explain-eresolve.js @@ -1,41 +1,32 @@ const t = require('tap') -const npm = {} -const { explain, report } = require('../../../lib/utils/explain-eresolve.js') -const { statSync, readFileSync, unlinkSync } = require('fs') -// strip out timestamps from reports -const read = f => readFileSync(f, 'utf8') - .replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/g, '${TIME}') - const { resolve } = require('path') +const { explain, report } = require('../../../lib/utils/explain-eresolve.js') const cases = require('../../fixtures/eresolve-explanations.js') +const { cleanDate } = require('../../fixtures/clean-snapshot.js') for (const [name, expl] of Object.entries(cases)) { // no sense storing the whole contents of each object in the snapshot // we can trust that JSON.stringify still works just fine. - expl.toJSON = () => { - return { name, json: true } - } + expl.toJSON = () => ({ name, json: true }) t.test(name, t => { - npm.cache = t.testdir() - const reportFile = resolve(npm.cache, 'eresolve-report.txt') - t.cleanSnapshot = str => str.split(reportFile).join('${REPORT}') + const dir = t.testdir() + const fileReport = resolve(dir, 'eresolve-report.txt') + const opts = { file: fileReport, date: new Date().toISOString() } + + t.cleanSnapshot = str => cleanDate(str.split(fileReport).join('${REPORT}')) - npm.color = true - t.matchSnapshot(report(expl, true, reportFile), 'report with color') - const reportData = read(reportFile) - t.matchSnapshot(reportData, 'report') - unlinkSync(reportFile) + const color = report(expl, true, opts) + t.matchSnapshot(color.explanation, 'report with color') + t.matchSnapshot(color.file, 'report from color') - t.matchSnapshot(report(expl, false, reportFile), 'report with no color') - t.equal(read(reportFile), reportData, 'same report written for object') - unlinkSync(reportFile) + const noColor = report(expl, false, opts) + t.matchSnapshot(noColor.explanation, 'report with no color') + t.equal(noColor.file, color.file, 'same report written for object') t.matchSnapshot(explain(expl, true, 2), 'explain with color, depth of 2') - t.throws(() => statSync(reportFile), { code: 'ENOENT' }, 'no report') t.matchSnapshot(explain(expl, false, 6), 'explain with no color, depth of 6') - t.throws(() => statSync(reportFile), { code: 'ENOENT' }, 'no report') t.end() }) diff --git a/test/lib/utils/log-file.js b/test/lib/utils/log-file.js index 3c7bb3fe8324a..4be5231c1c4fa 100644 --- a/test/lib/utils/log-file.js +++ b/test/lib/utils/log-file.js @@ -6,11 +6,11 @@ const os = require('os') const fsMiniPass = require('fs-minipass') const rimraf = require('rimraf') const LogFile = require('../../../lib/utils/log-file.js') -const runId = require('../../../lib/utils/run-id.js') -const { cleanCwd } = require('../../fixtures/clean-snapshot') +const { cleanCwd, cleanDate } = require('../../fixtures/clean-snapshot') -t.cleanSnapshot = (path) => cleanCwd(path) +t.cleanSnapshot = (path) => cleanDate(cleanCwd(path)) +const getId = (d = new Date()) => d.toISOString().replace(/[.:]/g, '_') const last = arr => arr[arr.length - 1] const range = (n) => Array.from(Array(n).keys()) const makeOldLogs = (count, oldStyle) => { @@ -20,7 +20,7 @@ const makeOldLogs = (count, oldStyle) => { return range(oldStyle ? count : (count / 2)).reduce((acc, i) => { const cloneDate = new Date(d.getTime()) cloneDate.setSeconds(i) - const dateId = runId(cloneDate) + const dateId = getId(cloneDate) if (oldStyle) { acc[`${dateId}-debug.log`] = 'hello' } else { @@ -42,10 +42,15 @@ const cleanErr = (message) => { const loadLogFile = async (t, { buffer = [], mocks, testdir = {}, ...options } = {}) => { const root = t.testdir(testdir) + const MockLogFile = t.mock('../../../lib/utils/log-file.js', mocks) const logFile = new MockLogFile(Object.keys(options).length ? options : undefined) + buffer.forEach((b) => logFile.log(...b)) - await logFile.load({ dir: root, ...options }) + + const id = getId() + await logFile.load({ path: path.join(root, `${id}-`), ...options }) + t.teardown(() => logFile.off()) return { root, diff --git a/test/lib/utils/timers.js b/test/lib/utils/timers.js index 259ecd5dd4893..23d8eb6e2cafe 100644 --- a/test/lib/utils/timers.js +++ b/test/lib/utils/timers.js @@ -68,11 +68,11 @@ t.test('finish unstarted timer', async (t) => { }) t.test('writes file', async (t) => { - const { timers } = mockTimers(t, { id: 'TIMING_FILE' }) + const { timers } = mockTimers(t) const dir = t.testdir() process.emit('time', 'foo') process.emit('timeEnd', 'foo') - timers.load({ dir }) + timers.load({ path: resolve(dir, `TIMING_FILE-`) }) timers.writeFile({ some: 'data' }) const data = JSON.parse(fs.readFileSync(resolve(dir, 'TIMING_FILE-timing.json'))) t.match(data, { @@ -88,7 +88,7 @@ t.test('fails to write file', async (t) => { const { logs, timers } = mockTimers(t) const dir = t.testdir() - timers.load({ dir: join(dir, 'does', 'not', 'exist') }) + timers.load({ path: join(dir, 'does', 'not', 'exist') }) timers.writeFile() t.match(logs.warn, [['timing', 'could not write timing file']]) From 7e6b8244b0eef9ee60e293859f4147e577cb2f3b Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Thu, 22 Sep 2022 23:01:59 -0700 Subject: [PATCH 34/40] chore(make): docs should come before test during publish docs needs to rebuild cmark-gfm which needs to be present in order to run tests --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 484c5152f0292..5f66ee7174f16 100644 --- a/Makefile +++ b/Makefile @@ -113,7 +113,7 @@ prune: deps node bin/npm-cli.js prune --omit=dev --no-save --no-audit --no-fund node scripts/git-dirty.js -publish: gitclean ls-ok link lint-all test-all docs prune +publish: gitclean ls-ok link docs lint-all test-all prune node bin/npm-cli.js publish --tag=$(PUBLISHTAG) release: gitclean ls-ok docs prune From bc2155247d00b7a868c414f4bc86993069b035f9 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 28 Sep 2022 15:14:34 -0700 Subject: [PATCH 35/40] deps: npm-package-arg@9.1.2 Fixes #4994 --- node_modules/npm-package-arg/lib/npa.js | 6 ++++-- node_modules/npm-package-arg/package.json | 26 +++++++++++++++++------ package-lock.json | 8 +++---- package.json | 2 +- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/node_modules/npm-package-arg/lib/npa.js b/node_modules/npm-package-arg/lib/npa.js index 61fee0783ecc7..cd1932b0bc78b 100644 --- a/node_modules/npm-package-arg/lib/npa.js +++ b/node_modules/npm-package-arg/lib/npa.js @@ -241,8 +241,10 @@ function fromFile (res, where) { rawNoPrefix = rawSpec.replace(/^file:/, '') } // turn file:/../foo into file:../foo - if (/^\/\.\.?(\/|$)/.test(rawNoPrefix)) { - const rawSpec = res.rawSpec.replace(/^file:\//, 'file:') + // for 1, 2 or 3 leading slashes since we attempted + // in the previous step to make it a file protocol url with a leading slash + if (/^\/{1,3}\.\.?(\/|$)/.test(rawNoPrefix)) { + const rawSpec = res.rawSpec.replace(/^file:\/{1,3}/, 'file:') resolvedUrl = new url.URL(rawSpec, `file://${path.resolve(where)}/`) specUrl = new url.URL(rawSpec) rawNoPrefix = rawSpec.replace(/^file:/, '') diff --git a/node_modules/npm-package-arg/package.json b/node_modules/npm-package-arg/package.json index b9729db5d4f14..eddc6bbbbb8f8 100644 --- a/node_modules/npm-package-arg/package.json +++ b/node_modules/npm-package-arg/package.json @@ -1,6 +1,6 @@ { "name": "npm-package-arg", - "version": "9.1.0", + "version": "9.1.2", "description": "Parse the things that can be arguments to `npm install`", "main": "./lib/npa.js", "directories": { @@ -18,13 +18,10 @@ }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", + "@npmcli/template-oss": "4.3.2", "tap": "^16.0.1" }, "scripts": { - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "test": "tap", "snap": "tap", "npmclilint": "npmcli-lint", @@ -49,10 +46,25 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" }, "tap": { - "branches": 97 + "branches": 97, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" + "version": "4.3.2", + "releaseBranches": [ + "v9" + ], + "ciVersions": [ + "12.13.0", + "12.x", + "14.15.0", + "14.x", + "16.0.0", + "16.x" + ] } } diff --git a/package-lock.json b/package-lock.json index 43f364e27eb8c..2441009d92e20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -135,7 +135,7 @@ "nopt": "^6.0.0", "npm-audit-report": "^3.0.0", "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.1.0", + "npm-package-arg": "^9.1.2", "npm-pick-manifest": "^7.0.2", "npm-profile": "^6.2.0", "npm-registry-fetch": "^13.3.1", @@ -8010,9 +8010,9 @@ "license": "ISC" }, "node_modules/npm-package-arg": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.0.tgz", - "integrity": "sha512-4J0GL+u2Nh6OnhvUKXRr2ZMG4lR8qtLp+kv7UiV00Y+nGiSxtttCyIRHCt5L5BNkXQld/RceYItau3MDOoGiBw==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", + "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", "inBundle": true, "dependencies": { "hosted-git-info": "^5.0.0", diff --git a/package.json b/package.json index 7d0be98833116..250f519e11994 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "nopt": "^6.0.0", "npm-audit-report": "^3.0.0", "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.1.0", + "npm-package-arg": "^9.1.2", "npm-pick-manifest": "^7.0.2", "npm-profile": "^6.2.0", "npm-registry-fetch": "^13.3.1", From 525654e957a80c7f47472e18240e3c8d94e0568f Mon Sep 17 00:00:00 2001 From: Gar Date: Tue, 27 Sep 2022 09:13:10 -0700 Subject: [PATCH 36/40] feat: default access to `public` BREAKING CHANGE: The default value of `access` is now `public` --- workspaces/libnpmpublish/README.md | 4 +- workspaces/libnpmpublish/lib/publish.js | 5 +- workspaces/libnpmpublish/test/publish.js | 62 +++++++++++++++++++++++- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/workspaces/libnpmpublish/README.md b/workspaces/libnpmpublish/README.md index 85fb73e52fdbe..9c9c61d4b5965 100644 --- a/workspaces/libnpmpublish/README.md +++ b/workspaces/libnpmpublish/README.md @@ -44,8 +44,8 @@ A couple of options of note: defaults to `latest`. * `opts.access` - tells the registry whether this package should be - published as public or restricted. Only applies to scoped packages, which - default to restricted. + published as `public` or `restricted`. Only applies to scoped + packages. Defaults to `public`. * `opts.token` - can be passed in and will be used as the authentication token for the registry. For other ways to pass in auth details, see the diff --git a/workspaces/libnpmpublish/lib/publish.js b/workspaces/libnpmpublish/lib/publish.js index 75b764c98963f..7d01fabf1f2b4 100644 --- a/workspaces/libnpmpublish/lib/publish.js +++ b/workspaces/libnpmpublish/lib/publish.js @@ -17,10 +17,9 @@ Remove the 'private' field from the package.json to publish it.`), // spec is used to pick the appropriate registry/auth combo const spec = npa.resolve(manifest.name, manifest.version) opts = { - defaultTag: 'latest', - // if scoped, restricted by default - access: spec.scope ? 'restricted' : 'public', + access: 'public', algorithms: ['sha512'], + defaultTag: 'latest', ...opts, spec, } diff --git a/workspaces/libnpmpublish/test/publish.js b/workspaces/libnpmpublish/test/publish.js index fdd20f899430e..c696e82b22544 100644 --- a/workspaces/libnpmpublish/test/publish.js +++ b/workspaces/libnpmpublish/test/publish.js @@ -79,7 +79,66 @@ t.test('basic publish', async t => { t.ok(ret, 'publish succeeded') }) -t.test('scoped publish', async t => { +t.test('scoped publish - default access', async t => { + const manifest = { + name: '@claudiahdz/libnpmpublish', + version: '1.0.0', + description: 'some stuff', + } + + const tarData = await pack(`file:${testDir}`, { ...OPTS }) + const shasum = crypto.createHash('sha1').update(tarData).digest('hex') + const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) + const packument = { + _id: '@claudiahdz/libnpmpublish', + name: '@claudiahdz/libnpmpublish', + description: 'some stuff', + 'dist-tags': { + latest: '1.0.0', + }, + versions: { + '1.0.0': { + _id: '@claudiahdz/libnpmpublish@1.0.0', + _nodeVersion: process.versions.node, + _npmVersion: '6.13.7', + name: '@claudiahdz/libnpmpublish', + version: '1.0.0', + description: 'some stuff', + dist: { + shasum, + integrity: integrity.toString(), + tarball: 'http://mock.reg/@claudiahdz/libnpmpublish/' + + '-/@claudiahdz/libnpmpublish-1.0.0.tgz', + }, + }, + }, + access: 'public', + _attachments: { + '@claudiahdz/libnpmpublish-1.0.0.tgz': { + content_type: 'application/octet-stream', + data: tarData.toString('base64'), + length: tarData.length, + }, + }, + } + + const srv = tnock(t, REG) + srv.put('/@claudiahdz%2flibnpmpublish', body => { + t.same(body, packument, 'posted packument matches expectations') + return true + }, { + authorization: 'Bearer deadbeef', + }).reply(201, {}) + + const ret = await publish(manifest, tarData, { + ...OPTS, + npmVersion: '6.13.7', + token: 'deadbeef', + }) + t.ok(ret, 'publish succeeded') +}) + +t.test('scoped publish - restricted access', async t => { const manifest = { name: '@claudiahdz/libnpmpublish', version: '1.0.0', @@ -132,6 +191,7 @@ t.test('scoped publish', async t => { const ret = await publish(manifest, tarData, { ...OPTS, + access: 'restricted', npmVersion: '6.13.7', token: 'deadbeef', }) From f0e758494698d9dd8a58d07bf71c87608c36869e Mon Sep 17 00:00:00 2001 From: Gar Date: Wed, 28 Sep 2022 10:56:40 -0700 Subject: [PATCH 37/40] docs: update docs/logging for new --access default --- docs/content/commands/npm-publish.md | 20 ++-- docs/content/using-npm/config.md | 20 ++-- lib/commands/publish.js | 11 +- lib/utils/config/definitions.js | 22 ++-- .../test/lib/commands/publish.js.test.cjs | 100 +++++++++++++++++- .../lib/utils/config/definitions.js.test.cjs | 20 ++-- .../lib/utils/config/describe-all.js.test.cjs | 20 ++-- test/lib/commands/publish.js | 64 ++++++++++- 8 files changed, 217 insertions(+), 60 deletions(-) diff --git a/docs/content/commands/npm-publish.md b/docs/content/commands/npm-publish.md index 536d04988e684..0c1b777c881bb 100644 --- a/docs/content/commands/npm-publish.md +++ b/docs/content/commands/npm-publish.md @@ -118,19 +118,19 @@ tarball that will be compared with the local files by default. #### `access` -* Default: 'restricted' for scoped packages, 'public' for unscoped packages +* Default: 'public' for new packages, existing packages it will not change the + current level * Type: null, "restricted", or "public" -When publishing scoped packages, the access level defaults to `restricted`. -If you want your scoped package to be publicly viewable (and installable) -set `--access=public`. The only valid values for `access` are `public` and -`restricted`. Unscoped packages _always_ have an access level of `public`. +If do not want your scoped package to be publicly viewable (and installable) +set `--access=restricted`. -Note: Using the `--access` flag on the `npm publish` command will only set -the package access level on the initial publish of the package. Any -subsequent `npm publish` commands using the `--access` flag will not have an -effect to the access level. To make changes to the access level after the -initial publish use `npm access`. +Unscoped packages can not be set to `restricted`. + +Note: This defaults to not changing the current access level for existing +packages. Specifying a value of `restricted` or `public` during publish will +change the access for an existing package the same way that `npm access set +status` would. diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index 2de35fa2a46c3..e5d9d081feb4a 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -151,19 +151,19 @@ safer to use a registry-provided authentication bearer token stored in the #### `access` -* Default: 'restricted' for scoped packages, 'public' for unscoped packages +* Default: 'public' for new packages, existing packages it will not change the + current level * Type: null, "restricted", or "public" -When publishing scoped packages, the access level defaults to `restricted`. -If you want your scoped package to be publicly viewable (and installable) -set `--access=public`. The only valid values for `access` are `public` and -`restricted`. Unscoped packages _always_ have an access level of `public`. +If do not want your scoped package to be publicly viewable (and installable) +set `--access=restricted`. -Note: Using the `--access` flag on the `npm publish` command will only set -the package access level on the initial publish of the package. Any -subsequent `npm publish` commands using the `--access` flag will not have an -effect to the access level. To make changes to the access level after the -initial publish use `npm access`. +Unscoped packages can not be set to `restricted`. + +Note: This defaults to not changing the current access level for existing +packages. Specifying a value of `restricted` or `public` during publish will +change the access for an existing package the same way that `npm access set +status` would. diff --git a/lib/commands/publish.js b/lib/commands/publish.js index 64b6dfc513c95..1f281a0bb1d4f 100644 --- a/lib/commands/publish.js +++ b/lib/commands/publish.js @@ -114,10 +114,13 @@ class Publish extends BaseCommand { } } - log.notice( - '', - `Publishing to ${outputRegistry} with tag ${defaultTag}${dryRun ? ' (dry-run)' : ''}` - ) + const access = opts.access === null ? 'default' : opts.access + let msg = `Publishing to ${outputRegistry} with tag ${defaultTag} and ${access} access` + if (dryRun) { + msg = `${msg} (dry-run)` + } + + log.notice('', msg) if (!dryRun) { await otplease(this.npm, opts, opts => libpub(manifest, tarballData, opts)) diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index ae38efc32b5ae..5f74eb03b14c8 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -160,21 +160,19 @@ define('_auth', { define('access', { default: null, defaultDescription: ` - 'restricted' for scoped packages, 'public' for unscoped packages + 'public' for new packages, existing packages it will not change the current level `, type: [null, 'restricted', 'public'], description: ` - When publishing scoped packages, the access level defaults to - \`restricted\`. If you want your scoped package to be publicly viewable - (and installable) set \`--access=public\`. The only valid values for - \`access\` are \`public\` and \`restricted\`. Unscoped packages _always_ - have an access level of \`public\`. - - Note: Using the \`--access\` flag on the \`npm publish\` command will only - set the package access level on the initial publish of the package. Any - subsequent \`npm publish\` commands using the \`--access\` flag will not - have an effect to the access level. To make changes to the access level - after the initial publish use \`npm access\`. + If do not want your scoped package to be publicly viewable (and + installable) set \`--access=restricted\`. + + Unscoped packages can not be set to \`restricted\`. + + Note: This defaults to not changing the current access level for existing + packages. Specifying a value of \`restricted\` or \`public\` during + publish will change the access for an existing package the same way that + \`npm access set status\` would. `, flatten, }) diff --git a/tap-snapshots/test/lib/commands/publish.js.test.cjs b/tap-snapshots/test/lib/commands/publish.js.test.cjs index 3b215960fa37e..28211f7794cba 100644 --- a/tap-snapshots/test/lib/commands/publish.js.test.cjs +++ b/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -51,7 +51,7 @@ Array [ ], Array [ "", - "Publishing to https://registry.npmjs.org/ with tag latest (dry-run)", + "Publishing to https://registry.npmjs.org/ with tag latest and default access (dry-run)", ], ] ` @@ -72,7 +72,7 @@ exports[`test/lib/commands/publish.js TAP json > must match snapshot 1`] = ` Array [ Array [ "", - "Publishing to https://registry.npmjs.org/ with tag latest", + "Publishing to https://registry.npmjs.org/ with tag latest and default access", ], ] ` @@ -112,6 +112,53 @@ Array [ ] ` +exports[`test/lib/commands/publish.js TAP public access > must match snapshot 1`] = ` +Array [ + Array [ + "", + ], + Array [ + "", + "package: @npm/test-package@1.0.0", + ], + Array [ + "=== Tarball Contents ===", + ], + Array [ + "", + "55B package.json", + ], + Array [ + "=== Tarball Details ===", + ], + Array [ + "", + String( + name: @npm/test-package + version: 1.0.0 + filename: @npm/test-package-1.0.0.tgz + package size: 147 B + unpacked size: 55 B + shasum:{sha} + integrity:{sha} + total files: 1 + ), + ], + Array [ + "", + "", + ], + Array [ + "", + "Publishing to https://registry.npmjs.org/ with tag latest and public access", + ], +] +` + +exports[`test/lib/commands/publish.js TAP public access > new package version 1`] = ` ++ @npm/test-package@1.0.0 +` + exports[`test/lib/commands/publish.js TAP re-loads publishConfig.registry if added during script process > new package version 1`] = ` + test-package@1.0.0 ` @@ -120,6 +167,53 @@ exports[`test/lib/commands/publish.js TAP respects publishConfig.registry, runs ` +exports[`test/lib/commands/publish.js TAP restricted access > must match snapshot 1`] = ` +Array [ + Array [ + "", + ], + Array [ + "", + "package: @npm/test-package@1.0.0", + ], + Array [ + "=== Tarball Contents ===", + ], + Array [ + "", + "55B package.json", + ], + Array [ + "=== Tarball Details ===", + ], + Array [ + "", + String( + name: @npm/test-package + version: 1.0.0 + filename: @npm/test-package-1.0.0.tgz + package size: 147 B + unpacked size: 55 B + shasum:{sha} + integrity:{sha} + total files: 1 + ), + ], + Array [ + "", + "", + ], + Array [ + "", + "Publishing to https://registry.npmjs.org/ with tag latest and restricted access", + ], +] +` + +exports[`test/lib/commands/publish.js TAP restricted access > new package version 1`] = ` ++ @npm/test-package@1.0.0 +` + exports[`test/lib/commands/publish.js TAP scoped _auth config scoped registry > new package version 1`] = ` + @npm/test-package@1.0.0 ` @@ -165,7 +259,7 @@ Array [ ], Array [ "", - "Publishing to https://registry.npmjs.org/ with tag latest", + "Publishing to https://registry.npmjs.org/ with tag latest and default access", ], ] ` diff --git a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index df9313270d056..1005b9e4df112 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -180,19 +180,19 @@ safer to use a registry-provided authentication bearer token stored in the exports[`test/lib/utils/config/definitions.js TAP > config description for access 1`] = ` #### \`access\` -* Default: 'restricted' for scoped packages, 'public' for unscoped packages +* Default: 'public' for new packages, existing packages it will not change the + current level * Type: null, "restricted", or "public" -When publishing scoped packages, the access level defaults to \`restricted\`. -If you want your scoped package to be publicly viewable (and installable) -set \`--access=public\`. The only valid values for \`access\` are \`public\` and -\`restricted\`. Unscoped packages _always_ have an access level of \`public\`. +If do not want your scoped package to be publicly viewable (and installable) +set \`--access=restricted\`. -Note: Using the \`--access\` flag on the \`npm publish\` command will only set -the package access level on the initial publish of the package. Any -subsequent \`npm publish\` commands using the \`--access\` flag will not have an -effect to the access level. To make changes to the access level after the -initial publish use \`npm access\`. +Unscoped packages can not be set to \`restricted\`. + +Note: This defaults to not changing the current access level for existing +packages. Specifying a value of \`restricted\` or \`public\` during publish will +change the access for an existing package the same way that \`npm access set +status\` would. ` exports[`test/lib/utils/config/definitions.js TAP > config description for all 1`] = ` diff --git a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index 89ca7c952b182..e14b88464237c 100644 --- a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -24,19 +24,19 @@ safer to use a registry-provided authentication bearer token stored in the #### \`access\` -* Default: 'restricted' for scoped packages, 'public' for unscoped packages +* Default: 'public' for new packages, existing packages it will not change the + current level * Type: null, "restricted", or "public" -When publishing scoped packages, the access level defaults to \`restricted\`. -If you want your scoped package to be publicly viewable (and installable) -set \`--access=public\`. The only valid values for \`access\` are \`public\` and -\`restricted\`. Unscoped packages _always_ have an access level of \`public\`. +If do not want your scoped package to be publicly viewable (and installable) +set \`--access=restricted\`. -Note: Using the \`--access\` flag on the \`npm publish\` command will only set -the package access level on the initial publish of the package. Any -subsequent \`npm publish\` commands using the \`--access\` flag will not have an -effect to the access level. To make changes to the access level after the -initial publish use \`npm access\`. +Unscoped packages can not be set to \`restricted\`. + +Note: This defaults to not changing the current access level for existing +packages. Specifying a value of \`restricted\` or \`public\` during publish will +change the access for an existing package the same way that \`npm access set +status\` would. diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index 16b79df532d82..995abff88c2c1 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -28,7 +28,7 @@ t.cleanSnapshot = data => { t.test('respects publishConfig.registry, runs appropriate scripts', async t => { const { npm, joinedOutput, prefix } = await loadMockNpm(t, { config: { - loglevel: 'silent', // prevent scripts from leaking to stdout during the test + loglevel: 'silent', [`${alternateRegistry.slice(6)}/:_authToken`]: 'test-other-token', }, prefixDir: { @@ -730,3 +730,65 @@ t.test('scoped _auth config scoped registry', async t => { await npm.exec('publish', []) t.matchSnapshot(joinedOutput(), 'new package version') }) + +t.test('restricted access', async t => { + const spec = npa('@npm/test-package') + const { npm, joinedOutput, logs } = await loadMockNpm(t, { + config: { + ...auth, + access: 'restricted', + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: '@npm/test-package', + version: '1.0.0', + }, null, 2), + }, + globals: ({ prefix }) => ({ + 'process.cwd': () => prefix, + }), + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: token, + }) + registry.nock.put(`/${spec.escapedName}`, body => { + t.equal(body.access, 'restricted', 'access is explicitly set to restricted') + return true + }).reply(200, {}) + await npm.exec('publish', []) + t.matchSnapshot(joinedOutput(), 'new package version') + t.matchSnapshot(logs.notice) +}) + +t.test('public access', async t => { + const spec = npa('@npm/test-package') + const { npm, joinedOutput, logs } = await loadMockNpm(t, { + config: { + ...auth, + access: 'public', + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: '@npm/test-package', + version: '1.0.0', + }, null, 2), + }, + globals: ({ prefix }) => ({ + 'process.cwd': () => prefix, + }), + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + authorization: token, + }) + registry.nock.put(`/${spec.escapedName}`, body => { + t.equal(body.access, 'public', 'access is explicitly set to public') + return true + }).reply(200, {}) + await npm.exec('publish', []) + t.matchSnapshot(joinedOutput(), 'new package version') + t.matchSnapshot(logs.notice) +}) From 3ae796d937bd36a5b1b9fd6e9e8473b4f2ddc32d Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Wed, 28 Sep 2022 12:27:58 -0700 Subject: [PATCH 38/40] feat: implement new `npm-packlist` behavior This also lands the latest `pacote` which now requires passing in an `Arborist` constructor for use in loading the package tree that gets passed to `npm-packlist`. BREAKING CHANGE: `npm pack` now follows a strict order of operations when applying ignore rules. If a files array is present in the package.json, then rules in .gitignore and .npmignore files from the root will be ignored. --- DEPENDENCIES.md | 20 +- lib/commands/cache.js | 3 +- lib/package-url-cmd.js | 2 + .../@npmcli/metavuln-calculator/package.json | 19 +- node_modules/npm-bundled/LICENSE | 15 - node_modules/npm-bundled/lib/index.js | 254 ------ .../npm-normalize-package-bin/LICENSE | 15 - .../npm-normalize-package-bin/lib/index.js | 64 -- .../npm-normalize-package-bin/package.json | 41 - node_modules/npm-bundled/package.json | 47 -- node_modules/npm-packlist/bin/index.js | 39 - node_modules/npm-packlist/lib/index.js | 766 ++++++++---------- .../npm-normalize-package-bin/LICENSE | 15 - .../npm-normalize-package-bin/lib/index.js | 64 -- .../npm-normalize-package-bin/package.json | 41 - node_modules/npm-packlist/package.json | 29 +- node_modules/pacote/lib/dir.js | 15 +- node_modules/pacote/lib/git.js | 6 + node_modules/pacote/lib/registry.js | 1 - node_modules/pacote/package.json | 22 +- package-lock.json | 80 +- package.json | 2 +- tap-snapshots/test/lib/utils/tar.js.test.cjs | 16 +- test/fixtures/mock-registry.js | 3 +- test/lib/commands/publish.js | 3 +- test/lib/utils/tar.js | 9 +- .../arborist/lib/arborist/build-ideal-tree.js | 1 + workspaces/arborist/lib/arborist/reify.js | 1 + workspaces/arborist/package.json | 4 +- .../registry-mocks/fetch-lock-contents.js | 3 +- workspaces/libnpmdiff/lib/tarball.js | 6 +- workspaces/libnpmdiff/package.json | 3 +- workspaces/libnpmexec/package.json | 2 +- workspaces/libnpmpack/lib/index.js | 2 + workspaces/libnpmpack/package.json | 3 +- 35 files changed, 481 insertions(+), 1135 deletions(-) delete mode 100644 node_modules/npm-bundled/LICENSE delete mode 100644 node_modules/npm-bundled/lib/index.js delete mode 100644 node_modules/npm-bundled/node_modules/npm-normalize-package-bin/LICENSE delete mode 100644 node_modules/npm-bundled/node_modules/npm-normalize-package-bin/lib/index.js delete mode 100644 node_modules/npm-bundled/node_modules/npm-normalize-package-bin/package.json delete mode 100644 node_modules/npm-bundled/package.json delete mode 100755 node_modules/npm-packlist/bin/index.js delete mode 100644 node_modules/npm-packlist/node_modules/npm-normalize-package-bin/LICENSE delete mode 100644 node_modules/npm-packlist/node_modules/npm-normalize-package-bin/lib/index.js delete mode 100644 node_modules/npm-packlist/node_modules/npm-normalize-package-bin/package.json diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index e14cecf0dc7fe..0ce063561c744 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -25,6 +25,7 @@ graph LR; libnpmaccess-->npmcli-eslint-config["@npmcli/eslint-config"]; libnpmaccess-->npmcli-template-oss["@npmcli/template-oss"]; libnpmdiff-->npm-package-arg; + libnpmdiff-->npmcli-arborist["@npmcli/arborist"]; libnpmdiff-->npmcli-disparity-colors["@npmcli/disparity-colors"]; libnpmdiff-->npmcli-eslint-config["@npmcli/eslint-config"]; libnpmdiff-->npmcli-installed-package-contents["@npmcli/installed-package-contents"]; @@ -54,6 +55,7 @@ graph LR; libnpmorg-->npmcli-eslint-config["@npmcli/eslint-config"]; libnpmorg-->npmcli-template-oss["@npmcli/template-oss"]; libnpmpack-->npm-package-arg; + libnpmpack-->npmcli-arborist["@npmcli/arborist"]; libnpmpack-->npmcli-eslint-config["@npmcli/eslint-config"]; libnpmpack-->npmcli-run-script["@npmcli/run-script"]; libnpmpack-->npmcli-template-oss["@npmcli/template-oss"]; @@ -139,8 +141,6 @@ graph LR; npm-package-arg-->semver; npm-package-arg-->validate-npm-package-name; npm-packlist-->ignore-walk; - npm-packlist-->npm-bundled; - npm-packlist-->npm-normalize-package-bin; npm-profile-->npm-registry-fetch; npm-profile-->proc-log; npm-registry-fetch-->make-fetch-happen; @@ -333,6 +333,7 @@ graph LR; libnpmdiff-->diff; libnpmdiff-->minimatch; libnpmdiff-->npm-package-arg; + libnpmdiff-->npmcli-arborist["@npmcli/arborist"]; libnpmdiff-->npmcli-disparity-colors["@npmcli/disparity-colors"]; libnpmdiff-->npmcli-eslint-config["@npmcli/eslint-config"]; libnpmdiff-->npmcli-installed-package-contents["@npmcli/installed-package-contents"]; @@ -379,6 +380,7 @@ graph LR; libnpmorg-->tap; libnpmpack-->nock; libnpmpack-->npm-package-arg; + libnpmpack-->npmcli-arborist["@npmcli/arborist"]; libnpmpack-->npmcli-eslint-config["@npmcli/eslint-config"]; libnpmpack-->npmcli-run-script["@npmcli/run-script"]; libnpmpack-->npmcli-template-oss["@npmcli/template-oss"]; @@ -554,10 +556,7 @@ graph LR; npm-package-arg-->proc-log; npm-package-arg-->semver; npm-package-arg-->validate-npm-package-name; - npm-packlist-->glob; npm-packlist-->ignore-walk; - npm-packlist-->npm-bundled; - npm-packlist-->npm-normalize-package-bin; npm-pick-manifest-->npm-install-checks; npm-pick-manifest-->npm-normalize-package-bin; npm-pick-manifest-->npm-package-arg; @@ -756,12 +755,13 @@ Each group depends on packages lower down the chain, nothing depends on packages higher up the chain. - npm - - libnpmexec, libnpmfund - - @npmcli/arborist, libnpmpublish - - @npmcli/metavuln-calculator, libnpmdiff, libnpmpack + - libnpmpublish + - libnpmdiff, libnpmexec, libnpmfund, libnpmpack + - @npmcli/arborist + - @npmcli/metavuln-calculator - pacote, libnpmaccess, libnpmhook, libnpmorg, libnpmsearch, libnpmteam, npm-profile - npm-registry-fetch - make-fetch-happen, libnpmversion, @npmcli/config, init-package-json - - @npmcli/installed-package-contents, @npmcli/map-workspaces, cacache, @npmcli/git, @npmcli/run-script, npm-packlist, read-package-json, @npmcli/query, readdir-scoped-modules, promzard - - npm-bundled, read-package-json-fast, @npmcli/fs, unique-filename, @npmcli/promise-spawn, npm-package-arg, normalize-package-data, bin-links, nopt, npm-install-checks, npmlog, dezalgo, read + - @npmcli/installed-package-contents, @npmcli/map-workspaces, cacache, @npmcli/git, @npmcli/run-script, read-package-json, @npmcli/query, readdir-scoped-modules, promzard + - npm-bundled, read-package-json-fast, @npmcli/fs, unique-filename, @npmcli/promise-spawn, npm-package-arg, npm-packlist, normalize-package-data, bin-links, nopt, npm-install-checks, npmlog, dezalgo, read - npm-normalize-package-bin, @npmcli/name-from-folder, semver, @npmcli/move-file, fs-minipass, infer-owner, ssri, unique-slug, proc-log, @npmcli/node-gyp, hosted-git-info, validate-npm-package-name, ignore-walk, minipass-fetch, @npmcli/package-json, cmd-shim, read-cmd-shim, write-file-atomic, abbrev, are-we-there-yet, gauge, parse-conflict-json, wrappy, treeverse, @npmcli/eslint-config, @npmcli/template-oss, @npmcli/disparity-colors, @npmcli/ci-detect, mute-stream, ini, npm-audit-report, npm-user-validate \ No newline at end of file diff --git a/lib/commands/cache.js b/lib/commands/cache.js index bc52889c0006f..a2e6434b34cab 100644 --- a/lib/commands/cache.js +++ b/lib/commands/cache.js @@ -1,4 +1,5 @@ const cacache = require('cacache') +const Arborist = require('@npmcli/arborist') const { promisify } = require('util') const pacote = require('pacote') const path = require('path') @@ -164,7 +165,7 @@ class Cache extends BaseCommand { return pacote.tarball.stream(spec, stream => { stream.resume() return stream.promise() - }, this.npm.flatOptions) + }, { ...this.npm.flatOptions, Arborist }) })) } diff --git a/lib/package-url-cmd.js b/lib/package-url-cmd.js index 4254dde4517ba..eac2bbe1b6d51 100644 --- a/lib/package-url-cmd.js +++ b/lib/package-url-cmd.js @@ -2,6 +2,7 @@ const pacote = require('pacote') const hostedGitInfo = require('hosted-git-info') +const Arborist = require('@npmcli/arborist') const openUrl = require('./utils/open-url.js') const log = require('./utils/log-shim') @@ -31,6 +32,7 @@ class PackageUrlCommand extends BaseCommand { ...this.npm.flatOptions, where: this.npm.localPrefix, fullMetadata: true, + Arborist, } const mani = await pacote.manifest(arg, opts) const url = this.getUrl(arg, mani) diff --git a/node_modules/@npmcli/metavuln-calculator/package.json b/node_modules/@npmcli/metavuln-calculator/package.json index 2e7209ffc7da0..90b4d2ecddce4 100644 --- a/node_modules/@npmcli/metavuln-calculator/package.json +++ b/node_modules/@npmcli/metavuln-calculator/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/metavuln-calculator", - "version": "3.1.1", + "version": "4.0.0-pre.0", "main": "lib/index.js", "files": [ "bin/", @@ -18,9 +18,6 @@ "posttest": "npm run lint", "snap": "tap", "postsnap": "npm run lint", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "eslint": "eslint", "lint": "eslint \"**/*.js\"", "lintfix": "npm run lint -- --fix", @@ -29,25 +26,29 @@ }, "tap": { "check-coverage": true, - "coverage-map": "map.js" + "coverage-map": "map.js", + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "devDependencies": { "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", + "@npmcli/template-oss": "4.4.2", "require-inject": "^1.4.4", "tap": "^16.0.1" }, "dependencies": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", + "pacote": "^14.0.0 || ^14.0.0-pre.0", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" + "version": "4.4.2" } } diff --git a/node_modules/npm-bundled/LICENSE b/node_modules/npm-bundled/LICENSE deleted file mode 100644 index 20a4762540923..0000000000000 --- a/node_modules/npm-bundled/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) npm, Inc. and Contributors - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/npm-bundled/lib/index.js b/node_modules/npm-bundled/lib/index.js deleted file mode 100644 index 4f54ca647c087..0000000000000 --- a/node_modules/npm-bundled/lib/index.js +++ /dev/null @@ -1,254 +0,0 @@ -'use strict' - -// walk the tree of deps starting from the top level list of bundled deps -// Any deps at the top level that are depended on by a bundled dep that -// does not have that dep in its own node_modules folder are considered -// bundled deps as well. This list of names can be passed to npm-packlist -// as the "bundled" argument. Additionally, packageJsonCache is shared so -// packlist doesn't have to re-read files already consumed in this pass - -const fs = require('fs') -const path = require('path') -const EE = require('events').EventEmitter -// we don't care about the package bins, but we share a pj cache -// with other modules that DO care about it, so keep it nice. -const normalizePackageBin = require('npm-normalize-package-bin') - -class BundleWalker extends EE { - constructor (opt) { - opt = opt || {} - super(opt) - this.path = path.resolve(opt.path || process.cwd()) - - this.parent = opt.parent || null - if (this.parent) { - this.result = this.parent.result - // only collect results in node_modules folders at the top level - // since the node_modules in a bundled dep is included always - if (!this.parent.parent) { - const base = path.basename(this.path) - const scope = path.basename(path.dirname(this.path)) - this.result.add(/^@/.test(scope) ? scope + '/' + base : base) - } - this.root = this.parent.root - this.packageJsonCache = this.parent.packageJsonCache - } else { - this.result = new Set() - this.root = this.path - this.packageJsonCache = opt.packageJsonCache || new Map() - } - - this.seen = new Set() - this.didDone = false - this.children = 0 - this.node_modules = [] - this.package = null - this.bundle = null - } - - addListener (ev, fn) { - return this.on(ev, fn) - } - - on (ev, fn) { - const ret = super.on(ev, fn) - if (ev === 'done' && this.didDone) { - this.emit('done', this.result) - } - return ret - } - - done () { - if (!this.didDone) { - this.didDone = true - if (!this.parent) { - const res = Array.from(this.result) - this.result = res - this.emit('done', res) - } else { - this.emit('done') - } - } - } - - start () { - const pj = path.resolve(this.path, 'package.json') - if (this.packageJsonCache.has(pj)) { - this.onPackage(this.packageJsonCache.get(pj)) - } else { - this.readPackageJson(pj) - } - return this - } - - readPackageJson (pj) { - fs.readFile(pj, (er, data) => - er ? this.done() : this.onPackageJson(pj, data)) - } - - onPackageJson (pj, data) { - try { - this.package = normalizePackageBin(JSON.parse(data + '')) - } catch (er) { - return this.done() - } - this.packageJsonCache.set(pj, this.package) - this.onPackage(this.package) - } - - allDepsBundled (pkg) { - return Object.keys(pkg.dependencies || {}).concat( - Object.keys(pkg.optionalDependencies || {})) - } - - onPackage (pkg) { - // all deps are bundled if we got here as a child. - // otherwise, only bundle bundledDeps - // Get a unique-ified array with a short-lived Set - const bdRaw = this.parent ? this.allDepsBundled(pkg) - : pkg.bundleDependencies || pkg.bundledDependencies || [] - - const bd = Array.from(new Set( - Array.isArray(bdRaw) ? bdRaw - : bdRaw === true ? this.allDepsBundled(pkg) - : Object.keys(bdRaw))) - - if (!bd.length) { - return this.done() - } - - this.bundle = bd - this.readModules() - } - - readModules () { - readdirNodeModules(this.path + '/node_modules', (er, nm) => - er ? this.onReaddir([]) : this.onReaddir(nm)) - } - - onReaddir (nm) { - // keep track of what we have, in case children need it - this.node_modules = nm - - this.bundle.forEach(dep => this.childDep(dep)) - if (this.children === 0) { - this.done() - } - } - - childDep (dep) { - if (this.node_modules.indexOf(dep) !== -1) { - if (!this.seen.has(dep)) { - this.seen.add(dep) - this.child(dep) - } - } else if (this.parent) { - this.parent.childDep(dep) - } - } - - child (dep) { - const p = this.path + '/node_modules/' + dep - this.children += 1 - const child = new BundleWalker({ - path: p, - parent: this, - }) - child.on('done', _ => { - if (--this.children === 0) { - this.done() - } - }) - child.start() - } -} - -class BundleWalkerSync extends BundleWalker { - start () { - super.start() - this.done() - return this - } - - readPackageJson (pj) { - try { - this.onPackageJson(pj, fs.readFileSync(pj)) - } catch { - // empty catch - } - return this - } - - readModules () { - try { - this.onReaddir(readdirNodeModulesSync(this.path + '/node_modules')) - } catch { - this.onReaddir([]) - } - } - - child (dep) { - new BundleWalkerSync({ - path: this.path + '/node_modules/' + dep, - parent: this, - }).start() - } -} - -const readdirNodeModules = (nm, cb) => { - fs.readdir(nm, (er, set) => { - if (er) { - cb(er) - } else { - const scopes = set.filter(f => /^@/.test(f)) - if (!scopes.length) { - cb(null, set) - } else { - const unscoped = set.filter(f => !/^@/.test(f)) - let count = scopes.length - scopes.forEach(scope => { - fs.readdir(nm + '/' + scope, (readdirEr, pkgs) => { - if (readdirEr || !pkgs.length) { - unscoped.push(scope) - } else { - unscoped.push.apply(unscoped, pkgs.map(p => scope + '/' + p)) - } - if (--count === 0) { - cb(null, unscoped) - } - }) - }) - } - } - }) -} - -const readdirNodeModulesSync = nm => { - const set = fs.readdirSync(nm) - const unscoped = set.filter(f => !/^@/.test(f)) - const scopes = set.filter(f => /^@/.test(f)).map(scope => { - try { - const pkgs = fs.readdirSync(nm + '/' + scope) - return pkgs.length ? pkgs.map(p => scope + '/' + p) : [scope] - } catch (er) { - return [scope] - } - }).reduce((a, b) => a.concat(b), []) - return unscoped.concat(scopes) -} - -const walk = (options, callback) => { - const p = new Promise((resolve, reject) => { - new BundleWalker(options).on('done', resolve).on('error', reject).start() - }) - return callback ? p.then(res => callback(null, res), callback) : p -} - -const walkSync = options => { - return new BundleWalkerSync(options).start().result -} - -module.exports = walk -walk.sync = walkSync -walk.BundleWalker = BundleWalker -walk.BundleWalkerSync = BundleWalkerSync diff --git a/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/LICENSE b/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/LICENSE deleted file mode 100644 index 19cec97b18468..0000000000000 --- a/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) npm, Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/lib/index.js b/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/lib/index.js deleted file mode 100644 index d6f0a581b9e66..0000000000000 --- a/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/lib/index.js +++ /dev/null @@ -1,64 +0,0 @@ -// pass in a manifest with a 'bin' field here, and it'll turn it -// into a properly santized bin object -const { join, basename } = require('path') - -const normalize = pkg => - !pkg.bin ? removeBin(pkg) - : typeof pkg.bin === 'string' ? normalizeString(pkg) - : Array.isArray(pkg.bin) ? normalizeArray(pkg) - : typeof pkg.bin === 'object' ? normalizeObject(pkg) - : removeBin(pkg) - -const normalizeString = pkg => { - if (!pkg.name) { - return removeBin(pkg) - } - pkg.bin = { [pkg.name]: pkg.bin } - return normalizeObject(pkg) -} - -const normalizeArray = pkg => { - pkg.bin = pkg.bin.reduce((acc, k) => { - acc[basename(k)] = k - return acc - }, {}) - return normalizeObject(pkg) -} - -const removeBin = pkg => { - delete pkg.bin - return pkg -} - -const normalizeObject = pkg => { - const orig = pkg.bin - const clean = {} - let hasBins = false - Object.keys(orig).forEach(binKey => { - const base = join('/', basename(binKey.replace(/\\|:/g, '/'))).slice(1) - - if (typeof orig[binKey] !== 'string' || !base) { - return - } - - const binTarget = join('/', orig[binKey]) - .replace(/\\/g, '/').slice(1) - - if (!binTarget) { - return - } - - clean[base] = binTarget - hasBins = true - }) - - if (hasBins) { - pkg.bin = clean - } else { - delete pkg.bin - } - - return pkg -} - -module.exports = normalize diff --git a/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/package.json b/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/package.json deleted file mode 100644 index 02de808d9b702..0000000000000 --- a/node_modules/npm-bundled/node_modules/npm-normalize-package-bin/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "npm-normalize-package-bin", - "version": "2.0.0", - "description": "Turn any flavor of allowable package.json bin into a normalized object", - "main": "lib/index.js", - "repository": { - "type": "git", - "url": "https://github.com/npm/npm-normalize-package-bin.git" - }, - "author": "GitHub Inc.", - "license": "ISC", - "scripts": { - "test": "tap", - "snap": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "prepublishOnly": "git push origin --follow-tags", - "posttest": "npm run lint" - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.3.0" - }, - "files": [ - "bin/", - "lib/" - ], - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/npm-bundled/package.json b/node_modules/npm-bundled/package.json deleted file mode 100644 index e4c0106c2d504..0000000000000 --- a/node_modules/npm-bundled/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "npm-bundled", - "version": "2.0.1", - "description": "list things in node_modules that are bundledDependencies, or transitive dependencies thereof", - "main": "lib/index.js", - "repository": { - "type": "git", - "url": "https://github.com/npm/npm-bundled.git" - }, - "author": "GitHub Inc.", - "license": "ISC", - "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "3.5.0", - "mkdirp": "^1.0.4", - "mutate-fs": "^2.1.1", - "rimraf": "^3.0.2", - "tap": "^16.3.0" - }, - "scripts": { - "test": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --all; git push origin --tags", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "prepublishOnly": "git push origin --follow-tags", - "snap": "tap", - "posttest": "npm run lint" - }, - "files": [ - "bin/", - "lib/" - ], - "dependencies": { - "npm-normalize-package-bin": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/npm-packlist/bin/index.js b/node_modules/npm-packlist/bin/index.js deleted file mode 100755 index 48a6b879aa823..0000000000000 --- a/node_modules/npm-packlist/bin/index.js +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env node -'use strict' - -const packlist = require('../') - -const dirs = [] -let doSort = false -process.argv.slice(2).forEach(arg => { - if (arg === '-h' || arg === '--help') { - console.log('usage: npm-packlist [-s --sort] [directory, directory, ...]') - process.exit(0) - } else if (arg === '-s' || arg === '--sort') { - doSort = true - } else { - dirs.push(arg) - } -}) - -const sort = list => doSort ? list.sort((a, b) => a.localeCompare(b, 'en')) : list - -const main = async () => { - if (!dirs.length) { - const results = await packlist({ path: process.cwd() }) - console.log(sort(results).join('\n')) - } else { - for (const dir of dirs) { - console.group(`> ${dir}`) - const results = await packlist({ path: dir }) - console.log(sort(results).join('\n')) - console.groupEnd() - } - } -} - -// coverage disabled for catch handler because we don't need to test that -main().catch(/* istanbul ignore next */(err) => { - process.exitCode = 1 - console.error(err.stack) -}) diff --git a/node_modules/npm-packlist/lib/index.js b/node_modules/npm-packlist/lib/index.js index bd72329f027e6..1b2cdbb8df641 100644 --- a/node_modules/npm-packlist/lib/index.js +++ b/node_modules/npm-packlist/lib/index.js @@ -1,87 +1,18 @@ 'use strict' -// Do a two-pass walk, first to get the list of packages that need to be -// bundled, then again to get the actual files and folders. -// Keep a cache of node_modules content and package.json data, so that the -// second walk doesn't have to re-do all the same work. +const { Walker: IgnoreWalker } = require('ignore-walk') +const { lstatSync: lstat, readFileSync: readFile } = require('fs') +const { basename, dirname, extname, join, relative, resolve, sep } = require('path') -const bundleWalk = require('npm-bundled') -const BundleWalker = bundleWalk.BundleWalker +// symbols used to represent synthetic rule sets +const defaultRules = Symbol('npm-packlist.rules.default') +const strictRules = Symbol('npm-packlist.rules.strict') -const ignoreWalk = require('ignore-walk') -const IgnoreWalker = ignoreWalk.Walker - -const rootBuiltinRules = Symbol('root-builtin-rules') -const packageNecessaryRules = Symbol('package-necessary-rules') -const path = require('path') - -const normalizePackageBin = require('npm-normalize-package-bin') - -// Weird side-effect of this: a readme (etc) file will be included -// if it exists anywhere within a folder with a package.json file. -// The original intent was only to include these files in the root, -// but now users in the wild are dependent on that behavior for -// localized documentation and other use cases. Adding a `/` to -// these rules, while tempting and arguably more "correct", is a -// significant change that will break existing use cases. -const packageMustHaveFileNames = 'readme|copying|license|licence' - -const packageMustHaves = `@(${packageMustHaveFileNames}){,.*[^~$]}` -const packageMustHavesRE = new RegExp(`^(${packageMustHaveFileNames})(\\..*[^~$])?$`, 'i') - -const fs = require('fs') -const glob = require('glob') -const globify = pattern => pattern.split('\\').join('/') - -const readOutOfTreeIgnoreFiles = (root, rel, result = '') => { - for (const file of ['.npmignore', '.gitignore']) { - try { - const ignoreContent = fs.readFileSync(path.join(root, file), { encoding: 'utf8' }) - result += ignoreContent + '\n' - // break the loop immediately after concatting, this allows us to prioritize the - // .npmignore and discard the .gitignore if one exists - break - } catch (err) { - // we ignore ENOENT errors completely because we don't care if the file doesn't exist - // but we throw everything else because failing to read a file that does exist is - // something that the user likely wants to know about. we don't need to test this. - /* istanbul ignore next */ - if (err.code !== 'ENOENT') { - throw err - } - } - } - - if (!rel) { - return result - } - - const firstRel = rel.split(path.sep)[0] - const newRoot = path.join(root, firstRel) - const newRel = path.relative(newRoot, path.join(root, rel)) - - return readOutOfTreeIgnoreFiles(newRoot, newRel, result) -} - -const pathHasPkg = (input) => { - if (!input.startsWith('node_modules/')) { - return false - } - - const segments = input.slice('node_modules/'.length).split('/', 2) - return segments[0].startsWith('@') - ? segments.length === 2 - : true -} - -const pkgFromPath = (input) => { - const segments = input.slice('node_modules/'.length).split('/', 2) - return segments[0].startsWith('@') - ? segments.join('/') - : segments[0] -} +// There may be others, but :?|<> are handled by node-tar +const nameIsBadForWindows = file => /\*/.test(file) -const defaultRules = [ +// these are the default rules that are applied to everything except for non-link bundled deps +const defaults = [ '.npmignore', '.gitignore', '**/.git', @@ -103,410 +34,413 @@ const defaultRules = [ '._*', '**/._*/**', '*.orig', - '/package-lock.json', - '/yarn.lock', - '/pnpm-lock.yaml', '/archived-packages/**', ] -// There may be others, but :?|<> are handled by node-tar -const nameIsBadForWindows = file => /\*/.test(file) +const strictDefaults = [ + // these are forcibly included at all levels + '!/readme{,.*[^~$]}', + '!/copying{,.*[^~$]}', + '!/license{,.*[^~$]}', + '!/licence{,.*[^~$]}', + // these are forcibly excluded + '/.git', +] -class Walker extends IgnoreWalker { - constructor (opt) { - opt = opt || {} - - // the order in which rules are applied. - opt.ignoreFiles = [ - rootBuiltinRules, - 'package.json', - '.npmignore', - '.gitignore', - packageNecessaryRules, - ] +const normalizePath = (path) => path.split('\\').join('/') - opt.includeEmpty = false - opt.path = opt.path || process.cwd() - - // only follow links in the root node_modules folder, because if those - // folders are included, it's because they're bundled, and bundles - // should include the contents, not the symlinks themselves. - // This regexp tests to see that we're either a node_modules folder, - // or a @scope within a node_modules folder, in the root's node_modules - // hierarchy (ie, not in test/foo/node_modules/ or something). - const followRe = /^(?:\/node_modules\/(?:@[^/]+\/[^/]+|[^/]+)\/)*\/node_modules(?:\/@[^/]+)?$/ - const rootPath = opt.parent ? opt.parent.root : opt.path - const followTestPath = opt.path.replace(/\\/g, '/').slice(rootPath.length) - opt.follow = followRe.test(followTestPath) - - super(opt) - - // ignore a bunch of things by default at the root level. - // also ignore anything in the main project node_modules hierarchy, - // except bundled dependencies - if (this.isProject) { - this.bundled = opt.bundled || [] - this.bundledScopes = Array.from(new Set( - this.bundled.filter(f => /^@/.test(f)) - .map(f => f.split('/')[0]))) - this.packageJsonCache = this.parent ? this.parent.packageJsonCache - : (opt.packageJsonCache || new Map()) - let rules = defaultRules.join('\n') + '\n' - - if (opt.prefix && opt.workspaces) { - const gPath = globify(opt.path) - const gPrefix = globify(opt.prefix) - const gWorkspaces = opt.workspaces.map((ws) => globify(ws)) - // if opt.path and opt.prefix are not the same directory, and opt.workspaces has opt.path - // in it, then we know that opt.path is a workspace directory. in order to not drop ignore - // rules from directories between the workspace root (opt.prefix) and the workspace itself - // (opt.path), we need to find and read those now - /* istanbul ignore else */ - if (gPath !== gPrefix && gWorkspaces.includes(gPath)) { - // relpath is the relative path between the prefix and the parent of opt.path - // we use the parent because ignore-walk will read the files in opt.path already - const relpath = path.relative(opt.prefix, path.dirname(opt.path)) - rules += readOutOfTreeIgnoreFiles(opt.prefix, relpath) - } else if (gPath === gPrefix) { - // on the other hand, if the path and the prefix are the same, then we ignore workspaces - // so that we don't pack workspaces inside of a root project - rules += opt.workspaces.map((ws) => globify(path.relative(opt.path, ws))).join('\n') - } +const readOutOfTreeIgnoreFiles = (root, rel, result = []) => { + for (const file of ['.npmignore', '.gitignore']) { + try { + const ignoreContent = readFile(join(root, file), { encoding: 'utf8' }) + result.push(ignoreContent) + // break the loop immediately after reading, this allows us to prioritize + // the .npmignore and discard the .gitignore if one is present + break + } catch (err) { + // we ignore ENOENT errors completely because we don't care if the file doesn't exist + // but we throw everything else because failing to read a file that does exist is + // something that the user likely wants to know about + // istanbul ignore next -- we do not need to test a thrown error + if (err.code !== 'ENOENT') { + throw err } - - super.onReadIgnoreFile(rootBuiltinRules, rules, _ => _) - } else { - this.bundled = [] - this.bundledScopes = [] - this.packageJsonCache = this.parent.packageJsonCache } } - get isProject () { - return !this.parent || this.parent.follow && this.isSymbolicLink + if (!rel) { + return result } - onReaddir (entries) { - if (this.isProject) { - entries = entries.filter(e => - e !== '.git' && - !(e === 'node_modules' && this.bundled.length === 0) - ) - } - - // if we have a package.json, then look in it for 'files' - // we _only_ do this in the root project, not bundled deps - // or other random folders. Bundled deps are always assumed - // to be in the state the user wants to include them, and - // a package.json somewhere else might be a template or - // test or something else entirely. - if (!this.isProject || !entries.includes('package.json')) { - return super.onReaddir(entries) - } + const firstRel = rel.split(sep, 1)[0] + const newRoot = join(root, firstRel) + const newRel = relative(newRoot, join(root, rel)) - // when the cache has been seeded with the root manifest, - // we must respect that (it may differ from the filesystem) - const ig = path.resolve(this.path, 'package.json') + return readOutOfTreeIgnoreFiles(newRoot, newRel, result) +} - if (this.packageJsonCache.has(ig)) { - const pkg = this.packageJsonCache.get(ig) +class PackWalker extends IgnoreWalker { + constructor (tree, opts) { + const options = { + ...opts, + includeEmpty: false, + follow: false, + // we path.resolve() here because ignore-walk doesn't do it and we want full paths + path: resolve(opts?.path || tree.path).replace(/\\/g, '/'), + ignoreFiles: opts?.ignoreFiles || [ + defaultRules, + 'package.json', + '.npmignore', + '.gitignore', + strictRules, + ], + } - // fall back to filesystem when seeded manifest is invalid - if (!pkg || typeof pkg !== 'object') { - return this.readPackageJson(entries) + super(options) + this.isPackage = options.isPackage + this.seen = options.seen || new Set() + this.tree = tree + this.requiredFiles = options.requiredFiles || [] + + const additionalDefaults = [] + if (options.prefix && options.workspaces) { + const path = normalizePath(options.path) + const prefix = normalizePath(options.prefix) + const workspaces = options.workspaces.map((ws) => normalizePath(ws)) + + // istanbul ignore else - this does nothing unless we need it to + if (path !== prefix && workspaces.includes(path)) { + // if path and prefix are not the same directory, and workspaces has path in it + // then we know path is a workspace directory. in order to not drop ignore rules + // from directories between the workspaces root (prefix) and the workspace itself + // (path) we need to find and read those now + const relpath = relative(options.prefix, dirname(options.path)) + additionalDefaults.push(...readOutOfTreeIgnoreFiles(options.prefix, relpath)) + } else if (path === prefix) { + // on the other hand, if the path and prefix are the same, then we ignore workspaces + // so that we don't pack a workspace as part of the root project. append them as + // normalized relative paths from the root + additionalDefaults.push(...workspaces.map((w) => normalizePath(relative(options.path, w)))) } - - // feels wonky, but this ensures package bin is _always_ - // normalized, as well as guarding against invalid JSON - return this.getPackageFiles(entries, JSON.stringify(pkg)) } - this.readPackageJson(entries) - } + // go ahead and inject the default rules now + this.injectRules(defaultRules, [...defaults, ...additionalDefaults]) - onReadPackageJson (entries, er, pkg) { - if (er) { - this.emit('error', er) - } else { - this.getPackageFiles(entries, pkg) + if (!this.isPackage) { + // if this instance is not a package, then place some strict default rules, and append + // known required files for this directory + this.injectRules(strictRules, [ + ...strictDefaults, + ...this.requiredFiles.map((file) => `!${file}`), + ]) } } - mustHaveFilesFromPackage (pkg) { - const files = [] - if (pkg.browser) { - files.push('/' + pkg.browser) - } - if (pkg.main) { - files.push('/' + pkg.main) + // overridden method: we intercept the reading of the package.json file here so that we can + // process it into both the package.json file rules as well as the strictRules synthetic rule set + addIgnoreFile (file, callback) { + // if we're adding anything other than package.json, then let ignore-walk handle it + if (file !== 'package.json' || !this.isPackage) { + return super.addIgnoreFile(file, callback) } - if (pkg.bin) { - // always an object because normalized already - for (const key in pkg.bin) { - files.push('/' + pkg.bin[key]) - } + + return this.processPackage(callback) + } + + // overridden method: if we're done, but we're a package, then we also need to evaluate bundles + // before we actually emit our done event + emit (ev, data) { + if (ev !== 'done' || !this.isPackage) { + return super.emit(ev, data) } - files.push( - '/package.json', - '/npm-shrinkwrap.json', - '!/package-lock.json', - packageMustHaves - ) - return files + + // we intentionally delay the done event while keeping the function sync here + // eslint-disable-next-line promise/catch-or-return, promise/always-return + this.gatherBundles().then(() => { + super.emit('done', this.result) + }) + return true } - getPackageFiles (entries, pkg) { - try { - // XXX this could be changed to use read-package-json-fast - // which handles the normalizing of bins for us, and simplifies - // the test for bundleDependencies and bundledDependencies later. - // HOWEVER if we do this, we need to be sure that we're careful - // about what we write back out since rpj-fast removes some fields - // that the user likely wants to keep. it also would add a second - // file read that we would want to optimize away. - pkg = normalizePackageBin(JSON.parse(pkg.toString())) - } catch (er) { - // not actually a valid package.json - return super.onReaddir(entries) + // overridden method: before actually filtering, we make sure that we've removed the rules for + // files that should no longer take effect due to our order of precedence + filterEntries () { + if (this.ignoreRules['package.json']) { + // package.json means no .npmignore or .gitignore + this.ignoreRules['.npmignore'] = null + this.ignoreRules['.gitignore'] = null + } else if (this.ignoreRules['.npmignore']) { + // .npmignore means no .gitignore + this.ignoreRules['.gitignore'] = null } - const ig = path.resolve(this.path, 'package.json') - this.packageJsonCache.set(ig, pkg) + return super.filterEntries() + } - // no files list, just return the normal readdir() result - if (!Array.isArray(pkg.files)) { - return super.onReaddir(entries) + // overridden method: we never want to include anything that isn't a file or directory + onstat (opts, callback) { + if (!opts.st.isFile() && !opts.st.isDirectory()) { + return callback() } - pkg.files.push(...this.mustHaveFilesFromPackage(pkg)) + return super.onstat(opts, callback) + } - // If the package has a files list, then it's unlikely to include - // node_modules, because why would you do that? but since we use - // the files list as the effective readdir result, that means it - // looks like we don't have a node_modules folder at all unless we - // include it here. - if ((pkg.bundleDependencies || pkg.bundledDependencies) && entries.includes('node_modules')) { - pkg.files.push('node_modules') + // overridden method: we want to refuse to pack files that are invalid, node-tar protects us from + // a lot of them but not all + stat (opts, callback) { + if (nameIsBadForWindows(opts.entry)) { + return callback() } - const patterns = Array.from(new Set(pkg.files)).reduce((set, pattern) => { - const excl = pattern.match(/^!+/) - if (excl) { - pattern = pattern.slice(excl[0].length) - } - // strip off any / or ./ from the start of the pattern. /foo => foo, ./foo => foo - pattern = pattern.replace(/^\.?\/+/, '') - // an odd number of ! means a negated pattern. !!foo ==> foo - const negate = excl && excl[0].length % 2 === 1 - set.push({ pattern, negate }) - return set - }, []) - - let n = patterns.length - const set = new Set() - const negates = new Set() - const results = [] - const then = (pattern, negate, er, fileList, i) => { - if (er) { - return this.emit('error', er) - } + return super.stat(opts, callback) + } - results[i] = { negate, fileList } - if (--n === 0) { - processResults(results) + // overridden method: this is called to create options for a child walker when we step + // in to a normal child directory (this will never be a bundle). the default method here + // copies the root's `ignoreFiles` value, but we don't want to respect package.json for + // subdirectories, so we override it with a list that intentionally omits package.json + walkerOpt (entry, opts) { + let ignoreFiles = null + + // however, if we have a tree, and we have workspaces, and the directory we're about + // to step into is a workspace, then we _do_ want to respect its package.json + if (this.tree.workspaces) { + const workspaceDirs = [...this.tree.workspaces.values()] + .map((dir) => dir.replace(/\\/g, '/')) + + const entryPath = join(this.path, entry).replace(/\\/g, '/') + if (workspaceDirs.includes(entryPath)) { + ignoreFiles = [ + defaultRules, + 'package.json', + '.npmignore', + '.gitignore', + strictRules, + ] } + } else { + ignoreFiles = [ + defaultRules, + '.npmignore', + '.gitignore', + strictRules, + ] } - const processResults = processed => { - for (const { negate, fileList } of processed) { - if (negate) { - fileList.forEach(f => { - f = f.replace(/\/+$/, '') - set.delete(f) - negates.add(f) - }) - } else { - fileList.forEach(f => { - f = f.replace(/\/+$/, '') - set.add(f) - negates.delete(f) - }) - } - } - const list = Array.from(set) - // replace the files array with our computed explicit set - pkg.files = list.concat(Array.from(negates).map(f => '!' + f)) - const rdResult = Array.from(new Set( - list.map(f => f.replace(/^\/+/, '')) - )) - super.onReaddir(rdResult) + return { + ...super.walkerOpt(entry, opts), + ignoreFiles, + // we map over our own requiredFiles and pass ones that are within this entry + requiredFiles: this.requiredFiles + .map((file) => { + if (relative(file, entry) === '..') { + return relative(entry, file).replace(/\\/g, '/') + } + return false + }) + .filter(Boolean), } + } - // maintain the index so that we process them in-order only once all - // are completed, otherwise the parallelism messes things up, since a - // glob like **/*.js will always be slower than a subsequent !foo.js - patterns.forEach(({ pattern, negate }, i) => - this.globFiles(pattern, (er, res) => then(pattern, negate, er, res, i))) + // overridden method: we want child walkers to be instances of this class, not ignore-walk + walker (entry, opts, callback) { + new PackWalker(this.tree, this.walkerOpt(entry, opts)).on('done', callback).start() } - filterEntry (entry, partial) { - // get the partial path from the root of the walk - const p = this.path.slice(this.root.length + 1) - const { isProject } = this - const pkg = isProject && pathHasPkg(entry) - ? pkgFromPath(entry) - : null - const rootNM = isProject && entry === 'node_modules' - const rootPJ = isProject && entry === 'package.json' - - return ( - // if we're in a bundled package, check with the parent. - /^node_modules($|\/)/i.test(p) && !this.isProject ? this.parent.filterEntry( - this.basename + '/' + entry, partial) - - // if package is bundled, all files included - // also include @scope dirs for bundled scoped deps - // they'll be ignored if no files end up in them. - // However, this only matters if we're in the root. - // node_modules folders elsewhere, like lib/node_modules, - // should be included normally unless ignored. - : pkg ? this.bundled.indexOf(pkg) !== -1 || - this.bundledScopes.indexOf(pkg) !== -1 - - // only walk top node_modules if we want to bundle something - : rootNM ? !!this.bundled.length - - // always include package.json at the root. - : rootPJ ? true - - // always include readmes etc in any included dir - : packageMustHavesRE.test(entry) ? true - - // npm-shrinkwrap and package.json always included in the root pkg - : isProject && (entry === 'npm-shrinkwrap.json' || entry === 'package.json') - ? true - - // package-lock never included - : isProject && entry === 'package-lock.json' ? false - - // otherwise, follow ignore-walk's logic - : super.filterEntry(entry, partial) - ) + // overridden method: we use a custom sort method to help compressibility + sort (a, b) { + // optimize for compressibility + // extname, then basename, then locale alphabetically + // https://twitter.com/isntitvacant/status/1131094910923231232 + const exta = extname(a).toLowerCase() + const extb = extname(b).toLowerCase() + const basea = basename(a).toLowerCase() + const baseb = basename(b).toLowerCase() + + return exta.localeCompare(extb, 'en') || + basea.localeCompare(baseb, 'en') || + a.localeCompare(b, 'en') } - filterEntries () { - if (this.ignoreRules['.npmignore']) { - this.ignoreRules['.gitignore'] = null - } - this.filterEntries = super.filterEntries - super.filterEntries() + // convenience method: this joins the given rules with newlines, appends a trailing newline, + // and calls the internal onReadIgnoreFile method + injectRules (filename, rules, callback = () => {}) { + this.onReadIgnoreFile(filename, `${rules.join('\n')}\n`, callback) } - addIgnoreFile (file, then) { - const ig = path.resolve(this.path, file) - if (file === 'package.json' && !this.isProject) { - then() - } else if (this.packageJsonCache.has(ig)) { - this.onPackageJson(ig, this.packageJsonCache.get(ig), then) - } else { - super.addIgnoreFile(file, then) + // custom method: this is called by addIgnoreFile when we find a package.json, it uses the + // arborist tree to pull both default rules and strict rules for the package + processPackage (callback) { + const { + bin, + browser, + files, + main, + } = this.tree.package + + // rules in these arrays are inverted since they are patterns we want to _not_ ignore + const ignores = [] + const strict = [ + ...strictDefaults, + '!/package.json', + '!/npm-shrinkwrap.json', + '/.git', + '/node_modules', + '/package-lock.json', + '/yarn.lock', + '/pnpm-lock.yaml', + ] + + // if we have a files array in our package, we need to pull rules from it + if (files) { + for (const file of files) { + // invert the rule because these are things we want to include + const inverse = `!${file}` + try { + // if an entry in the files array is a specific file, then we need to include it as a + // strict requirement for this package. if it's a directory or a pattern, it's a default + // pattern instead. this is ugly, but we have to stat to find out if it's a file + const stat = lstat(join(this.path, file.replace(/^!+/, '')).replace(/\\/g, '/')) + // if we have a file and we know that, it's strictly required + if (stat.isFile()) { + strict.unshift(inverse) + this.requiredFiles.push(file.startsWith('/') ? file.slice(1) : file) + } else if (stat.isDirectory()) { + // otherwise, it's a default ignore, and since we got here we know it's not a pattern + // so we include the directory contents + ignores.push(inverse) + ignores.push(`${inverse}/**`) + } + // if the thing exists, but is neither a file or a directory, we don't want it at all + } catch (err) { + // if lstat throws, then we assume we're looking at a pattern and treat it as a default + ignores.push(inverse) + } + } + + // we prepend a '*' to exclude everything, followed by our inverted file rules + // which now mean to include those + this.injectRules('package.json', ['*', ...ignores]) } - } - onPackageJson (ig, pkg, then) { - this.packageJsonCache.set(ig, pkg) + // browser is required + if (browser) { + strict.push(`!/${browser}`) + } - if (Array.isArray(pkg.files)) { - // in this case we already included all the must-haves - super.onReadIgnoreFile('package.json', pkg.files.map( - f => '!' + f - ).join('\n') + '\n', then) - } else { - // if there's a bin, browser or main, make sure we don't ignore it - // also, don't ignore the package.json itself, or any files that - // must be included in the package. - const rules = this.mustHaveFilesFromPackage(pkg).map(f => `!${f}`) - const data = rules.join('\n') + '\n' - super.onReadIgnoreFile(packageNecessaryRules, data, then) + // main is required + if (main) { + strict.push(`!/${main}`) } - } - // override parent stat function to completely skip any filenames - // that will break windows entirely. - // XXX(isaacs) Next major version should make this an error instead. - stat ({ entry, file, dir }, then) { - if (nameIsBadForWindows(entry)) { - then() - } else { - super.stat({ entry, file, dir }, then) + // each bin is required + if (bin) { + for (const key in bin) { + strict.push(`!/${bin[key]}`) + } } + + // and now we add all of the strict rules to our synthetic file + this.injectRules(strictRules, strict, callback) } - // override parent onstat function to nix all symlinks, other than - // those coming out of the followed bundled symlink deps - onstat ({ st, entry, file, dir, isSymbolicLink }, then) { - if (st.isSymbolicLink()) { - then() - } else { - super.onstat({ st, entry, file, dir, isSymbolicLink }, then) + // custom method: after we've finished gathering the files for the root package, we call this + // before emitting the 'done' event in order to gather all of the files for bundled deps + async gatherBundles () { + if (this.seen.has(this.tree)) { + return } - } - onReadIgnoreFile (file, data, then) { - if (file === 'package.json') { - try { - const ig = path.resolve(this.path, file) - this.onPackageJson(ig, JSON.parse(data), then) - } catch (er) { - // ignore package.json files that are not json - then() - } + // add this node to our seen tracker + this.seen.add(this.tree) + + // if we're the project root, then we look at our bundleDependencies, otherwise we got here + // because we're a bundled dependency of the root, which means we need to include all prod + // and optional dependencies in the bundle + let toBundle + if (this.tree.isProjectRoot) { + const { bundleDependencies } = this.tree.package + toBundle = bundleDependencies || [] } else { - super.onReadIgnoreFile(file, data, then) + const { dependencies, optionalDependencies } = this.tree.package + toBundle = Object.keys(dependencies || {}).concat(Object.keys(optionalDependencies || {})) } - } - sort (a, b) { - // optimize for compressibility - // extname, then basename, then locale alphabetically - // https://twitter.com/isntitvacant/status/1131094910923231232 - const exta = path.extname(a).toLowerCase() - const extb = path.extname(b).toLowerCase() - const basea = path.basename(a).toLowerCase() - const baseb = path.basename(b).toLowerCase() + for (const dep of toBundle) { + const edge = this.tree.edgesOut.get(dep) + // no edgeOut = missing node, so skip it. we can't pack it if it's not here + // we also refuse to pack peer dependencies and dev dependencies + if (!edge || edge.peer || edge.dev) { + continue + } - return exta.localeCompare(extb, 'en') || - basea.localeCompare(baseb, 'en') || - a.localeCompare(b, 'en') - } + // get a reference to the node we're bundling + const node = this.tree.edgesOut.get(dep).to + // we use node.path for the path because we want the location the node was linked to, + // not where it actually lives on disk + const path = node.path + // but link nodes don't have edgesOut, so we need to pass in the target of the node + // in order to make sure we correctly traverse its dependencies + const tree = node.target + + // and start building options to be passed to the walker for this package + const walkerOpts = { + path, + isPackage: true, + ignoreFiles: [], + seen: this.seen, // pass through seen so we can prevent infinite circular loops + } - globFiles (pattern, cb) { - glob(globify(pattern), { dot: true, cwd: this.path, nocase: true }, cb) - } + // if our node is a link, we apply defaultRules. we don't do this for regular bundled + // deps because their .npmignore and .gitignore files are excluded by default and may + // override defaults + if (node.isLink) { + walkerOpts.ignoreFiles.push(defaultRules) + } - readPackageJson (entries) { - fs.readFile(this.path + '/package.json', (er, pkg) => - this.onReadPackageJson(entries, er, pkg)) - } + // _all_ nodes will follow package.json rules from their package root + walkerOpts.ignoreFiles.push('package.json') + + // only link nodes will obey .npmignore or .gitignore + if (node.isLink) { + walkerOpts.ignoreFiles.push('.npmignore') + walkerOpts.ignoreFiles.push('.gitignore') + } - walker (entry, opt, then) { - new Walker(this.walkerOpt(entry, opt)).on('done', then).start() + // _all_ nodes follow strict rules + walkerOpts.ignoreFiles.push(strictRules) + + // create a walker for this dependency and gather its results + const walker = new PackWalker(tree, walkerOpts) + const bundled = await new Promise((pResolve, pReject) => { + walker.on('error', pReject) + walker.on('done', pResolve) + walker.start() + }) + + // now we make sure we have our paths correct from the root, and accumulate everything into + // our own result set to deduplicate + const relativeFrom = relative(this.root, walker.path) + for (const file of bundled) { + this.result.add(join(relativeFrom, file).replace(/\\/g, '/')) + } + } } } -const walk = (options, callback) => { - options = options || {} - const p = new Promise((resolve, reject) => { - const bw = new BundleWalker(options) - bw.on('done', bundled => { - options.bundled = bundled - options.packageJsonCache = bw.packageJsonCache - new Walker(options).on('done', resolve).on('error', reject).start() - }) - bw.start() +const walk = (tree, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + const p = new Promise((pResolve, pReject) => { + new PackWalker(tree, { ...options, isPackage: true }) + .on('done', pResolve).on('error', pReject).start() }) return callback ? p.then(res => callback(null, res), callback) : p } module.exports = walk -walk.Walker = Walker +walk.Walker = PackWalker diff --git a/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/LICENSE b/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/LICENSE deleted file mode 100644 index 19cec97b18468..0000000000000 --- a/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/LICENSE +++ /dev/null @@ -1,15 +0,0 @@ -The ISC License - -Copyright (c) npm, Inc. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/lib/index.js b/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/lib/index.js deleted file mode 100644 index d6f0a581b9e66..0000000000000 --- a/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/lib/index.js +++ /dev/null @@ -1,64 +0,0 @@ -// pass in a manifest with a 'bin' field here, and it'll turn it -// into a properly santized bin object -const { join, basename } = require('path') - -const normalize = pkg => - !pkg.bin ? removeBin(pkg) - : typeof pkg.bin === 'string' ? normalizeString(pkg) - : Array.isArray(pkg.bin) ? normalizeArray(pkg) - : typeof pkg.bin === 'object' ? normalizeObject(pkg) - : removeBin(pkg) - -const normalizeString = pkg => { - if (!pkg.name) { - return removeBin(pkg) - } - pkg.bin = { [pkg.name]: pkg.bin } - return normalizeObject(pkg) -} - -const normalizeArray = pkg => { - pkg.bin = pkg.bin.reduce((acc, k) => { - acc[basename(k)] = k - return acc - }, {}) - return normalizeObject(pkg) -} - -const removeBin = pkg => { - delete pkg.bin - return pkg -} - -const normalizeObject = pkg => { - const orig = pkg.bin - const clean = {} - let hasBins = false - Object.keys(orig).forEach(binKey => { - const base = join('/', basename(binKey.replace(/\\|:/g, '/'))).slice(1) - - if (typeof orig[binKey] !== 'string' || !base) { - return - } - - const binTarget = join('/', orig[binKey]) - .replace(/\\/g, '/').slice(1) - - if (!binTarget) { - return - } - - clean[base] = binTarget - hasBins = true - }) - - if (hasBins) { - pkg.bin = clean - } else { - delete pkg.bin - } - - return pkg -} - -module.exports = normalize diff --git a/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/package.json b/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/package.json deleted file mode 100644 index 02de808d9b702..0000000000000 --- a/node_modules/npm-packlist/node_modules/npm-normalize-package-bin/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "npm-normalize-package-bin", - "version": "2.0.0", - "description": "Turn any flavor of allowable package.json bin into a normalized object", - "main": "lib/index.js", - "repository": { - "type": "git", - "url": "https://github.com/npm/npm-normalize-package-bin.git" - }, - "author": "GitHub Inc.", - "license": "ISC", - "scripts": { - "test": "tap", - "snap": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "postpublish": "git push origin --follow-tags", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "template-oss-apply": "template-oss-apply --force", - "lintfix": "npm run lint -- --fix", - "prepublishOnly": "git push origin --follow-tags", - "posttest": "npm run lint" - }, - "devDependencies": { - "@npmcli/eslint-config": "^3.1.0", - "@npmcli/template-oss": "3.5.0", - "tap": "^16.3.0" - }, - "files": [ - "bin/", - "lib/" - ], - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "templateOSS": { - "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0" - } -} diff --git a/node_modules/npm-packlist/package.json b/node_modules/npm-packlist/package.json index c3c8817202a39..4aaa524bf76a7 100644 --- a/node_modules/npm-packlist/package.json +++ b/node_modules/npm-packlist/package.json @@ -1,16 +1,13 @@ { "name": "npm-packlist", - "version": "5.1.3", + "version": "7.0.0-pre.0", "description": "Get a list of the files to add from a folder into an npm package", "directories": { "test": "test" }, - "main": "lib", + "main": "lib/index.js", "dependencies": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^2.0.0", - "npm-normalize-package-bin": "^2.0.0" + "ignore-walk": "^5.0.1" }, "author": "GitHub Inc.", "license": "ISC", @@ -19,8 +16,9 @@ "lib/" ], "devDependencies": { + "@npmcli/arborist": "^6.0.0 || ^6.0.0-pre.0", "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.6.0", + "@npmcli/template-oss": "4.4.2", "mutate-fs": "^2.1.1", "tap": "^16.0.1" }, @@ -29,9 +27,6 @@ "posttest": "npm run lint", "snap": "tap", "postsnap": "npm run lintfix --", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "eslint": "eslint", "lint": "eslint \"**/*.js\"", "lintfix": "npm run lint -- --fix", @@ -46,16 +41,20 @@ "tap": { "test-env": [ "LC_ALL=sk" + ], + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ], + "files": [ + "test/*.js" ] }, - "bin": { - "npm-packlist": "bin/index.js" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.6.0" + "version": "4.4.2" } } diff --git a/node_modules/pacote/lib/dir.js b/node_modules/pacote/lib/dir.js index 502379810a006..df04cd08c51e5 100644 --- a/node_modules/pacote/lib/dir.js +++ b/node_modules/pacote/lib/dir.js @@ -16,6 +16,9 @@ class DirFetcher extends Fetcher { super(spec, opts) // just the fully resolved filename this.resolved = this.spec.fetchSpec + + this.tree = opts.tree || null + this.Arborist = opts.Arborist || null } // exposes tarCreateOptions as public API @@ -59,6 +62,10 @@ class DirFetcher extends Fetcher { } [_tarballFromResolved] () { + if (!this.tree && !this.Arborist) { + throw new Error('DirFetcher requires either a tree or an Arborist constructor to pack') + } + const stream = new Minipass() stream.resolved = this.resolved stream.integrity = this.integrity @@ -68,7 +75,13 @@ class DirFetcher extends Fetcher { // run the prepare script, get the list of files, and tar it up // pipe to the stream, and proxy errors the chain. this[_prepareDir]() - .then(() => packlist({ path: this.resolved, prefix, workspaces })) + .then(async () => { + if (!this.tree) { + const arb = new this.Arborist({ path: this.resolved }) + this.tree = await arb.loadActual() + } + return packlist(this.tree, { path: this.resolved, prefix, workspaces }) + }) .then(files => tar.c(tarCreateOptions(this.package), files) .on('error', er => stream.emit('error', er)).pipe(stream)) .catch(er => stream.emit('error', er)) diff --git a/node_modules/pacote/lib/git.js b/node_modules/pacote/lib/git.js index c4819b4fdf49c..1fa8b1f966334 100644 --- a/node_modules/pacote/lib/git.js +++ b/node_modules/pacote/lib/git.js @@ -61,6 +61,8 @@ class GitFetcher extends Fetcher { } else { this.resolvedSha = '' } + + this.Arborist = opts.Arborist || null } // just exposed to make it easier to test all the combinations @@ -206,8 +208,12 @@ class GitFetcher extends Fetcher { // check it out and then shell out to the DirFetcher tarball packer this[_clone](dir => this[_prepareDir](dir) .then(() => new Promise((res, rej) => { + if (!this.Arborist) { + throw new Error('GitFetcher requires an Arborist constructor to pack a tarball') + } const df = new DirFetcher(`file:${dir}`, { ...this.opts, + Arborist: this.Arborist, resolved: null, integrity: null, }) diff --git a/node_modules/pacote/lib/registry.js b/node_modules/pacote/lib/registry.js index c8eb6b0290702..eeb22e93c33d6 100644 --- a/node_modules/pacote/lib/registry.js +++ b/node_modules/pacote/lib/registry.js @@ -97,7 +97,6 @@ class RegistryFetcher extends Fetcher { integrity: null, }) const packument = await res.json() - packument._cached = res.headers.has('x-local-cache') packument._contentLength = +res.headers.get('content-length') if (this.packumentCache) { this.packumentCache.set(this.packumentUrl, packument) diff --git a/node_modules/pacote/package.json b/node_modules/pacote/package.json index 960530ec0b33d..f9b796d86cd20 100644 --- a/node_modules/pacote/package.json +++ b/node_modules/pacote/package.json @@ -1,6 +1,6 @@ { "name": "pacote", - "version": "13.6.2", + "version": "14.0.0-pre.3", "description": "JavaScript package downloader", "author": "GitHub Inc.", "bin": { @@ -11,9 +11,6 @@ "scripts": { "test": "tap", "snap": "tap", - "preversion": "npm test", - "postversion": "npm publish", - "prepublishOnly": "git push origin --follow-tags", "lint": "eslint \"**/*.js\"", "postlint": "template-oss-check", "lintfix": "npm run lint -- --fix", @@ -21,11 +18,16 @@ "template-oss-apply": "template-oss-apply --force" }, "tap": { - "timeout": 300 + "timeout": 300, + "nyc-arg": [ + "--exclude", + "tap-snapshots/**" + ] }, "devDependencies": { - "@npmcli/eslint-config": "^3.0.1", - "@npmcli/template-oss": "3.5.0", + "@npmcli/arborist": "^6.0.0 || ^6.0.0-pre.0", + "@npmcli/eslint-config": "^3.1.0", + "@npmcli/template-oss": "4.4.2", "hosted-git-info": "^5.0.0", "mutate-fs": "^2.1.1", "nock": "^13.2.4", @@ -53,7 +55,7 @@ "minipass": "^3.1.6", "mkdirp": "^1.0.4", "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", + "npm-packlist": "^7.0.0 || ^7.0.0-pre.0", "npm-pick-manifest": "^7.0.0", "npm-registry-fetch": "^13.0.1", "proc-log": "^2.0.0", @@ -65,7 +67,7 @@ "tar": "^6.1.11" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "repository": { "type": "git", @@ -73,7 +75,7 @@ }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.", - "version": "3.5.0", + "version": "4.4.2", "windowsCI": false } } diff --git a/package-lock.json b/package-lock.json index 2441009d92e20..e455502bd7466 100644 --- a/package-lock.json +++ b/package-lock.json @@ -143,7 +143,7 @@ "npmlog": "^6.0.2", "opener": "^1.5.2", "p-map": "^4.0.0", - "pacote": "^13.6.2", + "pacote": "^14.0.0-pre.3", "parse-conflict-json": "^2.0.2", "proc-log": "^2.0.1", "qrcode-terminal": "^0.12.0", @@ -2269,17 +2269,17 @@ } }, "node_modules/@npmcli/metavuln-calculator": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz", - "integrity": "sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA==", + "version": "4.0.0-pre.0", + "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-4.0.0-pre.0.tgz", + "integrity": "sha512-2rJ7hovlcZMkqKm2cOWuZ0YsXIcP3iARsm+aYn/SLXK9aWRMVTW1f4fpDjtSvkZkaQVr48ofSG3YLYwlersSQA==", "dependencies": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", + "pacote": "^14.0.0 || ^14.0.0-pre.0", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@npmcli/move-file": { @@ -7966,27 +7966,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/npm-bundled": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", - "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", - "inBundle": true, - "dependencies": { - "npm-normalize-package-bin": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "inBundle": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/npm-install-checks": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", @@ -8025,30 +8004,15 @@ } }, "node_modules/npm-packlist": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", - "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "version": "7.0.0-pre.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.0-pre.0.tgz", + "integrity": "sha512-m98nCdY9RDDSJAODMf9afFwUyyuSO7rl1b8vvKRJD6s/isdTlOEgfdxJP4Pj31l973GNDe1n41e07QGPSIBQSw==", "inBundle": true, "dependencies": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^2.0.0", - "npm-normalize-package-bin": "^2.0.0" - }, - "bin": { - "npm-packlist": "bin/index.js" + "ignore-walk": "^5.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", - "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "inBundle": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-pick-manifest": { @@ -8587,9 +8551,9 @@ } }, "node_modules/pacote": { - "version": "13.6.2", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.2.tgz", - "integrity": "sha512-Gu8fU3GsvOPkak2CkbojR7vjs3k3P9cA6uazKTHdsdV0gpCEQq2opelnEv30KRQWgVzP5Vd/5umjcedma3MKtg==", + "version": "14.0.0-pre.3", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-14.0.0-pre.3.tgz", + "integrity": "sha512-WS8jos9mKpG6yRdMacwBc5WPEE4Z4xyJqyYiBoEU/0ayFlEPL8M8LUXlg86zjMWVpPobWIOIHvDO2i5oxOpIgQ==", "inBundle": true, "dependencies": { "@npmcli/git": "^3.0.0", @@ -8603,7 +8567,7 @@ "minipass": "^3.1.6", "mkdirp": "^1.0.4", "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", + "npm-packlist": "^7.0.0 || ^7.0.0-pre.0", "npm-pick-manifest": "^7.0.0", "npm-registry-fetch": "^13.0.1", "proc-log": "^2.0.0", @@ -8618,7 +8582,7 @@ "pacote": "lib/bin.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/parent-module": { @@ -13870,7 +13834,7 @@ "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", + "@npmcli/metavuln-calculator": "^4.0.0-pre.0", "@npmcli/move-file": "^2.0.0", "@npmcli/name-from-folder": "^1.0.1", "@npmcli/node-gyp": "^2.0.0", @@ -13891,7 +13855,7 @@ "npm-pick-manifest": "^7.0.2", "npm-registry-fetch": "^13.0.0", "npmlog": "^6.0.2", - "pacote": "^13.6.1", + "pacote": "^14.0.0-pre.3", "parse-conflict-json": "^2.0.1", "proc-log": "^2.0.0", "promise-all-reject-late": "^1.0.0", @@ -13942,13 +13906,14 @@ "version": "5.0.0-pre.0", "license": "ISC", "dependencies": { + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", "diff": "^5.1.0", "minimatch": "^5.0.1", "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1", + "pacote": "^14.0.0-pre.3", "tar": "^6.1.0" }, "devDependencies": { @@ -13972,7 +13937,7 @@ "mkdirp-infer-owner": "^2.0.0", "npm-package-arg": "^9.0.1", "npmlog": "^6.0.2", - "pacote": "^13.6.1", + "pacote": "^14.0.0-pre.3", "proc-log": "^2.0.0", "read": "^1.0.7", "read-package-json-fast": "^2.0.2", @@ -14045,9 +14010,10 @@ "version": "5.0.0-pre.0", "license": "ISC", "dependencies": { + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1" + "pacote": "^14.0.0-pre.3" }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", diff --git a/package.json b/package.json index 250f519e11994..a457bf5ed3aa2 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "npmlog": "^6.0.2", "opener": "^1.5.2", "p-map": "^4.0.0", - "pacote": "^13.6.2", + "pacote": "^14.0.0-pre.3", "parse-conflict-json": "^2.0.2", "proc-log": "^2.0.1", "qrcode-terminal": "^0.12.0", diff --git a/tap-snapshots/test/lib/utils/tar.js.test.cjs b/tap-snapshots/test/lib/utils/tar.js.test.cjs index d132d7af6e6f9..e4af36aeae0b6 100644 --- a/tap-snapshots/test/lib/utils/tar.js.test.cjs +++ b/tap-snapshots/test/lib/utils/tar.js.test.cjs @@ -11,10 +11,10 @@ exports[`test/lib/utils/tar.js TAP should log tarball contents > must match snap package: my-cool-pkg@1.0.0 === Tarball Contents === -4B cat -4B chai -4B dog -97B package.json +4B cat +4B chai +4B dog +114B package.json === Bundled Dependencies === bundle-dep @@ -23,10 +23,10 @@ bundle-dep name: my-cool-pkg version: 1.0.0 filename: my-cool-pkg-1.0.0.tgz -package size: 274 B -unpacked size: 113 B -shasum: cd0dfccff77dff944eb761854bc0b0497d974f67 -integrity: sha512-qeFip1jH05vkW[...]zHSdMdPpYogMA== +package size: 271 B +unpacked size: 126 B +shasum: 23e31c8ad422f96301c07730e61ff403b10306f1 +integrity: sha512-/Lg5tEGQv5A5y[...]gq8T9D5+Wat1A== bundled deps: 1 bundled files: 0 own files: 5 diff --git a/test/fixtures/mock-registry.js b/test/fixtures/mock-registry.js index d978929b6b0d8..a39532958b338 100644 --- a/test/fixtures/mock-registry.js +++ b/test/fixtures/mock-registry.js @@ -5,6 +5,7 @@ * for tests against any registry data. */ const pacote = require('pacote') +const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') class MockRegistry { #tap @@ -250,7 +251,7 @@ class MockRegistry { async tarball ({ manifest, tarball }) { const nock = this.nock const dist = new URL(manifest.dist.tarball) - const tar = await pacote.tarball(tarball) + const tar = await pacote.tarball(tarball, { Arborist }) nock.get(dist.pathname).reply(200, tar) return nock } diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index 995abff88c2c1..00fba9ef218e0 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -2,6 +2,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const MockRegistry = require('../../fixtures/mock-registry.js') const pacote = require('pacote') +const Arborist = require('@npmcli/arborist') const path = require('path') const fs = require('@npmcli/fs') const npa = require('npm-package-arg') @@ -227,7 +228,7 @@ t.test('tarball', async t => { 'index.js': 'console.log("hello world"}', }, }) - const tarball = await pacote.tarball(home) + const tarball = await pacote.tarball(home, { Arborist }) const tarFilename = path.join(home, 'tarball.tgz') await fs.writeFile(tarFilename, tarball) const registry = new MockRegistry({ diff --git a/test/lib/utils/tar.js b/test/lib/utils/tar.js index adc5cb364997f..23f40703b5cf4 100644 --- a/test/lib/utils/tar.js +++ b/test/lib/utils/tar.js @@ -27,12 +27,17 @@ t.test('should log tarball contents', async (t) => { bundleDependencies: [ 'bundle-dep', ], - }, null, 2), + dependencies: { + 'bundle-dep': '1.0.0', + }, + }), cat: 'meow', chai: 'blub', dog: 'woof', node_modules: { - 'bundle-dep': 'toto', + 'bundle-dep': { + 'package.json': '', + }, }, }) diff --git a/workspaces/arborist/lib/arborist/build-ideal-tree.js b/workspaces/arborist/lib/arborist/build-ideal-tree.js index e9a8720d7322d..0260bd563ab2f 100644 --- a/workspaces/arborist/lib/arborist/build-ideal-tree.js +++ b/workspaces/arborist/lib/arborist/build-ideal-tree.js @@ -833,6 +833,7 @@ This is a one-time fix-up, please be patient... await cacache.tmp.withTmp(this.cache, opt, async path => { await pacote.extract(node.resolved, path, { ...opt, + Arborist, resolved: node.resolved, integrity: node.integrity, }) diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 0c9026f5e4d1e..4f9db7575d79b 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -676,6 +676,7 @@ module.exports = cls => class Reifier extends cls { }) await pacote.extract(res, node.path, { ...this.options, + Arborist: this.constructor, resolved: node.resolved, integrity: node.integrity, }) diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 8082cf820d2f2..243b9d4675017 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -6,7 +6,7 @@ "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", + "@npmcli/metavuln-calculator": "^4.0.0-pre.0", "@npmcli/move-file": "^2.0.0", "@npmcli/name-from-folder": "^1.0.1", "@npmcli/node-gyp": "^2.0.0", @@ -27,7 +27,7 @@ "npm-pick-manifest": "^7.0.2", "npm-registry-fetch": "^13.0.0", "npmlog": "^6.0.2", - "pacote": "^13.6.1", + "pacote": "^14.0.0-pre.3", "parse-conflict-json": "^2.0.1", "proc-log": "^2.0.0", "promise-all-reject-late": "^1.0.0", diff --git a/workspaces/arborist/test/fixtures/registry-mocks/fetch-lock-contents.js b/workspaces/arborist/test/fixtures/registry-mocks/fetch-lock-contents.js index 0f756f00bd657..5fb010c13bea2 100644 --- a/workspaces/arborist/test/fixtures/registry-mocks/fetch-lock-contents.js +++ b/workspaces/arborist/test/fixtures/registry-mocks/fetch-lock-contents.js @@ -1,5 +1,6 @@ // fetch all the deps and tarballs in a v2 lockfile const pacote = require('pacote') +const Arborist = require('../../index.js') const url = require('url') const mkdirp = require('mkdirp') const {dirname, resolve} = require('path') @@ -29,7 +30,7 @@ const main = async lock => { continue const path = url.parse(meta.resolved).pathname.replace(/^\/@?/, '') const tgzFile = resolve(dir, path) - await pacote.tarball.file(meta.resolved, tgzFile) + await pacote.tarball.file(meta.resolved, tgzFile, { Arborist }) } console.log('OK!') } diff --git a/workspaces/libnpmdiff/lib/tarball.js b/workspaces/libnpmdiff/lib/tarball.js index 4d01d69c9c413..930d624f2d5b6 100644 --- a/workspaces/libnpmdiff/lib/tarball.js +++ b/workspaces/libnpmdiff/lib/tarball.js @@ -1,5 +1,6 @@ const { relative } = require('path') +const Arborist = require('@npmcli/arborist') const npa = require('npm-package-arg') const pkgContents = require('@npmcli/installed-package-contents') const pacote = require('pacote') @@ -28,7 +29,10 @@ const tarball = (manifest, opts) => { return nodeModulesTarball(manifest, opts) } - return pacote.tarball(manifest._resolved, opts) + return pacote.tarball(manifest._resolved, { + ...opts, + Arborist, + }) } module.exports = tarball diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 6b3e12e4fc3fb..cb14dfa3116db 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -47,13 +47,14 @@ "tap": "^16.0.1" }, "dependencies": { + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", "diff": "^5.1.0", "minimatch": "^5.0.1", "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1", + "pacote": "^14.0.0-pre.3", "tar": "^6.1.0" }, "templateOSS": { diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 0f2dde78fcc23..2d4df8579047f 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -66,7 +66,7 @@ "mkdirp-infer-owner": "^2.0.0", "npm-package-arg": "^9.0.1", "npmlog": "^6.0.2", - "pacote": "^13.6.1", + "pacote": "^14.0.0-pre.3", "proc-log": "^2.0.0", "read": "^1.0.7", "read-package-json-fast": "^2.0.2", diff --git a/workspaces/libnpmpack/lib/index.js b/workspaces/libnpmpack/lib/index.js index dc9cfd2c4e781..93428b37cb269 100644 --- a/workspaces/libnpmpack/lib/index.js +++ b/workspaces/libnpmpack/lib/index.js @@ -5,6 +5,7 @@ const npa = require('npm-package-arg') const runScript = require('@npmcli/run-script') const path = require('path') const util = require('util') +const Arborist = require('@npmcli/arborist') const writeFile = util.promisify(require('fs').writeFile) module.exports = pack @@ -33,6 +34,7 @@ async function pack (spec = 'file:.', opts = {}) { // packs tarball const tarball = await pacote.tarball(manifest._resolved, { ...opts, + Arborist, integrity: manifest._integrity, }) diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 96c9589a8cad3..20dc024ae1e13 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -35,9 +35,10 @@ "bugs": "https://github.com/npm/libnpmpack/issues", "homepage": "https://npmjs.com/package/libnpmpack", "dependencies": { + "@npmcli/arborist": "^6.0.0-pre.2", "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1" + "pacote": "^14.0.0-pre.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" From 45e43f1e87b8811a382c153488c5ad626fc59fc0 Mon Sep 17 00:00:00 2001 From: Luke Karrys Date: Thu, 29 Sep 2022 10:02:02 -0700 Subject: [PATCH 39/40] chore(libnpmpack): add sleep to tests to reduce flakiness --- workspaces/libnpmpack/test/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workspaces/libnpmpack/test/index.js b/workspaces/libnpmpack/test/index.js index b8007efe0b69e..d9ec1d12a6628 100644 --- a/workspaces/libnpmpack/test/index.js +++ b/workspaces/libnpmpack/test/index.js @@ -37,8 +37,8 @@ t.test('writes tarball to file when dryRun === false', async t => { name: 'my-cool-pkg', version: '1.0.0', scripts: { - prepack: 'touch prepack', - postpack: 'touch postpack', + prepack: 'touch prepack && sleep 1', + postpack: 'sleep 1 && touch postpack', }, }, null, 2), }) From b3977743be36b49f43c13cf116044731ed16d960 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 Sep 2022 00:29:40 +0000 Subject: [PATCH 40/40] chore: release 9.0.0-pre.3 --- .release-please-manifest.json | 14 +++++----- CHANGELOG.md | 37 ++++++++++++++++++++++++++ package-lock.json | 38 +++++++++++++-------------- package.json | 14 +++++----- workspaces/arborist/CHANGELOG.md | 10 +++++++ workspaces/arborist/package.json | 2 +- workspaces/libnpmdiff/CHANGELOG.md | 14 ++++++++++ workspaces/libnpmdiff/package.json | 4 +-- workspaces/libnpmexec/CHANGELOG.md | 14 ++++++++++ workspaces/libnpmexec/package.json | 4 +-- workspaces/libnpmfund/CHANGELOG.md | 6 +++++ workspaces/libnpmfund/package.json | 4 +-- workspaces/libnpmpack/CHANGELOG.md | 14 ++++++++++ workspaces/libnpmpack/package.json | 4 +-- workspaces/libnpmpublish/CHANGELOG.md | 14 ++++++++++ workspaces/libnpmpublish/package.json | 4 +-- 16 files changed, 153 insertions(+), 44 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6a8d9b04e0f32..b36c4d29f6a2d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,14 +1,14 @@ { - ".": "9.0.0-pre.2", - "workspaces/arborist": "6.0.0-pre.2", + ".": "9.0.0-pre.3", + "workspaces/arborist": "6.0.0-pre.3", "workspaces/libnpmaccess": "7.0.0-pre.1", - "workspaces/libnpmdiff": "5.0.0-pre.0", - "workspaces/libnpmexec": "5.0.0-pre.2", - "workspaces/libnpmfund": "4.0.0-pre.2", + "workspaces/libnpmdiff": "5.0.0-pre.1", + "workspaces/libnpmexec": "5.0.0-pre.3", + "workspaces/libnpmfund": "4.0.0-pre.3", "workspaces/libnpmhook": "9.0.0-pre.0", "workspaces/libnpmorg": "5.0.0-pre.0", - "workspaces/libnpmpack": "5.0.0-pre.0", - "workspaces/libnpmpublish": "7.0.0-pre.0", + "workspaces/libnpmpack": "5.0.0-pre.1", + "workspaces/libnpmpublish": "7.0.0-pre.1", "workspaces/libnpmsearch": "6.0.0-pre.0", "workspaces/libnpmteam": "5.0.0-pre.0", "workspaces/libnpmversion": "4.0.0-pre.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index 689f7f19f8832..56800101dc402 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog +## [9.0.0-pre.3](https://github.com/npm/cli/compare/v9.0.0-pre.2...v9.0.0-pre.3) (2022-09-30) + +### ⚠️ BREAKING CHANGES + +* `npm pack` now follows a strict order of operations when applying ignore rules. If a files array is present in the package.json, then rules in .gitignore and .npmignore files from the root will be ignored. +* `--timing` file changes: + - When run with the `--timing` flag, `npm` now writes timing data to a + file alongside the debug log data, respecting the `logs-dir` option and + falling back to `/_logs/` dir, instead of directly inside the + cache directory. + - The timing file data is no longer newline delimited JSON, and instead + each run will create a uniquely named `-timing.json` file, with the + `` portion being the same as the debug log. + - Finally, the data inside the file now has three top level keys, + `metadata`, `timers, and `unfinishedTimers` instead of everything being + a top level key. + +### Features + +* [`3ae796d`](https://github.com/npm/cli/commit/3ae796d937bd36a5b1b9fd6e9e8473b4f2ddc32d) implement new `npm-packlist` behavior (@lukekarrys) +* [`e64d69a`](https://github.com/npm/cli/commit/e64d69aedecc0943425605b3a6dc68aec3ad93aa) [#5581](https://github.com/npm/cli/pull/5581) write eresolve error files to the logs directory (@lukekarrys) +* [`3445da0`](https://github.com/npm/cli/commit/3445da0138f9eed9d73d2b3f5f451fcc1fa2e3fe) timings are now written alongside debug log files (@lukekarrys) + +### Documentation + +* [`f0e7584`](https://github.com/npm/cli/commit/f0e758494698d9dd8a58d07bf71c87608c36869e) [#5601](https://github.com/npm/cli/pull/5601) update docs/logging for new --access default (@wraithgar) + +### Dependencies + +* [`bc21552`](https://github.com/npm/cli/commit/bc2155247d00b7a868c414f4bc86993069b035f9) [#5603](https://github.com/npm/cli/pull/5603) `npm-package-arg@9.1.2` +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.2...arborist-v6.0.0-pre.3): `@npmcli/arborist@6.0.0-pre.3` +* [Workspace](https://github.com/npm/cli/compare/libnpmdiff-v5.0.0-pre.0...libnpmdiff-v5.0.0-pre.1): `libnpmdiff@5.0.0-pre.1` +* [Workspace](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.2...libnpmexec-v5.0.0-pre.3): `libnpmexec@5.0.0-pre.3` +* [Workspace](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.2...libnpmfund-v4.0.0-pre.3): `libnpmfund@4.0.0-pre.3` +* [Workspace](https://github.com/npm/cli/compare/libnpmpack-v5.0.0-pre.0...libnpmpack-v5.0.0-pre.1): `libnpmpack@5.0.0-pre.1` +* [Workspace](https://github.com/npm/cli/compare/libnpmpublish-v7.0.0-pre.0...libnpmpublish-v7.0.0-pre.1): `libnpmpublish@7.0.0-pre.1` + ## [9.0.0-pre.2](https://github.com/npm/cli/compare/v9.0.0-pre.1...v9.0.0-pre.2) (2022-09-23) ### ⚠️ BREAKING CHANGES diff --git a/package-lock.json b/package-lock.json index e455502bd7466..4c8acfb869429 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "9.0.0-pre.2", + "version": "9.0.0-pre.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npm", - "version": "9.0.0-pre.2", + "version": "9.0.0-pre.3", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -91,7 +91,7 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/ci-detect": "^2.0.0", "@npmcli/config": "^4.2.1", "@npmcli/fs": "^2.1.0", @@ -115,13 +115,13 @@ "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^2.3.1", "libnpmaccess": "^7.0.0-pre.1", - "libnpmdiff": "^5.0.0-pre.0", - "libnpmexec": "^5.0.0-pre.2", - "libnpmfund": "^4.0.0-pre.2", + "libnpmdiff": "^5.0.0-pre.1", + "libnpmexec": "^5.0.0-pre.3", + "libnpmfund": "^4.0.0-pre.3", "libnpmhook": "^9.0.0-pre.0", "libnpmorg": "^5.0.0-pre.0", - "libnpmpack": "^5.0.0-pre.0", - "libnpmpublish": "^7.0.0-pre.0", + "libnpmpack": "^5.0.0-pre.1", + "libnpmpublish": "^7.0.0-pre.1", "libnpmsearch": "^6.0.0-pre.0", "libnpmteam": "^5.0.0-pre.0", "libnpmversion": "^4.0.0-pre.0", @@ -13828,7 +13828,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "6.0.0-pre.2", + "version": "6.0.0-pre.3", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -13903,10 +13903,10 @@ } }, "workspaces/libnpmdiff": { - "version": "5.0.0-pre.0", + "version": "5.0.0-pre.1", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", @@ -13926,10 +13926,10 @@ } }, "workspaces/libnpmexec": { - "version": "5.0.0-pre.2", + "version": "5.0.0-pre.3", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.2.0", @@ -13957,10 +13957,10 @@ } }, "workspaces/libnpmfund": { - "version": "4.0.0-pre.2", + "version": "4.0.0-pre.3", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2" + "@npmcli/arborist": "^6.0.0-pre.3" }, "devDependencies": { "@npmcli/eslint-config": "^3.1.0", @@ -14007,10 +14007,10 @@ } }, "workspaces/libnpmpack": { - "version": "5.0.0-pre.0", + "version": "5.0.0-pre.1", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", "pacote": "^14.0.0-pre.3" @@ -14026,7 +14026,7 @@ } }, "workspaces/libnpmpublish": { - "version": "7.0.0-pre.0", + "version": "7.0.0-pre.1", "license": "ISC", "dependencies": { "normalize-package-data": "^4.0.0", @@ -14038,7 +14038,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/template-oss": "4.4.1", - "libnpmpack": "^5.0.0-pre.0", + "libnpmpack": "^5.0.0-pre.1", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", "tap": "^16.0.1" diff --git a/package.json b/package.json index a457bf5ed3aa2..be4d7f26d00c5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "9.0.0-pre.2", + "version": "9.0.0-pre.3", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -56,7 +56,7 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/ci-detect": "^2.0.0", "@npmcli/config": "^4.2.1", "@npmcli/fs": "^2.1.0", @@ -80,13 +80,13 @@ "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^2.3.1", "libnpmaccess": "^7.0.0-pre.1", - "libnpmdiff": "^5.0.0-pre.0", - "libnpmexec": "^5.0.0-pre.2", - "libnpmfund": "^4.0.0-pre.2", + "libnpmdiff": "^5.0.0-pre.1", + "libnpmexec": "^5.0.0-pre.3", + "libnpmfund": "^4.0.0-pre.3", "libnpmhook": "^9.0.0-pre.0", "libnpmorg": "^5.0.0-pre.0", - "libnpmpack": "^5.0.0-pre.0", - "libnpmpublish": "^7.0.0-pre.0", + "libnpmpack": "^5.0.0-pre.1", + "libnpmpublish": "^7.0.0-pre.1", "libnpmsearch": "^6.0.0-pre.0", "libnpmteam": "^5.0.0-pre.0", "libnpmversion": "^4.0.0-pre.0", diff --git a/workspaces/arborist/CHANGELOG.md b/workspaces/arborist/CHANGELOG.md index cd8e412efb9e7..da71aab1a6487 100644 --- a/workspaces/arborist/CHANGELOG.md +++ b/workspaces/arborist/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [6.0.0-pre.3](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.2...arborist-v6.0.0-pre.3) (2022-09-30) + +### ⚠️ BREAKING CHANGES + +* `npm pack` now follows a strict order of operations when applying ignore rules. If a files array is present in the package.json, then rules in .gitignore and .npmignore files from the root will be ignored. + +### Features + +* [`3ae796d`](https://github.com/npm/cli/commit/3ae796d937bd36a5b1b9fd6e9e8473b4f2ddc32d) implement new `npm-packlist` behavior (@lukekarrys) + ## [6.0.0-pre.2](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.1...arborist-v6.0.0-pre.2) (2022-09-23) ### Features diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 243b9d4675017..33b0794a21910 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "6.0.0-pre.2", + "version": "6.0.0-pre.3", "description": "Manage node_modules trees", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", diff --git a/workspaces/libnpmdiff/CHANGELOG.md b/workspaces/libnpmdiff/CHANGELOG.md index 96a402f9179a1..46c76e3489791 100644 --- a/workspaces/libnpmdiff/CHANGELOG.md +++ b/workspaces/libnpmdiff/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [5.0.0-pre.1](https://github.com/npm/cli/compare/libnpmdiff-v5.0.0-pre.0...libnpmdiff-v5.0.0-pre.1) (2022-09-30) + +### ⚠️ BREAKING CHANGES + +* `npm pack` now follows a strict order of operations when applying ignore rules. If a files array is present in the package.json, then rules in .gitignore and .npmignore files from the root will be ignored. + +### Features + +* [`3ae796d`](https://github.com/npm/cli/commit/3ae796d937bd36a5b1b9fd6e9e8473b4f2ddc32d) implement new `npm-packlist` behavior (@lukekarrys) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.2...arborist-v6.0.0-pre.3): `@npmcli/arborist@6.0.0-pre.3` + ## [5.0.0-pre.0](https://github.com/npm/cli/compare/libnpmdiff-v4.0.5...libnpmdiff-v5.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index cb14dfa3116db..c933f590edfff 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -1,6 +1,6 @@ { "name": "libnpmdiff", - "version": "5.0.0-pre.0", + "version": "5.0.0-pre.1", "description": "The registry diff", "repository": { "type": "git", @@ -47,7 +47,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", "binary-extensions": "^2.2.0", diff --git a/workspaces/libnpmexec/CHANGELOG.md b/workspaces/libnpmexec/CHANGELOG.md index 972bf585f3cab..1bc75bde5d2e3 100644 --- a/workspaces/libnpmexec/CHANGELOG.md +++ b/workspaces/libnpmexec/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [5.0.0-pre.3](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.2...libnpmexec-v5.0.0-pre.3) (2022-09-30) + +### ⚠️ BREAKING CHANGES + +* `npm pack` now follows a strict order of operations when applying ignore rules. If a files array is present in the package.json, then rules in .gitignore and .npmignore files from the root will be ignored. + +### Features + +* [`3ae796d`](https://github.com/npm/cli/commit/3ae796d937bd36a5b1b9fd6e9e8473b4f2ddc32d) implement new `npm-packlist` behavior (@lukekarrys) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.2...arborist-v6.0.0-pre.3): `@npmcli/arborist@6.0.0-pre.3` + ## [5.0.0-pre.2](https://github.com/npm/cli/compare/libnpmexec-v5.0.0-pre.1...libnpmexec-v5.0.0-pre.2) (2022-09-23) ### Dependencies diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 2d4df8579047f..48bd5e0075645 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "5.0.0-pre.2", + "version": "5.0.0-pre.3", "files": [ "bin/", "lib/" @@ -58,7 +58,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^2.1.1", "@npmcli/run-script": "^4.2.0", diff --git a/workspaces/libnpmfund/CHANGELOG.md b/workspaces/libnpmfund/CHANGELOG.md index 440951a45b302..51f191203dcd7 100644 --- a/workspaces/libnpmfund/CHANGELOG.md +++ b/workspaces/libnpmfund/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.0.0-pre.3](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.2...libnpmfund-v4.0.0-pre.3) (2022-09-30) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.2...arborist-v6.0.0-pre.3): `@npmcli/arborist@6.0.0-pre.3` + ## [4.0.0-pre.2](https://github.com/npm/cli/compare/libnpmfund-v4.0.0-pre.1...libnpmfund-v4.0.0-pre.2) (2022-09-23) ### Dependencies diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 43a90df172d53..81deb03ac9188 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "4.0.0-pre.2", + "version": "4.0.0-pre.3", "main": "lib/index.js", "files": [ "bin/", @@ -46,7 +46,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2" + "@npmcli/arborist": "^6.0.0-pre.3" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/workspaces/libnpmpack/CHANGELOG.md b/workspaces/libnpmpack/CHANGELOG.md index b38e01146ddc8..72d52f802b852 100644 --- a/workspaces/libnpmpack/CHANGELOG.md +++ b/workspaces/libnpmpack/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [5.0.0-pre.1](https://github.com/npm/cli/compare/libnpmpack-v5.0.0-pre.0...libnpmpack-v5.0.0-pre.1) (2022-09-30) + +### ⚠️ BREAKING CHANGES + +* `npm pack` now follows a strict order of operations when applying ignore rules. If a files array is present in the package.json, then rules in .gitignore and .npmignore files from the root will be ignored. + +### Features + +* [`3ae796d`](https://github.com/npm/cli/commit/3ae796d937bd36a5b1b9fd6e9e8473b4f2ddc32d) implement new `npm-packlist` behavior (@lukekarrys) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.0.0-pre.2...arborist-v6.0.0-pre.3): `@npmcli/arborist@6.0.0-pre.3` + ## [5.0.0-pre.0](https://github.com/npm/cli/compare/libnpmpack-v4.1.3...libnpmpack-v5.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 20dc024ae1e13..aa0b27036bddd 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "5.0.0-pre.0", + "version": "5.0.0-pre.1", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", @@ -35,7 +35,7 @@ "bugs": "https://github.com/npm/libnpmpack/issues", "homepage": "https://npmjs.com/package/libnpmpack", "dependencies": { - "@npmcli/arborist": "^6.0.0-pre.2", + "@npmcli/arborist": "^6.0.0-pre.3", "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", "pacote": "^14.0.0-pre.3" diff --git a/workspaces/libnpmpublish/CHANGELOG.md b/workspaces/libnpmpublish/CHANGELOG.md index 2c69ced553573..cfc1f93dd8f85 100644 --- a/workspaces/libnpmpublish/CHANGELOG.md +++ b/workspaces/libnpmpublish/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [7.0.0-pre.1](https://github.com/npm/cli/compare/libnpmpublish-v7.0.0-pre.0...libnpmpublish-v7.0.0-pre.1) (2022-09-30) + +### ⚠️ BREAKING CHANGES + +* The default value of `access` is now `public` + +### Features + +* [`525654e`](https://github.com/npm/cli/commit/525654e957a80c7f47472e18240e3c8d94e0568f) default access to `public` (@wraithgar) + +### Documentation + +* [`f0e7584`](https://github.com/npm/cli/commit/f0e758494698d9dd8a58d07bf71c87608c36869e) [#5601](https://github.com/npm/cli/pull/5601) update docs/logging for new --access default (@wraithgar) + ## [7.0.0-pre.0](https://github.com/npm/cli/compare/libnpmpublish-v6.0.5...libnpmpublish-v7.0.0-pre.0) (2022-09-08) ### ⚠ BREAKING CHANGES diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index ea2fdc181d0c0..8bfa3baf69f60 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpublish", - "version": "7.0.0-pre.0", + "version": "7.0.0-pre.1", "description": "Programmatic API for the bits behind npm publish and unpublish", "author": "GitHub Inc.", "main": "lib/index.js", @@ -26,7 +26,7 @@ "devDependencies": { "@npmcli/eslint-config": "^3.1.0", "@npmcli/template-oss": "4.4.1", - "libnpmpack": "^5.0.0-pre.0", + "libnpmpack": "^5.0.0-pre.1", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", "tap": "^16.0.1"