diff --git a/.release-please-manifest.json b/.release-please-manifest.json index aa4f78d56cc5b..cc446834528f8 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,14 +1,14 @@ { - ".": "9.1.2", - "workspaces/arborist": "6.1.3", + ".": "9.1.3", + "workspaces/arborist": "6.1.4", "workspaces/libnpmaccess": "7.0.0", - "workspaces/libnpmdiff": "5.0.4", - "workspaces/libnpmexec": "5.0.4", - "workspaces/libnpmfund": "4.0.4", + "workspaces/libnpmdiff": "5.0.5", + "workspaces/libnpmexec": "5.0.5", + "workspaces/libnpmfund": "4.0.5", "workspaces/libnpmhook": "9.0.0", "workspaces/libnpmorg": "5.0.0", - "workspaces/libnpmpack": "5.0.4", - "workspaces/libnpmpublish": "7.0.4", + "workspaces/libnpmpack": "5.0.5", + "workspaces/libnpmpublish": "7.0.5", "workspaces/libnpmsearch": "6.0.0", "workspaces/libnpmteam": "5.0.0", "workspaces/libnpmversion": "4.0.1", diff --git a/AUTHORS b/AUTHORS index ecd8124735921..af0d5ed1a0c62 100644 --- a/AUTHORS +++ b/AUTHORS @@ -864,3 +864,6 @@ shalvah Albert 理斯特 Gennadiy Gashev <63790536+gennadiygashev@users.noreply.github.com> Andrew Dawes +sosoba +Aron +HenryNguyen5 <6404866+HenryNguyen5@users.noreply.github.com> diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d1970b4d0e9..bbdeaaef5f856 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [9.1.3](https://github.com/npm/cli/compare/v9.1.2...v9.1.3) (2022-11-30) + +### Bug Fixes + +* [`ffbdea2`](https://github.com/npm/cli/commit/ffbdea286a08eeaf40ab83eea5bfe0602dc6bbcd) [#5894](https://github.com/npm/cli/pull/5894) npm pack filename on scoped packages (#5894) (@HenryNguyen5) +* [`c26d708`](https://github.com/npm/cli/commit/c26d708428a96da530092759b5ff6d67c7282348) [#5884](https://github.com/npm/cli/pull/5884) validate username at get-identity (#5884) (@sosoba, @nlf) + +### Documentation + +* [`ea948dc`](https://github.com/npm/cli/commit/ea948dceac5cfeef437c97874ab26c3275e75766) [#5881](https://github.com/npm/cli/pull/5881) update description of npm exec (#5881) (@styfle, @wraithgar) +* [`40f2c21`](https://github.com/npm/cli/commit/40f2c213d75a252665311b4f8775d297390aeb70) [#5865](https://github.com/npm/cli/pull/5865) ci-info url (#5865) (@wraithgar) +* [`681a45b`](https://github.com/npm/cli/commit/681a45bb48acd57aa64cb3241ea4915f5a12e029) [#5875](https://github.com/npm/cli/pull/5875) run the comand for directory workspaces (#5875) (@1aron) +* [`681a45b`](https://github.com/npm/cli/commit/681a45bb48acd57aa64cb3241ea4915f5a12e029) [#5875](https://github.com/npm/cli/pull/5875) add workspace directory example (#5875) (@1aron) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.1.3...arborist-v6.1.4): `@npmcli/arborist@6.1.4` +* [Workspace](https://github.com/npm/cli/compare/libnpmdiff-v5.0.4...libnpmdiff-v5.0.5): `libnpmdiff@5.0.5` +* [Workspace](https://github.com/npm/cli/compare/libnpmexec-v5.0.4...libnpmexec-v5.0.5): `libnpmexec@5.0.5` +* [Workspace](https://github.com/npm/cli/compare/libnpmfund-v4.0.4...libnpmfund-v4.0.5): `libnpmfund@4.0.5` +* [Workspace](https://github.com/npm/cli/compare/libnpmpack-v5.0.4...libnpmpack-v5.0.5): `libnpmpack@5.0.5` +* [Workspace](https://github.com/npm/cli/compare/libnpmpublish-v7.0.4...libnpmpublish-v7.0.5): `libnpmpublish@7.0.5` + ## [9.1.2](https://github.com/npm/cli/compare/v9.1.1...v9.1.2) (2022-11-16) ### Bug Fixes diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index 2187275722624..734bd149750e9 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -33,6 +33,7 @@ graph LR; libnpmexec-->npm-package-arg; libnpmexec-->npmcli-arborist["@npmcli/arborist"]; libnpmexec-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmexec-->npmcli-mock-registry["@npmcli/mock-registry"]; libnpmexec-->npmcli-run-script["@npmcli/run-script"]; libnpmexec-->npmcli-template-oss["@npmcli/template-oss"]; libnpmexec-->npmlog; @@ -352,11 +353,14 @@ graph LR; libnpmexec-->bin-links; libnpmexec-->chalk; libnpmexec-->ci-info; + libnpmexec-->just-extend; + libnpmexec-->just-safe-set; libnpmexec-->minify-registry-metadata; libnpmexec-->mkdirp; libnpmexec-->npm-package-arg; libnpmexec-->npmcli-arborist["@npmcli/arborist"]; libnpmexec-->npmcli-eslint-config["@npmcli/eslint-config"]; + libnpmexec-->npmcli-mock-registry["@npmcli/mock-registry"]; libnpmexec-->npmcli-run-script["@npmcli/run-script"]; libnpmexec-->npmcli-template-oss["@npmcli/template-oss"]; libnpmexec-->npmlog; @@ -772,8 +776,8 @@ Each group depends on packages lower down the chain, nothing depends on packages higher up the chain. - npm - - @npmcli/smoke-tests, libnpmpublish - - @npmcli/mock-registry, libnpmdiff, libnpmexec, libnpmfund, libnpmpack + - @npmcli/smoke-tests, libnpmexec, libnpmpublish + - @npmcli/mock-registry, libnpmdiff, libnpmfund, libnpmpack - @npmcli/arborist - @npmcli/metavuln-calculator - pacote, libnpmaccess, libnpmhook, libnpmorg, libnpmsearch, libnpmteam, npm-profile diff --git a/docs/lib/content/commands/npm-exec.md b/docs/lib/content/commands/npm-exec.md index f156a9c8382ee..33fc1a08248ac 100644 --- a/docs/lib/content/commands/npm-exec.md +++ b/docs/lib/content/commands/npm-exec.md @@ -26,10 +26,11 @@ specified multiple times, to execute the supplied command in an environment where all specified packages are available. If any requested packages are not present in the local project -dependencies, then they are installed to a folder in the npm cache, which -is added to the `PATH` environment variable in the executed process. A -prompt is printed (which can be suppressed by providing either `--yes` or -`--no`). +dependencies, then a prompt is printed, which can be suppressed by +providing either `--yes` or `--no`. When standard input is not a TTY or a +CI environment is detected, `--yes` is assumed. The requested packages are +installed to a folder in the npm cache, which is added to the `PATH` +environment variable in the executed process. Package names provided without a specifier will be matched with whatever version exists in the local project. Package names with a specifier will diff --git a/docs/lib/content/using-npm/workspaces.md b/docs/lib/content/using-npm/workspaces.md index 5b68ef8ce9d3d..bbfa2d8817eb2 100644 --- a/docs/lib/content/using-npm/workspaces.md +++ b/docs/lib/content/using-npm/workspaces.md @@ -176,6 +176,11 @@ command-line in order to target multiple workspaces, e.g: npm run test --workspace=a --workspace=b ``` +Or run the command for each workspace within the 'packages' folder: +``` +npm run test --workspace=packages +``` + It's also possible to use the `workspaces` (plural) configuration option to enable the same behavior but running that command in the context of **all** configured workspaces. e.g: diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index f511b1badfe85..0f401d6572a59 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -441,7 +441,7 @@ define('ci-name', { description: ` The name of a continuous integration system. If not set explicitly, npm will detect the current CI environment using the - [\`ci-info\`](http://npm.im/@npmcli/ci-info) module. + [\`ci-info\`](http://npm.im/ci-info) module. `, flatten, }) diff --git a/lib/utils/get-identity.js b/lib/utils/get-identity.js index 41d882473ab7b..d8f59da14247a 100644 --- a/lib/utils/get-identity.js +++ b/lib/utils/get-identity.js @@ -12,7 +12,9 @@ module.exports = async (npm, opts) => { // No username, but we have other credentials; fetch the username from registry if (creds.token || creds.certfile && creds.keyfile) { const registryData = await npmFetch.json('/-/whoami', { ...opts }) - return registryData.username + if (typeof registryData?.username === 'string') { + return registryData.username + } } // At this point, even if they have a credentials object, it doesn't have a diff --git a/lib/utils/tar.js b/lib/utils/tar.js index 0a74ce8c44434..c25fe71614a60 100644 --- a/lib/utils/tar.js +++ b/lib/utils/tar.js @@ -120,7 +120,9 @@ const getContents = async (manifest, tarball) => { unpackedSize: totalEntrySize, shasum, integrity: ssri.parse(integrity.sha512[0]), - filename: `${manifest.name}-${manifest.version}.tgz`, + // @scope/packagename.tgz => scope-packagename.tgz + // we can safely use these global replace rules due to npm package naming rules + filename: `${manifest.name.replace('@', '').replace('/', '-')}-${manifest.version}.tgz`, files: uppers.concat(others), entryCount: totalEntries, bundled: Array.from(bundled), diff --git a/mock-registry/lib/index.js b/mock-registry/lib/index.js index 1652e3344f0a8..24666dde24a5d 100644 --- a/mock-registry/lib/index.js +++ b/mock-registry/lib/index.js @@ -10,6 +10,7 @@ class MockRegistry { #authorization #basic #debug + #strict constructor (opts) { if (!opts.registry) { @@ -19,20 +20,48 @@ class MockRegistry { this.#authorization = opts.authorization this.#basic = opts.basic this.#debug = opts.debug + this.#strict = opts.strict // Required for this.package this.#tap = opts.tap + if (this.#tap) { + this.startNock() + } } - static tnock (t, host, opts, { debug = false } = {}) { - if (debug) { - Nock.emitter.on('no match', req => console.error('NO MATCH', req.options)) + static tnock (t, host, opts, { debug = false, strict = false } = {}) { + const noMatch = (req) => { + if (strict) { + // There are network requests that get caught regardless of error code. + // Turning on strict mode requires that those requests get explicitly + // mocked with a 404, 500, etc. + // XXX: this is opt-in currently because it breaks some existing CLI + // tests. We should work towards making this the default for all tests. + t.fail(`Unmatched request: ${JSON.stringify(req.options, null, 2)}`) + } + if (debug) { + console.error('NO MATCH', t.name, req.options) + } } + + Nock.emitter.on('no match', noMatch) Nock.disableNetConnect() const server = Nock(host, opts) + + if (strict) { + // this requires that mocks not be shared between sub tests but it helps + // find mistakes quicker instead of waiting for the entire test to end + t.afterEach((t) => { + t.strictSame(server.pendingMocks(), [], 'no pending mocks after each') + t.strictSame(server.activeMocks(), [], 'no active mocks after each') + }) + } + t.teardown(() => { Nock.enableNetConnect() server.done() + Nock.emitter.off('no match', noMatch) }) + return server } @@ -41,24 +70,6 @@ class MockRegistry { } get nock () { - if (!this.#nock) { - if (!this.#tap) { - throw new Error('cannot mock packages without a tap fixture') - } - const reqheaders = {} - if (this.#authorization) { - reqheaders.authorization = `Bearer ${this.#authorization}` - } - if (this.#basic) { - reqheaders.authorization = `Basic ${this.#basic}` - } - this.#nock = MockRegistry.tnock( - this.#tap, - this.#registry, - { reqheaders }, - { debug: this.#debug } - ) - } return this.#nock } @@ -66,6 +77,31 @@ class MockRegistry { this.#nock = nock } + startNock () { + if (this.nock) { + return + } + + if (!this.#tap) { + throw new Error('cannot mock packages without a tap fixture') + } + + const reqheaders = {} + if (this.#authorization) { + reqheaders.authorization = `Bearer ${this.#authorization}` + } + if (this.#basic) { + reqheaders.authorization = `Basic ${this.#basic}` + } + + this.nock = MockRegistry.tnock( + this.#tap, + this.#registry, + { reqheaders }, + { debug: this.#debug, strict: this.#strict } + ) + } + search ({ responseCode = 200, results = [], error }) { // the flags, score, and searchScore parts of the response are never used // by npm, only package is used @@ -296,13 +332,14 @@ class MockRegistry { manifest.users = users } for (const packument of packuments) { + const unscoped = name.includes('/') ? name.split('/')[1] : name manifest.versions[packument.version] = { _id: `${name}@${packument.version}`, name, description: 'test package mock manifest', dependencies: {}, dist: { - tarball: `${this.#registry}/${name}/-/${name}-${packument.version}.tgz`, + tarball: `${this.#registry}/${name}/-/${unscoped}-${packument.version}.tgz`, }, maintainers: [], ...packument, diff --git a/package-lock.json b/package-lock.json index 350ea7a5b3afa..c76202a3efb4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm", - "version": "9.1.2", + "version": "9.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npm", - "version": "9.1.2", + "version": "9.1.3", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -86,7 +86,7 @@ ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/config": "^6.1.0", "@npmcli/map-workspaces": "^3.0.0", "@npmcli/package-json": "^3.0.0", @@ -109,13 +109,13 @@ "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.0", - "libnpmdiff": "^5.0.4", - "libnpmexec": "^5.0.4", - "libnpmfund": "^4.0.4", + "libnpmdiff": "^5.0.5", + "libnpmexec": "^5.0.5", + "libnpmfund": "^4.0.5", "libnpmhook": "^9.0.0", "libnpmorg": "^5.0.0", - "libnpmpack": "^5.0.4", - "libnpmpublish": "^7.0.4", + "libnpmpack": "^5.0.5", + "libnpmpublish": "^7.0.5", "libnpmsearch": "^6.0.0", "libnpmteam": "^5.0.0", "libnpmversion": "^4.0.1", @@ -14983,7 +14983,7 @@ }, "workspaces/arborist": { "name": "@npmcli/arborist", - "version": "6.1.3", + "version": "6.1.4", "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", @@ -15077,10 +15077,10 @@ } }, "workspaces/libnpmdiff": { - "version": "5.0.4", + "version": "5.0.5", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.0", "binary-extensions": "^2.2.0", @@ -15100,10 +15100,10 @@ } }, "workspaces/libnpmexec": { - "version": "5.0.4", + "version": "5.0.5", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/run-script": "^6.0.0", "chalk": "^4.1.0", "ci-info": "^3.6.1", @@ -15118,8 +15118,11 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.10.0", "bin-links": "^4.0.1", + "just-extend": "^6.1.1", + "just-safe-set": "^4.1.1", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", "tap": "^16.0.1" @@ -15129,10 +15132,10 @@ } }, "workspaces/libnpmfund": { - "version": "4.0.4", + "version": "4.0.5", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.1.3" + "@npmcli/arborist": "^6.1.4" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", @@ -15179,10 +15182,10 @@ } }, "workspaces/libnpmpack": { - "version": "5.0.4", + "version": "5.0.5", "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.0.0", "pacote": "^15.0.2" @@ -15199,7 +15202,7 @@ } }, "workspaces/libnpmpublish": { - "version": "7.0.4", + "version": "7.0.5", "license": "ISC", "dependencies": { "normalize-package-data": "^5.0.0", @@ -15211,7 +15214,7 @@ "devDependencies": { "@npmcli/eslint-config": "^4.0.0", "@npmcli/template-oss": "4.10.0", - "libnpmpack": "^5.0.4", + "libnpmpack": "^5.0.5", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", "tap": "^16.0.1" diff --git a/package.json b/package.json index 65042e523136a..b3ae1b9e00d73 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "9.1.2", + "version": "9.1.3", "name": "npm", "description": "a package manager for JavaScript", "workspaces": [ @@ -53,7 +53,7 @@ }, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/config": "^6.1.0", "@npmcli/map-workspaces": "^3.0.0", "@npmcli/package-json": "^3.0.0", @@ -76,13 +76,13 @@ "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.0", - "libnpmdiff": "^5.0.4", - "libnpmexec": "^5.0.4", - "libnpmfund": "^4.0.4", + "libnpmdiff": "^5.0.5", + "libnpmexec": "^5.0.5", + "libnpmfund": "^4.0.5", "libnpmhook": "^9.0.0", "libnpmorg": "^5.0.0", - "libnpmpack": "^5.0.4", - "libnpmpublish": "^7.0.4", + "libnpmpack": "^5.0.5", + "libnpmpublish": "^7.0.5", "libnpmsearch": "^6.0.0", "libnpmteam": "^5.0.0", "libnpmversion": "^4.0.1", diff --git a/smoke-tests/test/fixtures/setup.js b/smoke-tests/test/fixtures/setup.js index 4291006b435e0..003a2ee302e18 100644 --- a/smoke-tests/test/fixtures/setup.js +++ b/smoke-tests/test/fixtures/setup.js @@ -84,6 +84,7 @@ module.exports = async (t, { testdir = {}, debug } = {}) => { tap: t, registry: 'http://smoke-test-registry.club/', debug, + strict: true, }) const httpProxyRegistry = `http://localhost:${PORT}` const proxy = httpProxy.createProxyServer({}) @@ -92,12 +93,8 @@ module.exports = async (t, { testdir = {}, debug } = {}) => { t.teardown(() => server.close()) // update notifier should never be written - t.afterEach(async (t) => { + t.afterEach((t) => { t.equal(existsSync(join(paths.cache, '_update-notifier-last-checked')), false) - // this requires that mocks not be shared between sub tests but it helps - // find mistakes quicker instead of waiting for the entire test to end - t.strictSame(registry.nock.pendingMocks(), [], 'no pending mocks after each') - t.strictSame(registry.nock.activeMocks(), [], 'no active mocks after each') }) const debugLog = debug || CI ? (...a) => console.error(...a) : () => {} @@ -143,6 +140,7 @@ module.exports = async (t, { testdir = {}, debug } = {}) => { '--no-audit', '--no-update-notifier', '--loglevel=silly', + '--fetch-retries=0', ] const [positionals, flags] = args.reduce((acc, arg) => { if (arg.startsWith('-')) { diff --git a/smoke-tests/test/index.js b/smoke-tests/test/index.js index 4aafcb2cbd2e1..98f276be841b7 100644 --- a/smoke-tests/test/index.js +++ b/smoke-tests/test/index.js @@ -267,9 +267,6 @@ t.test('basic', async t => { const manifest = abbrevManifest() await registry.package({ manifest: manifest, - tarballs: { - '1.1.1': join(paths.root, 'packages', 'abbrev-1.1.1'), - }, }) await npm('update', '--no-save') diff --git a/tap-snapshots/test/lib/commands/pack.js.test.cjs b/tap-snapshots/test/lib/commands/pack.js.test.cjs index e3219b45ed54f..fdb64f990e9b8 100644 --- a/tap-snapshots/test/lib/commands/pack.js.test.cjs +++ b/tap-snapshots/test/lib/commands/pack.js.test.cjs @@ -56,6 +56,36 @@ Array [ ] ` +exports[`test/lib/commands/pack.js TAP should log scoped package output as valid json > logs pack contents 1`] = ` +Array [] +` + +exports[`test/lib/commands/pack.js TAP should log scoped package output as valid json > outputs as json 1`] = ` +Array [ + Array [ + Object { + "bundled": Array [], + "entryCount": 1, + "filename": "myscope-test-package-1.0.0.tgz", + "files": Array [ + Object { + "mode": 420, + "path": "package.json", + "size": 50, + }, + ], + "id": "@myscope/test-package@1.0.0", + "integrity": "sha512-bUu8iTm2E5DZMrwKeyx963K6ViEmaFocXh75EujgI+FHSaJeqvObcdk1KFwdx8CbOgsfNHEvWNQw/bONAJsoNw==", + "name": "@myscope/test-package", + "shasum": "7e6eb2e1ca46bed6b8fa8e144e0fcd1b22fe2d98", + "size": 145, + "unpackedSize": 50, + "version": "1.0.0", + }, + ], +] +` + exports[`test/lib/commands/pack.js TAP should pack current directory with no arguments > logs pack contents 1`] = ` Array [ undefined, diff --git a/tap-snapshots/test/lib/commands/publish.js.test.cjs b/tap-snapshots/test/lib/commands/publish.js.test.cjs index 28211f7794cba..fd9fd74624070 100644 --- a/tap-snapshots/test/lib/commands/publish.js.test.cjs +++ b/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -136,7 +136,7 @@ Array [ String( name: @npm/test-package version: 1.0.0 - filename: @npm/test-package-1.0.0.tgz + filename: npm-test-package-1.0.0.tgz package size: 147 B unpacked size: 55 B shasum:{sha} @@ -191,7 +191,7 @@ Array [ String( name: @npm/test-package version: 1.0.0 - filename: @npm/test-package-1.0.0.tgz + filename: npm-test-package-1.0.0.tgz package size: 147 B unpacked size: 55 B shasum:{sha} diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index 03913a0453ada..eb516f5e716e6 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -758,7 +758,7 @@ npm exec --package yo --package generator-node --call "yo node" The name of a continuous integration system. If not set explicitly, npm will detect the current CI environment using the -[\`ci-info\`](http://npm.im/@npmcli/ci-info) module. +[\`ci-info\`](http://npm.im/ci-info) module. #### \`cidr\` diff --git a/tap-snapshots/test/lib/utils/tar.js.test.cjs b/tap-snapshots/test/lib/utils/tar.js.test.cjs index e4af36aeae0b6..e2b004f176319 100644 --- a/tap-snapshots/test/lib/utils/tar.js.test.cjs +++ b/tap-snapshots/test/lib/utils/tar.js.test.cjs @@ -33,4 +33,34 @@ own files: 5 total files: 5 +` + +exports[`test/lib/utils/tar.js TAP should log tarball contents of a scoped package > must match snapshot 1`] = ` + + +package: @myscope/my-cool-pkg@1.0.0 +=== Tarball Contents === + +4B cat +4B chai +4B dog +123B package.json +=== Bundled Dependencies === + +bundle-dep +=== Tarball Details === + +name: @myscope/my-cool-pkg +version: 1.0.0 +filename: myscope-my-cool-pkg-1.0.0.tgz +package size: 280 B +unpacked size: 135 B +shasum: a4f63307f2211e8fde72cd39bc1176b4fe997b71 +integrity: sha512-b+RavF8JiErJt[...]YpwkJc8ycaabA== +bundled deps: 1 +bundled files: 0 +own files: 5 +total files: 5 + + ` diff --git a/test/lib/cli.js b/test/lib/cli.js index 5a75aa7fa121b..42a22a20b3964 100644 --- a/test/lib/cli.js +++ b/test/lib/cli.js @@ -30,7 +30,7 @@ const cliMock = async (t, opts) => { } t.afterEach(() => { - delete process.exitCode + process.exitCode = undefined }) t.test('print the version, and treat npm_g as npm -g', async t => { diff --git a/test/lib/commands/pack.js b/test/lib/commands/pack.js index f287d93dc7536..199afc640f035 100644 --- a/test/lib/commands/pack.js +++ b/test/lib/commands/pack.js @@ -77,6 +77,24 @@ t.test('should log output as valid json', async t => { t.ok(fs.statSync(path.resolve(npm.prefix, filename))) }) +t.test('should log scoped package output as valid json', async t => { + const { npm, outputs, logs } = await loadMockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: '@myscope/test-package', + version: '1.0.0', + }), + }, + }) + process.chdir(npm.prefix) + npm.config.set('json', true) + await npm.exec('pack', []) + const filename = 'myscope-test-package-1.0.0.tgz' + t.matchSnapshot(outputs.map(JSON.parse), 'outputs as json') + t.matchSnapshot(logs.notice.map(([, m]) => m), 'logs pack contents') + t.ok(fs.statSync(path.resolve(npm.prefix, filename))) +}) + t.test('dry run', async t => { const { npm, outputs, logs } = await loadMockNpm(t, { prefixDir: { diff --git a/test/lib/commands/whoami.js b/test/lib/commands/whoami.js index a4532390bc66b..8291b092dc167 100644 --- a/test/lib/commands/whoami.js +++ b/test/lib/commands/whoami.js @@ -1,6 +1,7 @@ const t = require('tap') const { load: loadMockNpm } = require('../../fixtures/mock-npm') const MockRegistry = require('@npmcli/mock-registry') +const nock = require('nock') const username = 'foo' const auth = { '//registry.npmjs.org/:_authToken': 'test-auth-token' } @@ -67,3 +68,27 @@ t.test('not logged in', async t => { }) await t.rejects(npm.exec('whoami', []), { code: 'ENEEDAUTH' }) }) + +t.test('non-string username in response', async t => { + nock.disableNetConnect() + t.teardown(() => { + nock.enableNetConnect() + }) + + const server = nock('https://registry.npmjs.org/', { + reqheaders: { + authorization: 'Bearer abcd1234', + }, + }) + .get('/-/whoami') + .reply(200, { username: null }) + + const { npm } = await loadMockNpm(t, { + config: { + '//registry.npmjs.org/:_authToken': 'abcd1234', + }, + }) + + await t.rejects(npm.exec('whoami', []), { code: 'ENEEDAUTH' }) + t.ok(server.isDone()) +}) diff --git a/test/lib/utils/tar.js b/test/lib/utils/tar.js index 23f40703b5cf4..f72b1432c89d6 100644 --- a/test/lib/utils/tar.js +++ b/test/lib/utils/tar.js @@ -51,6 +51,38 @@ t.test('should log tarball contents', async (t) => { t.matchSnapshot(printLogs(tarballContents)) }) +t.test('should log tarball contents of a scoped package', async (t) => { + const testDir = t.testdir({ + 'package.json': JSON.stringify({ + name: '@myscope/my-cool-pkg', + version: '1.0.0', + bundleDependencies: [ + 'bundle-dep', + ], + dependencies: { + 'bundle-dep': '1.0.0', + }, + }), + cat: 'meow', + chai: 'blub', + dog: 'woof', + node_modules: { + 'bundle-dep': { + 'package.json': '', + }, + }, + }) + + const tarball = await pack(testDir) + const tarballContents = await getContents({ + _id: '1', + name: '@myscope/my-cool-pkg', + version: '1.0.0', + }, tarball) + + t.matchSnapshot(printLogs(tarballContents)) +}) + t.test('should log tarball contents with unicode', async (t) => { const { logTar } = mockTar({ notice: (str) => { diff --git a/workspaces/arborist/CHANGELOG.md b/workspaces/arborist/CHANGELOG.md index b69684f80d171..775c37e445245 100644 --- a/workspaces/arborist/CHANGELOG.md +++ b/workspaces/arborist/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [6.1.4](https://github.com/npm/cli/compare/arborist-v6.1.3...arborist-v6.1.4) (2022-11-30) + +### Bug Fixes + +* [`80c6c4a`](https://github.com/npm/cli/commit/80c6c4a5111ab1779256a779a2cba41eb2c8675f) [#5907](https://github.com/npm/cli/pull/5907) do not reset hidden lockfile data before saving (#5907) (@nlf) + ## [6.1.3](https://github.com/npm/cli/compare/arborist-v6.1.2...arborist-v6.1.3) (2022-11-16) ### Bug Fixes diff --git a/workspaces/arborist/lib/arborist/reify.js b/workspaces/arborist/lib/arborist/reify.js index 36aabd6f0fcdd..e5ccec5c71d96 100644 --- a/workspaces/arborist/lib/arborist/reify.js +++ b/workspaces/arborist/lib/arborist/reify.js @@ -1531,16 +1531,12 @@ module.exports = cls => class Reifier extends cls { this.idealTree.meta.filename = this.idealTree.realpath + '/node_modules/.package-lock.json' this.idealTree.meta.hiddenLockfile = true - const resetMeta = this.idealTree.meta && this.idealTree.meta.lockfileVersion !== defaultLockfileVersion this.idealTree.meta.lockfileVersion = defaultLockfileVersion this.actualTree = this.idealTree this.idealTree = null if (!this[_global]) { - if (resetMeta) { - await this.actualTree.meta.reset() - } await this.actualTree.meta.save() const ignoreScripts = !!this.options.ignoreScripts // if we aren't doing a dry run or ignoring scripts and we actually made changes to the dep diff --git a/workspaces/arborist/package.json b/workspaces/arborist/package.json index 91d9f60c8d205..c17c3222e89bd 100644 --- a/workspaces/arborist/package.json +++ b/workspaces/arborist/package.json @@ -1,6 +1,6 @@ { "name": "@npmcli/arborist", - "version": "6.1.3", + "version": "6.1.4", "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 6eb0186cd241a..fa6d215833bbb 100644 --- a/workspaces/libnpmdiff/CHANGELOG.md +++ b/workspaces/libnpmdiff/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.5](https://github.com/npm/cli/compare/libnpmdiff-v5.0.4...libnpmdiff-v5.0.5) (2022-11-30) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.1.3...arborist-v6.1.4): `@npmcli/arborist@6.1.4` + ## [5.0.4](https://github.com/npm/cli/compare/libnpmdiff-v5.0.3...libnpmdiff-v5.0.4) (2022-11-16) ### Dependencies diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 5728476a18578..cd8937accac32 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -1,6 +1,6 @@ { "name": "libnpmdiff", - "version": "5.0.4", + "version": "5.0.5", "description": "The registry diff", "repository": { "type": "git", @@ -47,7 +47,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.0", "binary-extensions": "^2.2.0", diff --git a/workspaces/libnpmexec/CHANGELOG.md b/workspaces/libnpmexec/CHANGELOG.md index d54a544b5cc04..5809fb195c9ae 100644 --- a/workspaces/libnpmexec/CHANGELOG.md +++ b/workspaces/libnpmexec/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.5](https://github.com/npm/cli/compare/libnpmexec-v5.0.4...libnpmexec-v5.0.5) (2022-11-30) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.1.3...arborist-v6.1.4): `@npmcli/arborist@6.1.4` + ## [5.0.4](https://github.com/npm/cli/compare/libnpmexec-v5.0.3...libnpmexec-v5.0.4) (2022-11-16) ### Bug Fixes diff --git a/workspaces/libnpmexec/package.json b/workspaces/libnpmexec/package.json index 660e8f96620ad..ed550c5fb64bd 100644 --- a/workspaces/libnpmexec/package.json +++ b/workspaces/libnpmexec/package.json @@ -1,6 +1,6 @@ { "name": "libnpmexec", - "version": "5.0.4", + "version": "5.0.5", "files": [ "bin/", "lib/" @@ -51,14 +51,17 @@ }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", + "@npmcli/mock-registry": "^1.0.0", "@npmcli/template-oss": "4.10.0", "bin-links": "^4.0.1", + "just-extend": "^6.1.1", + "just-safe-set": "^4.1.1", "minify-registry-metadata": "^2.2.0", "mkdirp": "^1.0.4", "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/run-script": "^6.0.0", "chalk": "^4.1.0", "ci-info": "^3.6.1", diff --git a/workspaces/libnpmexec/test/fixtures/setup.js b/workspaces/libnpmexec/test/fixtures/setup.js new file mode 100644 index 0000000000000..84c404cbb9ca2 --- /dev/null +++ b/workspaces/libnpmexec/test/fixtures/setup.js @@ -0,0 +1,256 @@ + +const fs = require('fs/promises') +const { existsSync } = require('fs') +const { resolve, extname, join } = require('path') +const binLinks = require('bin-links') +const MockRegistry = require('@npmcli/mock-registry') +const justExtend = require('just-extend') +const set = require('just-safe-set') + +const merge = (...args) => justExtend(true, ...args) + +const DEFAULT_BIN_FILE = 'bin-file.js' + +const createPkg = ({ + name = '@npmcli/create-index', + bin, + files, + versions = [], + version, + localVersion, +}) => { + if (localVersion && !versions.includes(localVersion)) { + versions = [...versions, localVersion] + } + if (version && !versions.includes(version)) { + versions = [...versions, version] + } + + const defaultBinName = name.includes('/') ? name.split('/')[1] : name + + if (!bin) { + bin = { + [defaultBinName]: `./${DEFAULT_BIN_FILE}`, + } + } + + const pkgsArr = versions.map((v) => ({ + name, + version: v, + bin, + })) + + const pkgs = {} + const tarballs = {} + const fixtures = {} + + for (const pkg of pkgsArr) { + pkgs[pkg.version] = pkg + } + + if (localVersion) { + set(fixtures, ['node_modules', ...name.split('/')], { + 'package.json': pkgs[localVersion], + ...files || { + [DEFAULT_BIN_FILE]: { key: name, value: `local-${localVersion}` }, + }, + }) + fixtures['package.json'] = { + name: 'pkg', + version: '9.9.9', + dependencies: { + [name]: `^${localVersion}`, + }, + } + } + + for (const pkg of pkgsArr) { + const fixturePath = `${pkg.name}-${pkg.version}`.replace('/', '-') + set(fixtures, ['packages', fixturePath], { + 'package.json': pkg, + ...files || { + [DEFAULT_BIN_FILE]: { key: pkg.name, value: `packages-${pkg.version}` }, + }, + }) + tarballs[pkg.version] = join('packages', fixturePath) + } + + return { + pkg: pkgsArr[0], + pkgs, + fixtures, + package: ({ registry, path, tarballs: tgz = versions, ...opts }) => registry.package({ + times: 2, + manifest: registry.manifest({ name: pkgsArr[0].name, packuments: pkgsArr }), + tarballs: tgz.reduce((acc, v) => { + acc[v] = resolve(path, tarballs[v]) + return acc + }, {}), + ...opts, + }), + } +} + +const createTestdir = (...objs) => { + const testdirHelper = (obj, ancestors = []) => { + for (const [key, value] of Object.entries(obj)) { + if (extname(key) === '.json') { + obj[key] = JSON.stringify(value, null, 2) + } else if (extname(key) === '.js' || ancestors.slice(-2).join('/') === 'node_modules/.bin') { + // a js or bin file is converted to a bin script that writes a file + obj[key] = `#!/usr/bin/env node\nrequire('fs').writeFileSync( + 'output-${value.key.replace('/', '-')}', + JSON.stringify({ + value: '${value.value}', + args: process.argv.slice(2), + created: '${[...ancestors, key].join('/')}', + }) + )` + } else if (value && typeof value === 'object') { + obj[key] = testdirHelper(value, [...ancestors, key]) + } else { + obj[key] = value + } + } + return obj + } + + return testdirHelper(merge(...objs)) +} + +const setup = (t, { + pkg, + testdir: _testdir = {}, + mocks, + global, + debug, + execPath, + defaults = true, +} = {}) => { + const registry = new MockRegistry({ + tap: t, + registry: 'http://smoke-test-registry.club/', + strict: true, + debug, + }) + + if (debug) { + process.on('log', console.error) + t.teardown(() => process.off('log', console.error)) + } + + const { node_modules: testdirNm, ...testdir } = _testdir + const fullTestdir = createTestdir({ + cache: {}, + npxCache: {}, + ...testdirNm ? + global ? { + global: { + node_modules: { + '.bin': {}, + ...testdirNm, + }, + }, + } : { + node_modules: { + '.bin': {}, + ...testdirNm, + }, + } + : {}, + }, testdir) + + // quick way to remove undefined and null values that we merged + // in to not write certain directories + const path = t.testdir(JSON.parse(JSON.stringify(fullTestdir, (_, v) => { + if (v === null) { + return + } + if (typeof v === 'string') { + return v.replace(/\{REGISTRY\}/g, registry.origin) + } + return v + })) + ) + + const cache = resolve(path, 'cache') + const npxCache = resolve(path, 'npxCache') + const nodeModules = resolve(path, global ? 'global/node_modules' : 'node_modules') + + const defaultOpts = { + call: '', + color: false, + localBin: '', + globalBin: '', + packages: [], + scriptShell: undefined, + yes: true, + path, + runPath: path, + } + + const baseOpts = { + audit: false, + registry: registry.origin + '/', + ...existsSync(cache) ? { cache } : {}, + ...existsSync(npxCache) ? { npxCache } : {}, + ...global ? { + globalBin: resolve(path, nodeModules, '.bin'), + globalPath: resolve(path, 'global'), + } : {}, + } + + return { + path, + registry, + chmod: async (chmodPath) => { + if (!chmodPath) { + for (const p of [].concat(pkg)) { + await fs.chmod(resolve(path, nodeModules, p.name, DEFAULT_BIN_FILE), 0o775) + } + return + } + return fs.chmod(resolve(path, chmodPath), 0o775) + }, + binLinks: async (binPkg) => { + if (!binPkg) { + for (const p of [].concat(pkg)) { + await binLinks({ + pkg: p, + path: resolve(path, nodeModules, p.name), + }) + } + return + } + await binLinks({ + pkg: binPkg, + path: resolve(path, nodeModules, binPkg.name), + }) + }, + readOutput: async (outputPath, { root = path } = {}) => { + if (!outputPath) { + outputPath = pkg.name.replace('/', '-') + } + return fs.readFile(resolve(root, `output-${outputPath}`), 'utf-8').then(r => JSON.parse(r)) + }, + rmOutput: (outputPath, { root = path } = {}) => { + if (!outputPath) { + outputPath = pkg.name.replace('/', '-') + } + return fs.rm(resolve(root, `output-${outputPath}`)) + }, + exec: (opts) => t.mock(execPath || '../../lib/index.js', mocks)({ + ...defaults ? { + ...defaultOpts, + path, + runPath: path, + } : {}, + ...baseOpts, + ...opts, + }), + } +} + +module.exports.setup = setup +module.exports.createPkg = createPkg +module.exports.merge = merge diff --git a/workspaces/libnpmexec/test/index.js b/workspaces/libnpmexec/test/index.js index c3cdecf66e8d9..008560efc7018 100644 --- a/workspaces/libnpmexec/test/index.js +++ b/workspaces/libnpmexec/test/index.js @@ -1,1270 +1,16 @@ -const fs = require('fs') -const { resolve } = require('path') const t = require('tap') -const binLinks = require('bin-links') - -const libexec = require('../lib/index.js') - -// setup server -const registryServer = require('./registry/server.js') -const { registry } = registryServer -t.test('setup server', { bail: true, buffered: false }, registryServer) - -const baseOpts = { - audit: false, - call: '', - color: false, - localBin: '', - globalBin: '', - packages: [], - path: '', - registry, - runPath: '', - scriptShell: undefined, - yes: true, -} - -t.test('bin in local pkg', async t => { - const pkg = { - name: '@npmcli/local-pkg-bin-test', - bin: { - b: 'echo this is something else', - a: 'local-bin-test.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - 'local-bin-test.js': `#!/usr/bin/env node -require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - 'package.json': JSON.stringify(pkg), - }) - const localBin = resolve(path, 'node_modules/.bin') - const runPath = path - const npxCache = resolve(path, 'npxCache') - - const executable = resolve(path, 'local-bin-test.js') - fs.chmodSync(executable, 0o775) - - await libexec({ - ...baseOpts, - args: ['a', 'resfile'], - npxCache, - localBin, - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('locally available pkg - by scoped name only', async t => { - const pkg = { - name: '@npmcli/npx-local-test', - version: '2.0.0', - bin: { - 'npx-local-test': './index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@npmcli': { - 'npx-local-test': { - 'package.json': JSON.stringify(pkg), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@npmcli/npx-local-test': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = - resolve(path, 'node_modules/@npmcli/npx-local-test/index.js') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'node_modules/@npmcli/npx-local-test'), - pkg, - }) - - await libexec({ - ...baseOpts, - cache, - npxCache, - args: ['@npmcli/npx-local-test', 'resfile'], - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('locally available pkg - by name', async t => { - const pkg = { - name: '@ruyadorno/create-index', - version: '2.0.0', - bin: { - 'create-index': './index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify(pkg), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = - resolve(path, 'node_modules/@ruyadorno/create-index/index.js') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'node_modules/@ruyadorno/create-index'), - pkg, - }) - - await libexec({ - ...baseOpts, - cache, - npxCache, - packages: ['@ruyadorno/create-index'], - call: 'create-index resfile', - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('locally available pkg - by version', async t => { - const pkg = { - name: '@ruyadorno/create-index', - version: '1.0.0', - bin: { - 'create-index': './index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify(pkg), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync('resfile', 'LOCAL PKG')`, - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^1.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = - resolve(path, 'node_modules/@ruyadorno/create-index/index.js') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'node_modules/@ruyadorno/create-index'), - pkg, - }) - - await libexec({ - ...baseOpts, - cache, - npxCache, - args: ['@ruyadorno/create-index@1.0.0'], - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('locally available pkg - by range', async t => { - const pkg = { - name: '@ruyadorno/create-index', - version: '2.0.0', - bin: { - 'create-index': './index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify(pkg), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = - resolve(path, 'node_modules/@ruyadorno/create-index/index.js') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'node_modules/@ruyadorno/create-index'), - pkg, - }) - - await libexec({ - ...baseOpts, - cache, - npxCache, - packages: ['@ruyadorno/create-index@^2.0.0'], - call: 'create-index resfile', - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('locally available pkg - by tag', async t => { - const pkg = { - name: '@ruyadorno/create-index', - version: '1.0.0', - bin: { - 'create-index': './index.js', - }, - } - - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify(pkg), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - }, - }, - '.package-lock.json': JSON.stringify({ - name: 'lock', - lockfileVersion: 3, - requires: true, - packages: { - 'node_modules/@ruyadorno/create-index': { - version: '1.0.0', - resolved: 'https://registry.npmjs.org/@ruyadorno/create-index/-/create-index-1.0.0.tgz', - bin: { - 'create-index': 'create-index.js', - }, - }, - }, - - }), - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^1.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = - resolve(path, 'node_modules/@ruyadorno/create-index/index.js') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'node_modules/@ruyadorno/create-index'), - pkg, - }) - - await libexec({ - ...baseOpts, - cache, - npxCache, - packages: ['@ruyadorno/create-index@latest'], - call: 'create-index resfile', - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('multiple local pkgs', async t => { - const foo = { - name: '@ruyadorno/create-foo', - version: '2.0.0', - bin: { - 'create-foo': './index.js', - }, - } - const bar = { - name: '@ruyadorno/create-bar', - version: '2.0.0', - bin: { - 'create-bar': './index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-foo': { - 'package.json': JSON.stringify(foo), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'foo')`, - }, - 'create-bar': { - 'package.json': JSON.stringify(bar), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'bar')`, - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-foo': '^2.0.0', - '@ruyadorno/create-bar': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const setupBins = async (pkg) => { - const executable = - resolve(path, `node_modules/${pkg.name}/index.js`) - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, `node_modules/${pkg.name}`), - pkg, - }) - } - - await Promise.all([foo, bar] - .map(setupBins)) - - await libexec({ - ...baseOpts, - localBin: resolve(path, 'node_modules/.bin'), - cache, - npxCache, - packages: ['@ruyadorno/create-foo', '@ruyadorno/create-bar'], - call: 'create-foo resfile && create-bar bar', - path, - runPath, - }) - - const resFoo = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(resFoo, 'foo', 'should run local pkg bin script') - const resBar = fs.readFileSync(resolve(path, 'bar')).toString() - t.equal(resBar, 'bar', 'should run local pkg bin script') -}) - -t.test('no npxCache', async t => { - const path = t.testdir({ - cache: {}, - a: { - 'package.json': JSON.stringify({ - name: 'a', - bin: { - a: './index.js', - }, - }), - 'index.js': `#!/usr/bin/env node -require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - }, - }) - const runPath = path - const cache = resolve(path, 'cache') - - const executable = resolve(path, 'a/index.js') - fs.chmodSync(executable, 0o775) - - await t.rejects(libexec({ - ...baseOpts, - args: [`file:${resolve(path, 'a')}`, 'resfile'], - cache, - path, - runPath, - }), /Must provide a valid npxCache path/) -}) - -t.test('local file system path', async t => { - const path = t.testdir({ - cache: {}, - npxCache: {}, - a: { - 'package.json': JSON.stringify({ - name: 'a', - bin: { - a: './index.js', - }, - }), - 'index.js': `#!/usr/bin/env node -require('fs').writeFileSync(process.argv.slice(2)[0], 'LOCAL PKG')`, - }, - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = resolve(path, 'a/index.js') - fs.chmodSync(executable, 0o775) - - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: true }, - 'proc-log': { - warn (title, msg) { - t.fail('should not warn about local file package install') - }, - }, - }) - - await mockexec({ - ...baseOpts, - args: [`file:${resolve(path, 'a')}`, 'resfile'], - cache, - npxCache, - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run local pkg bin script') -}) - -t.test('global space pkg', async t => { - const pkg = { - name: 'a', - bin: { - a: 'index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - global: { - node_modules: { - '.bin': {}, - a: { - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'GLOBAL PKG')`, - 'package.json': JSON.stringify(pkg), - }, - }, - }, - }) - const globalBin = resolve(path, 'global/node_modules/.bin') - const globalPath = resolve(path, 'global') - const runPath = path - - const executable = resolve(path, 'global/node_modules/a') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'global/node_modules/a'), - pkg, - }) - - await libexec({ - ...baseOpts, - args: ['a', 'resfile'], - globalBin, - globalPath, - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'GLOBAL PKG', 'should run local pkg bin script') -}) - -t.test('global scoped pkg', async t => { - const pkg = { - name: '@ruyadorno/create-test', - bin: { - 'create-test': 'index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - global: { - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-test': { - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync(process.argv.slice(2)[0], 'GLOBAL PKG')`, - 'package.json': JSON.stringify(pkg), - }, - }, - }, - }, - }) - const globalBin = resolve(path, 'global/node_modules/.bin') - const globalPath = resolve(path, 'global') - const runPath = path - - await binLinks({ - path: resolve(path, 'global/node_modules/@ruyadorno/create-test'), - pkg, - }) - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-test', 'resfile'], - globalBin, - globalPath, - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'GLOBAL PKG', 'should run global pkg bin script') -}) - -t.test('run from registry - no local packages', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - global: { - lib: {}, - bin: {}, - }, - work: {}, - }) - const path = resolve(testdir, 'work') - - t.throws( - () => fs.statSync(resolve(path, 'index.js')), - { code: 'ENOENT' }, - 'should not have template file' - ) - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache: resolve(testdir, 'cache'), - globalPath: resolve(testdir, 'global'), - npxCache: resolve(testdir, 'npxCache'), - path, - runPath: path, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran create pkg') -}) - -t.test('run from registry - local version mismatch', async t => { - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify({ - name: '@ruyadorno/create-index', - version: '2.0.0', - }), - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index@1.0.0'], - cache, - npxCache, - path, - runPath, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran create pkg from registry') -}) - -t.test('run from registry - local range mismatch', async t => { - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify({ - name: '@ruyadorno/create-index', - version: '2.0.0', - }), - }, - }, - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index@^1.0.0'], - cache, - npxCache, - path, - runPath, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran create pkg from registry') -}) - -t.test('run from registry - local tag mismatch', async t => { - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify({ - name: '@ruyadorno/create-index', - version: '2.0.0', - }), - }, - }, - '.package-lock.json': JSON.stringify({ - name: 'lock', - lockfileVersion: 3, - requires: true, - packages: { - 'node_modules/@ruyadorno/create-index': { - version: '2.0.0', - resolved: 'https://registry.npmjs.org/@ruyadorno/create-index/-/create-index-2.0.0.tgz', - bin: { - 'create-index': 'create-index.js', - }, - }, - }, - - }), - }, - 'package.json': JSON.stringify({ - name: 'pkg', - dependencies: { - '@ruyadorno/create-index': '^2.0.0', - }, - }), - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index@latest'], - cache, - npxCache, - path, - runPath, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran create pkg from registry') -}) - -t.test('avoid install when exec from registry an available pkg', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - - t.throws( - () => fs.statSync(resolve(path, 'index.js')), - { code: 'ENOENT' }, - 'should not have template file' - ) - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran create pkg') - fs.unlinkSync(resolve(path, 'index.js')) - - await libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran create pkg again') -}) - -t.test('run multiple from registry', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - - t.throws( - () => fs.statSync(resolve(path, 'index.js')), - { code: 'ENOENT' }, - 'should not have index template file' - ) - - t.throws( - () => fs.statSync(resolve(path, 'test.js')), - { code: 'ENOENT' }, - 'should not have test template file' - ) - - await libexec({ - ...baseOpts, - packages: ['@ruyadorno/create-test', '@ruyadorno/create-index'], - call: 'create-test && create-index', - cache, - npxCache, - path, - runPath, - }) - - t.ok(fs.statSync(resolve(path, 'index.js')).isFile(), 'ran index pkg') - t.ok(fs.statSync(resolve(path, 'test.js')).isFile(), 'ran test pkg') -}) +const { setup } = require('./fixtures/setup.js') t.test('no args', async t => { - const path = t.testdir({}) - const runPath = path - const mockexec = t.mock('../lib/index.js', { - '../lib/run-script': ({ args }) => { - t.ok(args.length === 0, 'should call run-script with no args') - }, - }) - - await mockexec({ - ...baseOpts, - path, - runPath, - }) -}) - -t.test('prompt, accepts', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - t.test('with clearProgress function', async t => { - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: false }, - npmlog: { - clearProgress () { - t.ok(true, 'should call clearProgress function') - }, - disableProgress () {}, - enableProgress () {}, - }, - read (opts, cb) { - cb(null, 'y') - }, - '../lib/no-tty.js': () => false, - }) - - await mockexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - t.ok(fs.statSync(installedDir).isFile(), 'installed required packages') - }) - - t.test('without clearProgress function', async t => { - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: false }, - read (opts, cb) { - cb(null, 'y') - }, - '../lib/no-tty.js': () => false, - }) - - await mockexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - t.ok(fs.statSync(installedDir).isFile(), 'installed required packages') - }) -}) - -t.test('prompt, refuses', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - t.test('with clearProgress function', async t => { - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: false }, - npmlog: { - clearProgress () { - t.ok(true, 'should call clearProgress function') - }, - disableProgess () {}, - }, - read (opts, cb) { - cb(null, 'n') - }, - '../lib/no-tty.js': () => false, - }) - - await t.rejects( - mockexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }), - /canceled/, - 'should throw with canceled error' - ) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - - t.throws( - () => fs.statSync(installedDir), - { code: 'ENOENT' }, - 'should not have installed required packages' - ) - }) + t.plan(1) - t.test('without clearProgress function', async t => { - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: false }, - read (opts, cb) { - cb(null, 'n') - }, - '../lib/no-tty.js': () => false, - }) - - await t.rejects( - mockexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }), - /canceled/, - 'should throw with canceled error' - ) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - - t.throws( - () => fs.statSync(installedDir), - { code: 'ENOENT' }, - 'should not have installed required packages' - ) - }) -}) - -t.test('prompt, -n', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - - await t.rejects( - libexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: false, - }), - /canceled/, - 'should throw with canceled error' - ) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - - t.throws( - () => fs.statSync(installedDir), - { code: 'ENOENT' }, - 'should not have installed required packages' - ) -}) - -t.test('no prompt if no tty', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - const mockexec = t.mock('../lib/index.js', { - '../lib/no-tty.js': () => true, - }) - - await mockexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - t.ok(fs.statSync(installedDir).isFile(), 'installed required packages') -}) - -t.test('no prompt if CI', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: true }, - }) - - await mockexec({ - ...baseOpts, - args: ['@ruyadorno/create-index'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }) - - const installedDir = resolve(npxCache, - '0e8e15840a234288/node_modules/@ruyadorno/create-index/package.json') - t.ok(fs.statSync(installedDir).isFile(), 'installed required packages') -}) - -t.test('no prompt if CI, multiple packages', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const path = resolve(testdir, 'work') - const runPath = path - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - const mockexec = t.mock('../lib/index.js', { - 'ci-info': { isCI: true }, - 'proc-log': { - warn (title, msg) { - t.equal(title, 'exec', 'should warn exec title') - // this message is nondeterministic as it queries manifests so we just - // test the constituent parts - t.match( - msg, - 'The following packages were not found and will be installed:', - 'should warn installing packages' - ) - t.match(msg, '@ruyadorno/create-index@1.0.0', 'includes package being installed') - t.match(msg, '@ruyadorno/create-test@1.0.0', 'includes package being installed') + const { exec } = setup(t, { + mocks: { + '../../lib/run-script': ({ args }) => { + t.ok(args.length === 0, 'should call run-script with no args') }, }, }) - await mockexec({ - ...baseOpts, - call: 'create-index', - packages: ['@ruyadorno/create-index', '@ruyadorno/create-test'], - cache, - npxCache, - path, - runPath, - yes: undefined, - }) -}) - -t.test('defaults', async t => { - const testdir = t.testdir({ - cache: {}, - npxCache: {}, - work: {}, - }) - const cache = resolve(testdir, 'cache') - const npxCache = resolve(testdir, 'npxCache') - const workdir = resolve(testdir, 'work') - - const cwd = process.cwd() - process.chdir(workdir) - t.teardown(() => { - process.chdir(cwd) - }) - - await libexec({ - args: ['@ruyadorno/create-index'], - cache, - npxCache, - yes: true, - }) - - t.ok(fs.statSync(resolve(workdir, 'index.js')).isFile(), - 'ran create-index pkg') -}) - -t.test('scriptShell default value', t => { - t.test('/bin/sh platforms', t => { - t.plan(1) - const mockexec = t.mock('../lib/index.js', { - '../lib/is-windows.js': false, - '../lib/run-script.js': (opt) => { - t.equal(opt.scriptShell, 'sh', 'should use expected shell value') - }, - }) - mockexec({ args: [], runPath: t.testDirName }) - }) - - t.test('win32 defined ComSpec env var', t => { - t.plan(1) - const comspec = process.env.ComSpec - process.env.ComSpec = 'CMD' - const mockexec = t.mock('../lib/index.js', { - '../lib/is-windows.js': true, - '../lib/run-script.js': ({ scriptShell }) => { - t.equal(scriptShell, 'CMD', 'should use expected ComSpec value') - process.env.ComSpec = comspec - }, - }) - mockexec({ args: [], runPath: t.testDirName }) - }) - - t.test('win32 cmd', t => { - t.plan(1) - const comspec = process.env.ComSpec - process.env.ComSpec = '' - const mockexec = t.mock('../lib/index.js', { - '../lib/is-windows.js': true, - '../lib/run-script.js': ({ scriptShell }) => { - t.equal(scriptShell, 'cmd', 'should use expected cmd default value') - process.env.ComSpec = comspec - }, - }) - mockexec({ args: [], runPath: t.testDirName }) - }) - - t.end() -}) - -t.test('workspaces', async t => { - const pkg = { - name: '@ruyadorno/create-index', - version: '2.0.0', - bin: { - 'create-index': './index.js', - }, - } - const path = t.testdir({ - cache: {}, - npxCache: {}, - node_modules: { - '.bin': {}, - '@ruyadorno': { - 'create-index': { - 'package.json': JSON.stringify(pkg), - 'index.js': `#!/usr/bin/env node - require('fs').writeFileSync('resfile', 'LOCAL PKG')`, - }, - }, - a: t.fixture('symlink', '../a'), - }, - 'package.json': JSON.stringify({ - name: 'project', - workspaces: ['a'], - }), - a: { - 'package.json': JSON.stringify({ - name: 'a', - version: '1.0.0', - dependencies: { - '@ruyadorno/create-index': '^2.0.0', - }, - }), - }, - }) - const runPath = path - const cache = resolve(path, 'cache') - const npxCache = resolve(path, 'npxCache') - - const executable = - resolve(path, 'node_modules/@ruyadorno/create-index/index.js') - fs.chmodSync(executable, 0o775) - - await binLinks({ - path: resolve(path, 'node_modules/@ruyadorno/create-index'), - pkg, - }) - - // runs at the project level - await libexec({ - ...baseOpts, - args: ['create-index'], - localBin: resolve(path, 'node_modules/.bin'), - cache, - npxCache, - path, - runPath, - }) - - const res = fs.readFileSync(resolve(path, 'resfile')).toString() - t.equal(res, 'LOCAL PKG', 'should run existing bin from project level') - - // runs at the child workspace level - await libexec({ - ...baseOpts, - args: ['create-index'], - cache, - npxCache, - localBin: resolve(path, 'a/node_modules/.bin'), - path: resolve(path, 'a'), - runPath: resolve(path, 'a'), - }) - - const wRes = fs.readFileSync(resolve(path, 'a/resfile')).toString() - t.equal(wRes, 'LOCAL PKG', 'should run existing bin from workspace level') + await exec() }) diff --git a/workspaces/libnpmexec/test/local.js b/workspaces/libnpmexec/test/local.js new file mode 100644 index 0000000000000..19595187e265f --- /dev/null +++ b/workspaces/libnpmexec/test/local.js @@ -0,0 +1,370 @@ +const log = require('proc-log') +const { resolve } = require('path') +const t = require('tap') +const fs = require('fs/promises') +const { resetSeen: resetSeenLinks } = require('bin-links') +const { setup, createPkg, merge } = require('./fixtures/setup.js') + +t.test('bin in local pkg', async t => { + const { pkg, fixtures } = createPkg({ + version: '1.0.0', + name: '@npmcli/local-pkg-bin-test', + bin: { + b: 'does-not-exist.js', + a: 'local-bin-test.js', + 'a-nested': 'bin-dir/nested-bin-test.js', + 'conflicting-bin': 'conflicting-bin-test.js', + }, + files: { + 'local-bin-test.js': { key: 'local-bin', value: 'LOCAL PKG' }, + 'conflicting-bin-test.js': { key: 'conflicting-bin', value: 'LOCAL PKG' }, + 'bin-dir': { + 'nested-bin-test.js': { key: 'nested-bin', value: 'LOCAL PKG' }, + }, + }, + }) + + const existingPkg = createPkg({ + name: 'pkg-with-conflicting-bin', + localVersion: '1.0.0', + bin: { + 'conflicting-bin': 'index.js', + }, + files: { + 'index.js': { key: 'existing-bin', value: 'NODE_MODULES PKG' }, + }, + }) + + const { exec: _exec, chmod, readOutput, binLinks, path } = setup(t, { + pkg, + testdir: merge( + existingPkg.fixtures, + fixtures.packages[`@npmcli-local-pkg-bin-test-1.0.0`], + { + node_modules: { + '@npmcli': { + 'some-other-pkg-with-same-scope': {}, + }, + }, + } + ), + }) + + const localBin = resolve(path, 'node_modules', '.bin') + + await chmod('local-bin-test.js') + await chmod('conflicting-bin-test.js') + await chmod('bin-dir/nested-bin-test.js') + await chmod('node_modules/pkg-with-conflicting-bin/index.js') + + // Note that we have to resetSeenLinks after each exec since otherwise + // our non-existent file will fail when it gets attempted to get chmod'ed + // in a real world situation these would happen during different + // processes where these is no shared cache + const exec = async (...args) => { + await _exec(...args) + resetSeenLinks() + } + + await exec({ localBin, args: ['a', 'argument-a'] }) + t.match(await readOutput('local-bin'), { + value: 'LOCAL PKG', + args: ['argument-a'], + }) + t.strictSame(await fs.readdir(resolve(path, 'node_modules', '.bin')), []) + + await exec({ localBin, args: ['a-nested', 'argument-a-nested'] }) + t.strictSame(await fs.readdir(resolve(path, 'node_modules', '.bin')), []) + t.match(await readOutput('nested-bin'), { + value: 'LOCAL PKG', + args: ['argument-a-nested'], + }) + + // now link a bin which will conflict with the one we try to run next + await binLinks(existingPkg.pkg) + + t.match(await fs.readdir(resolve(path, 'node_modules', '.bin')), ['conflicting-bin']) + await exec({ localBin, args: ['conflicting-bin'] }) + // local bin was called for conflicting-bin + t.match(await readOutput('conflicting-bin'), { + value: 'LOCAL PKG', + }) + + await t.rejects(() => exec({ localBin, args: ['b'] }), /command failed/) +}) + +t.test('locally available pkg - by scoped name only', async t => { + const { pkg, fixtures } = createPkg({ + name: '@npmcli/npx-local-test', + localVersion: '2.0.0', + }) + + const { exec, chmod, binLinks, readOutput } = setup(t, { + pkg, + testdir: fixtures, + }) + + await chmod() + await binLinks() + await exec({ args: ['@npmcli/npx-local-test', 'arg'] }) + + t.match(await readOutput(), { + value: 'local-2.0.0', + args: ['arg'], + }) +}) + +t.test('locally available pkg - by name', async t => { + const { pkg, fixtures } = createPkg({ + name: '@npmcli/create-index', + localVersion: '2.0.0', + }) + + const { chmod, binLinks, exec, readOutput } = setup(t, { + pkg, + testdir: fixtures, + }) + + await chmod() + await binLinks() + await exec({ + packages: ['@npmcli/create-index'], + call: 'create-index arg', + }) + + t.match(await readOutput(), { + value: 'local-2.0.0', + args: ['arg'], + }) +}) + +t.test('locally available pkg - by version', async t => { + const { pkg, fixtures } = createPkg({ + name: '@npmcli/create-index', + localVersion: '1.0.0', + }) + const { chmod, binLinks, exec, readOutput } = setup(t, { + pkg, + testdir: fixtures, + }) + + await chmod() + await binLinks() + await exec({ args: ['@npmcli/create-index@1.0.0'] }) + + t.match(await readOutput(), { + value: 'local-1.0.0', + args: [], + }) +}) + +t.test('locally available pkg - by range', async t => { + const { pkg, fixtures } = createPkg({ + name: '@npmcli/create-index', + localVersion: '2.0.0', + }) + const { chmod, binLinks, exec, readOutput } = setup(t, { + pkg, + testdir: fixtures, + }) + + await chmod() + await binLinks() + await exec({ + packages: ['@npmcli/create-index@^2.0.0'], + call: 'create-index resfile', + }) + + t.match(await readOutput(), { + value: 'local-2.0.0', + args: ['resfile'], + }) +}) + +t.test('locally available pkg - by latest tag', async t => { + const { pkg, fixtures, package } = createPkg({ + name: '@npmcli/create-index', + localVersion: '1.0.0', + }) + const { chmod, binLinks, exec, readOutput, registry, path } = setup(t, { + pkg, + testdir: merge(fixtures, { + node_modules: { + '.package-lock.json': { + name: 'lock', + lockfileVersion: 3, + requires: true, + packages: { + [`node_modules/${pkg.name}`]: { + ...pkg, + resolved: `{REGISTRY}/${pkg.name}/-/create-index-${pkg.version}.tgz`, + }, + }, + }, + }, + }), + }) + + // latest forces the manifest to be fetched + await package({ registry, path, times: 1, tarballs: [] }) + + await chmod() + await binLinks() + await exec({ + packages: ['@npmcli/create-index@latest'], + call: 'create-index resfile', + }) + + t.match(await readOutput(), { + value: 'local-1.0.0', + args: ['resfile'], + }) +}) + +t.test('multiple local pkgs', async t => { + const pkgFoo = createPkg({ + name: '@npmcli/create-foo', + localVersion: '2.0.0', + }) + + const pkgBar = createPkg({ + name: '@npmcli/create-bar', + localVersion: '1.0.0', + }) + + const { readOutput, chmod, exec, binLinks } = setup(t, { + pkg: [pkgFoo.pkg, pkgBar.pkg], + testdir: merge(pkgFoo.fixtures, pkgBar.fixtures), + }) + + await chmod() + await binLinks() + + await exec({ + packages: ['@npmcli/create-foo', '@npmcli/create-bar'], + call: 'create-foo resfile && create-bar bar', + }) + + t.match(await readOutput('@npmcli-create-foo'), { + value: 'local-2.0.0', + args: ['resfile'], + }) + t.match(await readOutput('@npmcli-create-bar'), { + value: 'local-1.0.0', + args: ['bar'], + }) +}) + +t.test('no npxCache', async t => { + const { chmod, exec, path } = setup(t, { + testdir: { + npxCache: null, + a: { + 'package.json': { + name: 'a', + bin: { + a: './index.js', + }, + }, + 'index.js': { key: 'a', value: 'LOCAL PKG' }, + }, + }, + }) + + await chmod('a/index.js') + + await t.rejects(() => exec({ + args: [`file:${resolve(path, 'a')}`, 'resfile'], + }), /Must provide a valid npxCache path/) +}) + +t.test('local file system path', async t => { + const { exec, chmod, readOutput, path } = setup(t, { + mocks: { + 'ci-info': { isCI: true }, + 'proc-log': { + ...log, + warn () { + t.fail('should not warn about local file package install') + }, + }, + }, + testdir: { + a: { + 'package.json': { + name: 'a', + bin: { + a: './index.js', + }, + }, + 'index.js': { key: 'a', value: 'LOCAL PKG' }, + }, + }, + }) + + await chmod('a/index.js') + + await exec({ + args: [`file:${resolve(path, 'a')}`, 'resfile'], + + }) + + t.match(await readOutput('a'), { + value: 'LOCAL PKG', + args: ['resfile'], + }) +}) + +t.test('global space pkg', async t => { + const { pkg, fixtures } = createPkg({ + name: 'a', + localVersion: '1.0.0', + }) + + const { exec, chmod, readOutput, binLinks } = setup(t, { + pkg, + global: true, + testdir: fixtures, + }) + + await chmod() + await binLinks() + + await exec({ + args: ['a', 'resfile'], + }) + + t.match(await readOutput(), { + value: 'local-1.0.0', + args: [], + created: 'global/node_modules/a/bin-file.js', + }) +}) + +t.test('global scoped pkg', async t => { + const { pkg, fixtures, package } = createPkg({ + localVersion: '1.0.0', + name: '@npmcli/create-test', + }) + + const { chmod, exec, readOutput, binLinks, registry, path } = setup(t, { + pkg, + global: true, + testdir: fixtures, + }) + + await chmod() + await binLinks() + + await package({ registry, path, times: 1, tarballs: [] }) + + await exec({ + args: ['@npmcli/create-test', 'resfile'], + }) + + t.match(await readOutput(), { + value: 'local-1.0.0', + args: ['resfile'], + created: 'global/node_modules/@npmcli/create-test/bin-file.js', + }) +}) diff --git a/workspaces/libnpmexec/test/prompt.js b/workspaces/libnpmexec/test/prompt.js new file mode 100644 index 0000000000000..ff93d8f2b777b --- /dev/null +++ b/workspaces/libnpmexec/test/prompt.js @@ -0,0 +1,384 @@ +const log = require('proc-log') +const { resolve } = require('path') +const t = require('tap') +const fs = require('fs/promises') +const { setup, createPkg, merge } = require('./fixtures/setup.js') + +t.test('prompt, accepts', async t => { + t.test('with clearProgress function', async t => { + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + mocks: { + 'ci-info': { isCI: false }, + '../../lib/no-tty.js': () => false, + npmlog: { + clearProgress () { + t.ok(true, 'should call clearProgress function') + }, + disableProgress () {}, + enableProgress () {}, + }, + read (_, cb) { + cb(null, 'y') + }, + }, + }) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index'], + yes: undefined, + }) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.ok(await fs.stat(resolve(path, installedDir)).then(f => f.isFile())) + }) + + t.test('without clearProgress function', async t => { + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + mocks: { + 'ci-info': { isCI: false }, + '../../lib/no-tty.js': () => false, + read (_, cb) { + cb(null, 'y') + }, + }, + }) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index'], + yes: undefined, + }) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.ok(await fs.stat(resolve(path, installedDir)).then(f => f.isFile())) + }) +}) + +t.test('prompt, refuses', async t => { + t.test('with clearProgress function', async t => { + t.plan(3) + + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + mocks: { + 'ci-info': { isCI: false }, + npmlog: { + clearProgress () { + t.ok(true, 'should call clearProgress function') + }, + disableProgess () {}, + }, + read (_, cb) { + cb(null, 'n') + }, + '../../lib/no-tty.js': () => false, + }, + }) + + await package({ registry, path, times: 1, tarballs: [] }) + + await t.rejects( + exec({ + args: ['@npmcli/create-index'], + yes: undefined, + }), + /canceled/, + 'should throw with canceled error' + ) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.rejects( + () => fs.stat(resolve(path, installedDir)), + { code: 'ENOENT' } + ) + }) + + t.test('without clearProgress function', async t => { + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + mocks: { + 'ci-info': { isCI: false }, + read (_, cb) { + cb(null, 'n') + }, + '../../lib/no-tty.js': () => false, + }, + }) + + await package({ registry, path, times: 1, tarballs: [] }) + + await t.rejects( + exec({ + args: ['@npmcli/create-index'], + yes: undefined, + }), + /canceled/, + 'should throw with canceled error' + ) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.rejects( + () => fs.stat(resolve(path, installedDir)), + { code: 'ENOENT' } + ) + }) +}) + +t.test('prompt, -n', async t => { + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + }) + + await package({ registry, path, times: 1, tarballs: [] }) + + await t.rejects( + exec({ + args: ['@npmcli/create-index'], + yes: false, + }), + /canceled/, + 'should throw with canceled error' + ) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.rejects( + () => fs.stat(resolve(path, installedDir)), + { code: 'ENOENT' } + ) +}) + +t.test('no prompt if no tty', async t => { + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + mocks: { '../../lib/no-tty.js': () => true }, + }) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index'], + yes: undefined, + }) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.ok(await fs.stat(resolve(path, installedDir)).then(f => f.isFile())) +}) + +t.test('no prompt if CI', async t => { + const { pkg, package, fixtures } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: fixtures, + mocks: { 'ci-info': { isCI: true } }, + }) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index'], + yes: undefined, + }) + + const installedDir = `npxCache/e7ce50d8d2d8ec11/node_modules/${pkg.name}/package.json` + t.ok(await fs.stat(resolve(path, installedDir)).then(f => f.isFile())) +}) + +t.test('no prompt if CI, multiple packages', async t => { + t.plan(4) + + const pkgIndex = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const pkgTest = createPkg({ + name: '@npmcli/create-test', + version: '1.0.0', + }) + const { exec, path, registry } = setup(t, { + testdir: merge(pkgIndex.fixtures, pkgTest.fixtures), + mocks: { + 'ci-info': { isCI: true }, + 'proc-log': { + ...log, + warn (title, msg) { + t.equal(title, 'exec', 'should warn exec title') + // this message is nondeterministic as it queries manifests so we just + // test the constituent parts + t.match( + msg, + 'The following packages were not found and will be installed:', + 'should warn installing packages' + ) + t.match(msg, '@npmcli/create-index@1.0.0', 'includes package being installed') + t.match(msg, '@npmcli/create-test@1.0.0', 'includes package being installed') + }, + }, + }, + }) + + await pkgIndex.package({ path, registry }) + await pkgTest.package({ path, registry }) + + await exec({ + call: 'create-index', + packages: ['@npmcli/create-index', '@npmcli/create-test'], + yes: undefined, + }) +}) + +t.test('defaults', async t => { + const { pkg, fixtures, package } = createPkg({ + name: '@npmcli/create-index', + version: '1.0.0', + }) + const { exec, path, registry, readOutput } = setup(t, { + pkg, + defaults: false, + execPath: '../../../lib/index.js', + testdir: { + ...fixtures, + work: {}, + }, + }) + + const workDir = resolve(path, 'work') + const cwd = process.cwd() + process.chdir(workDir) + t.teardown(() => process.chdir(cwd)) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index'], + yes: true, + }) + + t.match(await readOutput('', { root: workDir }), { + value: 'packages-1.0.0', + args: [], + }) +}) + +t.test('scriptShell default value', async t => { + await t.test('/bin/sh platforms', async t => { + t.plan(1) + const mockexec = t.mock('../lib/index.js', { + '../lib/is-windows.js': false, + '../lib/run-script.js': (opt) => { + t.equal(opt.scriptShell, 'sh', 'should use expected shell value') + }, + }) + await mockexec({ args: [], runPath: t.testDirName }) + }) + + await t.test('win32 defined ComSpec env var', async t => { + t.plan(1) + const comspec = process.env.ComSpec + process.env.ComSpec = 'CMD' + const mockexec = t.mock('../lib/index.js', { + '../lib/is-windows.js': true, + '../lib/run-script.js': ({ scriptShell }) => { + t.equal(scriptShell, 'CMD', 'should use expected ComSpec value') + process.env.ComSpec = comspec + }, + }) + await mockexec({ args: [], runPath: t.testDirName }) + }) + + await t.test('win32 cmd', async t => { + t.plan(1) + const comspec = process.env.ComSpec + process.env.ComSpec = '' + const mockexec = t.mock('../lib/index.js', { + '../lib/is-windows.js': true, + '../lib/run-script.js': ({ scriptShell }) => { + t.equal(scriptShell, 'cmd', 'should use expected cmd default value') + process.env.ComSpec = comspec + }, + }) + await mockexec({ args: [], runPath: t.testDirName }) + }) +}) + +t.test('workspaces', async t => { + const { pkg, fixtures } = createPkg({ + name: '@npmcli/create-index', + localVersion: '2.0.0', + }) + + const { path, exec, chmod, binLinks, readOutput } = setup(t, { + pkg, + testdir: merge(fixtures, { + 'package.json': { + workspaces: ['a'], + dependencies: null, + }, + a: { + 'package.json': { + name: 'a', + version: '1.0.0', + dependencies: fixtures['package.json'].dependencies, + }, + }, + node_modules: { + a: t.fixture('symlink', '../a'), + }, + }), + }) + + await chmod() + await binLinks() + + // runs at the project level + await exec({ + args: ['create-index'], + localBin: resolve(path, 'node_modules/.bin'), + }) + + t.match(await readOutput(), { + value: 'local-2.0.0', + }) + + // runs at the child workspace level + await exec({ + args: ['create-index'], + localBin: resolve(path, 'a/node_modules/.bin'), + path: resolve(path, 'a'), + runPath: resolve(path, 'a'), + }) + + t.match(await readOutput('', { root: resolve(path, 'a') }), { + value: 'local-2.0.0', + }) +}) diff --git a/workspaces/libnpmexec/test/registry.js b/workspaces/libnpmexec/test/registry.js new file mode 100644 index 0000000000000..45d7cf4654541 --- /dev/null +++ b/workspaces/libnpmexec/test/registry.js @@ -0,0 +1,166 @@ +const { resolve } = require('path') +const t = require('tap') +const { setup, createPkg, merge } = require('./fixtures/setup.js') + +t.test('run from registry - no local packages', async t => { + const { fixtures, package } = createPkg({ versions: ['2.0.0'] }) + + const { exec, path, registry, readOutput } = setup(t, { + testdir: merge(fixtures, { + global: {}, + }), + }) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index'], + globalPath: resolve(path, 'global'), + }) + + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-2.0.0', + }) +}) + +t.test('run from registry - local version mismatch', async t => { + const { fixtures, package } = createPkg({ + localVersion: '2.0.0', + versions: ['2.0.0', '1.0.0'], + }) + + const { exec, path, registry, readOutput } = setup(t, { + testdir: { + ...fixtures, + }, + }) + + await package({ registry, path, tarballs: ['1.0.0'] }) + + await exec({ args: ['@npmcli/create-index@1.0.0'] }) + + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-1.0.0', + }) +}) + +t.test('run from registry - local range mismatch', async t => { + const { fixtures, package } = createPkg({ + localVersion: '2.0.0', + versions: ['2.0.0', '1.0.0'], + }) + + const { exec, path, registry, readOutput } = setup(t, { + testdir: { + ...fixtures, + }, + }) + + await package({ registry, path, tarballs: ['1.0.0'] }) + + await exec({ + args: ['@npmcli/create-index@^1.0.0'], + }) + + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-1.0.0', + }) +}) + +t.test('run from registry - local tag mismatch', async t => { + const { fixtures, package } = createPkg({ + localVersion: '2.0.0', + versions: ['2.0.0'], + }) + + const { exec, path, registry, readOutput } = setup(t, { + testdir: { + ...fixtures, + }, + }) + + await package({ registry, path }) + + await exec({ + args: ['@npmcli/create-index@latest'], + }) + + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-2.0.0', + }) +}) + +t.test('avoid install when exec from registry an available pkg', async t => { + const { fixtures, package } = createPkg({ + versions: ['2.0.0'], + }) + + const { exec, path, registry, readOutput, rmOutput } = setup(t, { + testdir: { + ...fixtures, + }, + }) + + await package({ registry, path }) + + // no file + t.rejects(() => readOutput('@npmcli-create-index'), { code: 'ENOENT' }) + + // file is created + await exec({ args: ['@npmcli/create-index'] }) + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-2.0.0', + }) + + // remove file + await rmOutput('@npmcli-create-index') + t.rejects(() => readOutput('@npmcli-create-index'), { code: 'ENOENT' }) + + // create file again but mock manifest only once + await package({ registry, path, tarballs: [], times: 1 }) + await exec({ args: ['@npmcli/create-index'] }) + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-2.0.0', + }) +}) + +t.test('run multiple from registry', async t => { + const indexPkg = createPkg({ + versions: ['2.0.0'], + name: '@npmcli/create-index', + }) + const testPkg = createPkg({ + versions: ['2.0.0'], + name: '@npmcli/create-test', + }) + + const { exec, path, registry, readOutput } = setup(t, { + testdir: { + ...merge(indexPkg.fixtures, testPkg.fixtures), + }, + }) + + await indexPkg.package({ registry, path }) + await testPkg.package({ registry, path }) + + t.rejects( + () => readOutput(resolve('@npmcli-create-index')), + { code: 'ENOENT' } + ) + t.rejects( + () => readOutput(resolve('@npmcli-create-test')), + { code: 'ENOENT' } + ) + + await exec({ + packages: ['@npmcli/create-test', '@npmcli/create-index'], + call: 'create-test && create-index', + }) + + t.match(await readOutput('@npmcli-create-index'), { + value: 'packages-2.0.0', + }) + t.match(await readOutput('@npmcli-create-test'), { + value: 'packages-2.0.0', + }) +}) diff --git a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index.json b/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index.json deleted file mode 100644 index 6118dec7dfd87..0000000000000 --- a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "_id": "@ruyadorno/create-index", - "name": "@ruyadorno/create-index", - "dist-tags": { - "latest": "1.0.0" - }, - "versions": { - "1.0.0": { - "name": "@ruyadorno/create-index", - "version": "1.0.0", - "description": "Create an empty index.js file", - "bin": { - "create-index": "create-index.js" - }, - "keywords": [ - "init", - "create", - "index" - ], - "author": { - "name": "Ruy Adorno", - "url": "https://ruyadorno.com/" - }, - "license": "MIT", - "gitHead": "0c1b6a4c503d8565439b2b194b4691824a1bc902", - "_id": "@ruyadorno/create-index@1.0.0", - "_nodeVersion": "15.13.0", - "_npmVersion": "7.9.0", - "dist": { - "integrity": "sha512-2T2JRYWtB9/wN8Vr/SRDcjIbKD5IjR5joO8iCCCYjXfDRZ2lYBSnZQ2kGp34F+T8OEavzJfj9sxNt9Y7QT7Oaw==", - "shasum": "a7d15d2ca78c496685b7b2bc24599d4e0983783c", - "tarball": "https://registry.npmjs.org/@ruyadorno/create-index/-/create-index-1.0.0.tgz", - "fileCount": 3, - "unpackedSize": 565, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgd0fRCRA9TVsSAnZWagAA9ysP/i22HySX0+RYcHUldWcv\neDgd24/wQqNEsQiTrGpIRSSorqbrC5+xoZfFzbvbUA24JaFChgQE1rRtYDab\ntjo5asfUqCspru1X05D3T3lmy3NyBCShqzwsZo88stj8L1w8DcnmU83als4h\n6DqxmwQbPMn+hd5gKtr6ZsUwHZRc/9dXWjn6GI3ztAla73RKXQ4D9Gs/ULyo\nNwS6a/CqThqu4atlA6ZGXum72XsFYSRB712N3Q1l0+8T9L3lAWuitGx/K8L/\n95gxU0e6ME+Wiin62SxH6QYWuVIKD04UNkz14dzfI2RIjT2NDbX6l308uSza\nbWz6aro4w9kUJviDX/hk/o469d+EQ87L+vpFrLDbSfZg8RtvSptHCDdM6mNw\n05xNFji33ujMX54HyGxplioAgnE5X2ZTQuBymsiINHq5gxCn8MSaUxiX45yB\n7Bhf1rWbp5KgiUa0kGXV4eoAutP6HWs1avzkHi9q2xS61wMBdPPHX5GsTTqe\nI+4mdgpNOdQLQjLyCp+ydvSqTHtVHkHDrBJzgkOjDWC7YzDcbzFQt6Fn6uc/\nA4kTlU1yTD2lPz9ICNI6BwqM7aOa9qCVkBL7vWaUUpxblRpzfbKmCtEi704h\nIJ6YZ3z6xwTl59aMXiInOLFsb7upEwtTXTAWqDlsJmTYS7hsVi3gY7wqYp1p\nMwwm\r\n=rrJ8\r\n-----END PGP SIGNATURE-----\r\n" - }, - "_npmUser": { - "name": "ruyadorno", - "email": "ruyadorno@hotmail.com" - }, - "directories": {}, - "maintainers": [ - { - "name": "ruyadorno", - "email": "ruyadorno@hotmail.com" - } - ], - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/create-index_1.0.0_1618429905498_0.11104270815832784" - }, - "_hasShrinkwrap": false - } - }, - "time": { - "created": "2021-04-14T19:51:45.442Z", - "1.0.0": "2021-04-14T19:51:45.650Z", - "modified": "2021-04-14T19:51:47.833Z" - }, - "maintainers": [ - { - "name": "ruyadorno", - "email": "ruyadorno@hotmail.com" - } - ], - "description": "Create an empty index.js file", - "keywords": [ - "init", - "create", - "index" - ], - "author": { - "name": "Ruy Adorno", - "url": "https://ruyadorno.com/" - }, - "license": "MIT", - "readme": "# create-index\n\nPuts an empty `index.js` into current working dir. Meant for testing only.\n\n## Usage\n\n`npm exec @ruyadorno/create-index`\n\n", - "readmeFilename": "README.md", - "_cached": false, - "_contentLength": 0 -} diff --git a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index.min.json b/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index.min.json deleted file mode 100644 index e4e998317585c..0000000000000 --- a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index.min.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@ruyadorno/create-index", - "dist-tags": { - "latest": "1.0.0" - }, - "versions": { - "1.0.0": { - "name": "@ruyadorno/create-index", - "version": "1.0.0", - "bin": { - "create-index": "create-index.js" - }, - "dist": { - "integrity": "sha512-2T2JRYWtB9/wN8Vr/SRDcjIbKD5IjR5joO8iCCCYjXfDRZ2lYBSnZQ2kGp34F+T8OEavzJfj9sxNt9Y7QT7Oaw==", - "shasum": "a7d15d2ca78c496685b7b2bc24599d4e0983783c", - "tarball": "https://registry.npmjs.org/@ruyadorno/create-index/-/create-index-1.0.0.tgz", - "fileCount": 3, - "unpackedSize": 565, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgd0fRCRA9TVsSAnZWagAA9ysP/i22HySX0+RYcHUldWcv\neDgd24/wQqNEsQiTrGpIRSSorqbrC5+xoZfFzbvbUA24JaFChgQE1rRtYDab\ntjo5asfUqCspru1X05D3T3lmy3NyBCShqzwsZo88stj8L1w8DcnmU83als4h\n6DqxmwQbPMn+hd5gKtr6ZsUwHZRc/9dXWjn6GI3ztAla73RKXQ4D9Gs/ULyo\nNwS6a/CqThqu4atlA6ZGXum72XsFYSRB712N3Q1l0+8T9L3lAWuitGx/K8L/\n95gxU0e6ME+Wiin62SxH6QYWuVIKD04UNkz14dzfI2RIjT2NDbX6l308uSza\nbWz6aro4w9kUJviDX/hk/o469d+EQ87L+vpFrLDbSfZg8RtvSptHCDdM6mNw\n05xNFji33ujMX54HyGxplioAgnE5X2ZTQuBymsiINHq5gxCn8MSaUxiX45yB\n7Bhf1rWbp5KgiUa0kGXV4eoAutP6HWs1avzkHi9q2xS61wMBdPPHX5GsTTqe\nI+4mdgpNOdQLQjLyCp+ydvSqTHtVHkHDrBJzgkOjDWC7YzDcbzFQt6Fn6uc/\nA4kTlU1yTD2lPz9ICNI6BwqM7aOa9qCVkBL7vWaUUpxblRpzfbKmCtEi704h\nIJ6YZ3z6xwTl59aMXiInOLFsb7upEwtTXTAWqDlsJmTYS7hsVi3gY7wqYp1p\nMwwm\r\n=rrJ8\r\n-----END PGP SIGNATURE-----\r\n" - } - } - }, - "modified": "2021-04-14T19:51:47.833Z", - "_cached": false, - "_contentLength": 1423 -} \ No newline at end of file diff --git a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index/-/create-index-1.0.0.tgz b/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index/-/create-index-1.0.0.tgz deleted file mode 100644 index d6ddf7570e3fc..0000000000000 Binary files a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-index/-/create-index-1.0.0.tgz and /dev/null differ diff --git a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test.json b/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test.json deleted file mode 100644 index d193b83cf25df..0000000000000 --- a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "_id": "@ruyadorno/create-test", - "name": "@ruyadorno/create-test", - "dist-tags": { - "latest": "1.0.0" - }, - "versions": { - "1.0.0": { - "name": "@ruyadorno/create-test", - "version": "1.0.0", - "description": "Creates an empty test.js file", - "bin": { - "create-test": "create-test.js" - }, - "keywords": [ - "init", - "create", - "test" - ], - "author": { - "name": "Ruy Adorno", - "url": "https://ruyadorno.com/" - }, - "license": "MIT", - "gitHead": "707aa293e34f48dcf9cb6b4b452cb1fc8e484c8b", - "_id": "@ruyadorno/create-test@1.0.0", - "_nodeVersion": "15.13.0", - "_npmVersion": "7.9.0", - "dist": { - "integrity": "sha512-WOifELHCU8nmg0yHsPbSETPaNO1orDPhTSflJsomqGFNwVS44qvkWwMPbDE3L2aAglXLf5AxUznyFkxsXgDF2w==", - "shasum": "f0f393449fe5205c54a4ca2181d8355d2372da93", - "tarball": "https://registry.npmjs.org/@ruyadorno/create-test/-/create-test-1.0.0.tgz", - "fileCount": 3, - "unpackedSize": 557, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgd1SICRA9TVsSAnZWagAAOa4P/jknjgmFaBWz6PCng8qV\nsdfa23GbE4MdmvpB72v6DvNjGQ+51Vgd7PBAJRo+d3LmQ0c2DE/e6PZEgam/\nOtuVbgimxPy85V1MTA66bgML4nFtEOKS/R/Z5s7wMMCrhYqKdMp6ELMUEO07\n7cDIzAmc7WeSLyzhTBC661T0nKPPAf2nKKYXLI+6RisQoXnEgZmgNyNlIt6D\nNDNTRZjaR6s1QvHgWN9h/hLAgKvgaAnSy+JOzcB+SGaClLow3svbvW+klQpA\n8afOTLV4D/pgPDGXvvwDDInH6yccYSOSNiAZgd45hsmo82xIR3n+Cod2qk9Y\njCye36nXzdQTz9A7a3SgH++DV7fA5n87GoahkpGEnKu8gjgMuE6ncDEypbTi\nM4R8JikZrScR2wWXtO+jK4f/5XHVh19ZpqdOrlxzXutkUy0/bMoHFNxcGrXB\n5D1Qk/lOpNO4rd0NoURk6OkpueHOlBHlBNxqrEsltzY2IWs+JICcFaz385H0\nKYyNQrmltEqWVgW+LeFvm3B1sLL5wySqplX/396lC6kCHZyofeeqZFcC1G+m\ntkp0iho63tlm6WjIzw6ddHWu8olNohCk4xFpvNkkZ0u9GR4BaDBRXS60AcoD\nNIYwMuUlqmXAc7ey+xNZCqXokgbtjD7aI2uIDLNUMHELxrRzBccHe76sIQit\nBeBy\r\n=u7P4\r\n-----END PGP SIGNATURE-----\r\n" - }, - "_npmUser": { - "name": "ruyadorno", - "email": "ruyadorno@hotmail.com" - }, - "directories": {}, - "maintainers": [ - { - "name": "ruyadorno", - "email": "ruyadorno@hotmail.com" - } - ], - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/create-test_1.0.0_1618433159830_0.5969279363908722" - }, - "_hasShrinkwrap": false - } - }, - "time": { - "created": "2021-04-14T20:45:59.789Z", - "1.0.0": "2021-04-14T20:45:59.974Z", - "modified": "2021-04-14T20:46:02.139Z" - }, - "maintainers": [ - { - "name": "ruyadorno", - "email": "ruyadorno@hotmail.com" - } - ], - "description": "Creates an empty test.js file", - "keywords": [ - "init", - "create", - "test" - ], - "author": { - "name": "Ruy Adorno", - "url": "https://ruyadorno.com/" - }, - "license": "MIT", - "readme": "# create-test\n\nPuts an empty `test.js` into current working dir. Meant for testing only.\n\n## Usage\n\n`npm exec @ruyadorno/create-test`\n\n", - "readmeFilename": "README.md", - "_cached": false, - "_contentLength": 0 -} \ No newline at end of file diff --git a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test.min.json b/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test.min.json deleted file mode 100644 index cc15084158717..0000000000000 --- a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test.min.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "@ruyadorno/create-test", - "dist-tags": { - "latest": "1.0.0" - }, - "versions": { - "1.0.0": { - "name": "@ruyadorno/create-test", - "version": "1.0.0", - "bin": { - "create-test": "create-test.js" - }, - "dist": { - "integrity": "sha512-WOifELHCU8nmg0yHsPbSETPaNO1orDPhTSflJsomqGFNwVS44qvkWwMPbDE3L2aAglXLf5AxUznyFkxsXgDF2w==", - "shasum": "f0f393449fe5205c54a4ca2181d8355d2372da93", - "tarball": "https://registry.npmjs.org/@ruyadorno/create-test/-/create-test-1.0.0.tgz", - "fileCount": 3, - "unpackedSize": 557, - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgd1SICRA9TVsSAnZWagAAOa4P/jknjgmFaBWz6PCng8qV\nsdfa23GbE4MdmvpB72v6DvNjGQ+51Vgd7PBAJRo+d3LmQ0c2DE/e6PZEgam/\nOtuVbgimxPy85V1MTA66bgML4nFtEOKS/R/Z5s7wMMCrhYqKdMp6ELMUEO07\n7cDIzAmc7WeSLyzhTBC661T0nKPPAf2nKKYXLI+6RisQoXnEgZmgNyNlIt6D\nNDNTRZjaR6s1QvHgWN9h/hLAgKvgaAnSy+JOzcB+SGaClLow3svbvW+klQpA\n8afOTLV4D/pgPDGXvvwDDInH6yccYSOSNiAZgd45hsmo82xIR3n+Cod2qk9Y\njCye36nXzdQTz9A7a3SgH++DV7fA5n87GoahkpGEnKu8gjgMuE6ncDEypbTi\nM4R8JikZrScR2wWXtO+jK4f/5XHVh19ZpqdOrlxzXutkUy0/bMoHFNxcGrXB\n5D1Qk/lOpNO4rd0NoURk6OkpueHOlBHlBNxqrEsltzY2IWs+JICcFaz385H0\nKYyNQrmltEqWVgW+LeFvm3B1sLL5wySqplX/396lC6kCHZyofeeqZFcC1G+m\ntkp0iho63tlm6WjIzw6ddHWu8olNohCk4xFpvNkkZ0u9GR4BaDBRXS60AcoD\nNIYwMuUlqmXAc7ey+xNZCqXokgbtjD7aI2uIDLNUMHELxrRzBccHe76sIQit\nBeBy\r\n=u7P4\r\n-----END PGP SIGNATURE-----\r\n" - } - } - }, - "modified": "2021-04-14T20:46:02.139Z", - "_cached": false, - "_contentLength": 1417 -} \ No newline at end of file diff --git a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test/-/create-test-1.0.0.tgz b/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test/-/create-test-1.0.0.tgz deleted file mode 100644 index 34a85702055f3..0000000000000 Binary files a/workspaces/libnpmexec/test/registry/content/ruyadorno/create-test/-/create-test-1.0.0.tgz and /dev/null differ diff --git a/workspaces/libnpmexec/test/registry/server.js b/workspaces/libnpmexec/test/registry/server.js deleted file mode 100644 index f35acfdeb2e5a..0000000000000 --- a/workspaces/libnpmexec/test/registry/server.js +++ /dev/null @@ -1,280 +0,0 @@ -const { join, dirname } = require('path') -const { existsSync, readFileSync, writeFileSync } = require('fs') -const PORT = 12345 + (+process.env.TAP_CHILD_ID || 0) -const http = require('http') -const https = require('https') - -const mkdirp = require('mkdirp') -const doProxy = process.env.ARBORIST_TEST_PROXY -const missing = /\/@isaacs(\/|%2[fF])(this-does-not-exist-at-all|testing-missing-tgz\/-\/)/ -const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' -const { gzipSync, unzipSync } = require('zlib') - -let advisoryBulkResponse = null -let failAdvisoryBulk = false -let auditResponse = null -let failAudit = false -const startServer = cb => { - const server = module.exports.server = http.createServer((req, res) => { - res.setHeader('connection', 'close') - - if (req.url === '/-/npm/v1/security/advisories/bulk') { - const body = [] - req.on('data', c => body.push(c)) - req.on('end', () => { - res.setHeader('connection', 'close') - if (failAdvisoryBulk) { - res.statusCode = 503 - return res.end('no advisory bulk for you') - } - if (!advisoryBulkResponse) { - if (auditResponse && !failAudit) { - // simulate what the registry does when quick audits are allowed, - // but advisory bulk requests are not - res.statusCode = 405 - return res.end(JSON.stringify({ - code: 'MethodNotAllowedError', - message: 'POST is not allowed', - })) - } else { - res.statusCode = 404 - return res.end('not found') - } - } - if (doProxy && !existsSync(advisoryBulkResponse)) { - // hit the main registry, then fall back to staging for now - // XXX: remove this when bulk advisory endpoint pushed to production! - const opts = { - host: 'registry.npmjs.org', - method: req.method, - path: req.url, - headers: { - ...req.headers, - accept: '*', - host: 'registry.npmjs.org', - connection: 'close', - 'if-none-match': '', - }, - } - const handleUpstream = upstream => { - res.statusCode = upstream.statusCode - if (upstream.statusCode >= 300 || upstream.statusCode < 200) { - console.error('UPSTREAM ERROR', upstream.statusCode) - return upstream.pipe(res) - } - res.setHeader('content-encoding', upstream.headers['content-encoding']) - const file = advisoryBulkResponse - console.error('PROXY', `${req.url} -> ${file} ${upstream.statusCode}`) - mkdirp.sync(dirname(file)) - const data = [] - upstream.on('end', () => { - const out = Buffer.concat(data) - const obj = JSON.parse(unzipSync(out).toString()) - writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n') - res.end(out) - }) - upstream.on('data', c => data.push(c)) - } - return https.request(opts).on('response', upstream => { - if (upstream.statusCode !== 200) { - console.error('ATTEMPTING TO PROXY FROM STAGING') - console.error('NOTE: THIS WILL FAIL WHEN NOT ON VPN!') - opts.host = 'security-microservice-3-west.npm.red' - opts.headers.host = opts.host - opts.path = '/v1/advisories/bulk' - https.request(opts) - .on('response', r => handleUpstream(r)) - .end(Buffer.concat(body)) - } else { - handleUpstream(upstream) - } - }).end(Buffer.concat(body)) - } else { - res.setHeader('content-encoding', 'gzip') - res.end(gzipSync(readFileSync(advisoryBulkResponse))) - } - }) - return - } else if (req.url === '/-/npm/v1/security/audits/quick') { - const body = [] - req.on('data', c => body.push(c)) - req.on('end', () => { - res.setHeader('connection', 'close') - if (failAudit) { - res.statusCode = 503 - return res.end('no audit for you') - } - if (!auditResponse) { - res.statusCode = 404 - return res.end('not found') - } - if (doProxy && !existsSync(auditResponse)) { - return https.request({ - host: 'registry.npmjs.org', - method: req.method, - path: req.url, - headers: { - ...req.headers, - accept: '*', - host: 'registry.npmjs.org', - connection: 'close', - 'if-none-match': '', - }, - }).on('response', upstream => { - res.statusCode = upstream.statusCode - if (upstream.statusCode >= 300 || upstream.statusCode < 200) { - console.error('UPSTREAM ERROR', upstream.statusCode) - // don't save if it's not a valid response - return upstream.pipe(res) - } - res.setHeader('content-encoding', upstream.headers['content-encoding']) - const file = auditResponse - console.error('PROXY', `${req.url} -> ${file} ${upstream.statusCode}`) - mkdirp.sync(dirname(file)) - const data = [] - upstream.on('end', () => { - const out = Buffer.concat(data) - // make it a bit prettier to read later - const obj = JSON.parse(unzipSync(out).toString()) - writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n') - res.end(out) - }) - upstream.on('data', c => data.push(c)) - }).end(Buffer.concat(body)) - } else { - res.setHeader('content-encoding', 'gzip') - res.end(gzipSync(readFileSync(auditResponse))) - } - }) - return - } - - const f = join(__dirname, 'content', join('/', req.url.replace(/@/, '').replace(/%2f/i, '/'))) - const isCorgi = req.headers.accept.includes('application/vnd.npm.install-v1+json') - const file = f + ( - isCorgi && existsSync(`${f}.min.json`) ? '.min.json' - : existsSync(`${f}.json`) ? '.json' - : existsSync(`${f}/index.json`) ? 'index.json' - : '' - ) - - try { - const body = readFileSync(file) - res.setHeader('content-length', body.length) - res.setHeader('content-type', /\.min\.json$/.test(file) ? corgiDoc - : /\.json$/.test(file) ? 'application/json' - : 'application/octet-stream') - res.end(body) - } catch (er) { - // testing things going missing from the registry somehow - if (missing.test(req.url)) { - res.statusCode = 404 - res.end('{"error": "not found"}') - return - } - - if (doProxy) { - return https.get({ - host: 'registry.npmjs.org', - path: req.url, - headers: { - ...req.headers, - accept: '*', - 'accept-encoding': 'identity', - host: 'registry.npmjs.org', - connection: 'close', - 'if-none-match': '', - }, - }).on('response', upstream => { - const errorStatus = - upstream.statusCode >= 300 || upstream.statusCode < 200 - - if (errorStatus) { - console.error('UPSTREAM ERROR', upstream.statusCode) - } - - const ct = upstream.headers['content-type'] - const isJson = ct.includes('application/json') - const proxyFile = isJson ? f + '.json' : f - console.error('PROXY', `${req.url} -> ${proxyFile} ${ct}`) - mkdirp.sync(dirname(proxyFile)) - const data = [] - res.statusCode = upstream.statusCode - res.setHeader('content-type', ct) - upstream.on('end', () => { - console.error('ENDING', req.url) - const out = Buffer.concat(data) - if (!errorStatus) { - if (isJson) { - const obj = JSON.parse(out.toString()) - writeFileSync(proxyFile, JSON.stringify(obj, 0, 2) + '\n') - const mrm = require('minify-registry-metadata') - const minFile = proxyFile.replace(/\.json$/, '.min.json') - writeFileSync(minFile, JSON.stringify(mrm(obj), 0, 2) + '\n') - console.error('WROTE JSONS', [proxyFile, minFile]) - } else { - writeFileSync(proxyFile, out) - } - } - res.end(out) - }) - upstream.on('data', c => data.push(c)) - }).end() - } - - res.statusCode = er.code === 'ENOENT' ? 404 : 500 - if (res.method === 'GET') { - console.error(er) - } - res.setHeader('content-type', 'text/plain') - res.end(er.stack) - } - }) - server.listen(PORT, cb) -} - -module.exports = t => startServer(() => { - t.parent.teardown(() => module.exports.server.close()) - t.end() -}) - -module.exports.auditResponse = value => { - if (auditResponse && auditResponse !== value) { - throw new Error('setting audit response, but already set\n' + - '(did you forget to call the returned function on teardown?)') - } - auditResponse = value - return () => auditResponse = null -} -module.exports.failAudit = () => { - failAudit = true - return () => failAudit = false -} - -module.exports.advisoryBulkResponse = value => { - if (advisoryBulkResponse && advisoryBulkResponse !== value) { - throw new Error('setting advisory bulk response, but already set\n' + - '(did you forget to call the returned function on teardown?)') - } - advisoryBulkResponse = value - return () => advisoryBulkResponse = null -} -module.exports.failAdvisoryBulk = () => { - failAdvisoryBulk = true - return () => failAdvisoryBulk = false -} - -module.exports.registry = `http://localhost:${PORT}/` - -module.exports.start = startServer -module.exports.stop = () => module.exports.server.close() - -if (require.main === module) { - startServer(() => { - console.log(`Mock registry live at: - ${module.exports.registry} -Press ^D to close gracefully.`) - }) - process.openStdin() - process.stdin.on('end', () => module.exports.server.close()) -} diff --git a/workspaces/libnpmfund/CHANGELOG.md b/workspaces/libnpmfund/CHANGELOG.md index 06b757c833fee..0cc5aa0d69616 100644 --- a/workspaces/libnpmfund/CHANGELOG.md +++ b/workspaces/libnpmfund/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [4.0.5](https://github.com/npm/cli/compare/libnpmfund-v4.0.4...libnpmfund-v4.0.5) (2022-11-30) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.1.3...arborist-v6.1.4): `@npmcli/arborist@6.1.4` + ## [4.0.4](https://github.com/npm/cli/compare/libnpmfund-v4.0.3...libnpmfund-v4.0.4) (2022-11-16) ### Dependencies diff --git a/workspaces/libnpmfund/package.json b/workspaces/libnpmfund/package.json index 61324e2b3e8ff..ab7879ae0564f 100644 --- a/workspaces/libnpmfund/package.json +++ b/workspaces/libnpmfund/package.json @@ -1,6 +1,6 @@ { "name": "libnpmfund", - "version": "4.0.4", + "version": "4.0.5", "main": "lib/index.js", "files": [ "bin/", @@ -46,7 +46,7 @@ "tap": "^16.0.1" }, "dependencies": { - "@npmcli/arborist": "^6.1.3" + "@npmcli/arborist": "^6.1.4" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" diff --git a/workspaces/libnpmpack/CHANGELOG.md b/workspaces/libnpmpack/CHANGELOG.md index f8df27b8857ab..ae6a0e1a31598 100644 --- a/workspaces/libnpmpack/CHANGELOG.md +++ b/workspaces/libnpmpack/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [5.0.5](https://github.com/npm/cli/compare/libnpmpack-v5.0.4...libnpmpack-v5.0.5) (2022-11-30) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/arborist-v6.1.3...arborist-v6.1.4): `@npmcli/arborist@6.1.4` + ## [5.0.4](https://github.com/npm/cli/compare/libnpmpack-v5.0.3...libnpmpack-v5.0.4) (2022-11-16) ### Dependencies diff --git a/workspaces/libnpmpack/package.json b/workspaces/libnpmpack/package.json index 1c2eff2465e98..564b0cc039775 100644 --- a/workspaces/libnpmpack/package.json +++ b/workspaces/libnpmpack/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpack", - "version": "5.0.4", + "version": "5.0.5", "description": "Programmatic API for the bits behind npm pack", "author": "GitHub Inc.", "main": "lib/index.js", @@ -36,7 +36,7 @@ "bugs": "https://github.com/npm/libnpmpack/issues", "homepage": "https://npmjs.com/package/libnpmpack", "dependencies": { - "@npmcli/arborist": "^6.1.3", + "@npmcli/arborist": "^6.1.4", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.0.0", "pacote": "^15.0.2" diff --git a/workspaces/libnpmpublish/CHANGELOG.md b/workspaces/libnpmpublish/CHANGELOG.md index c19bafd2265ea..026689f2cc196 100644 --- a/workspaces/libnpmpublish/CHANGELOG.md +++ b/workspaces/libnpmpublish/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [7.0.5](https://github.com/npm/cli/compare/libnpmpublish-v7.0.4...libnpmpublish-v7.0.5) (2022-11-30) + +### Dependencies + +* [Workspace](https://github.com/npm/cli/compare/libnpmpack-v5.0.4...libnpmpack-v5.0.5): `libnpmpack@5.0.5` + ## [7.0.4](https://github.com/npm/cli/compare/libnpmpublish-v7.0.3...libnpmpublish-v7.0.4) (2022-11-16) ### Dependencies diff --git a/workspaces/libnpmpublish/package.json b/workspaces/libnpmpublish/package.json index 5445ac14b76fa..09798c8336cbf 100644 --- a/workspaces/libnpmpublish/package.json +++ b/workspaces/libnpmpublish/package.json @@ -1,6 +1,6 @@ { "name": "libnpmpublish", - "version": "7.0.4", + "version": "7.0.5", "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": "^4.0.0", "@npmcli/template-oss": "4.10.0", - "libnpmpack": "^5.0.4", + "libnpmpack": "^5.0.5", "lodash.clonedeep": "^4.5.0", "nock": "^13.2.4", "tap": "^16.0.1"