From e30bec87ad5a2f9773c72c087b2eb3d317a0ec33 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 24 Feb 2024 15:51:22 +0100 Subject: [PATCH 1/7] test: add tests for custom registries with auth --- sources/httpUtils.ts | 13 +++++ tests/_registryServer.mjs | 109 ++++++++++++++++++++++++++++++++++++++ tests/_runCli.ts | 6 ++- tests/main.test.ts | 34 ++++++++++++ 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 tests/_registryServer.mjs diff --git a/sources/httpUtils.ts b/sources/httpUtils.ts index f88f752a..fe1fddc1 100644 --- a/sources/httpUtils.ts +++ b/sources/httpUtils.ts @@ -33,6 +33,19 @@ export async function fetch(input: string | URL, init?: RequestInit) { dispatcher: agent, }); } catch (error) { + if (error?.message?.includes?.(`Request cannot be constructed from a URL that includes credentials`)) { + const url = new URL(input as string); + const authorization = `Bearer ${Buffer.from(`${url.username}:${url.password}`).toString(`base64`)}`; + url.username = ``; + url.password = ``; + return fetch(url, { + ...init, + headers: { + ...init?.headers, + authorization, + }, + }); + } throw new Error( `Error when performing the request to ${input}; for troubleshooting help, see https://github.com/nodejs/corepack#troubleshooting`, {cause: error}, diff --git a/tests/_registryServer.mjs b/tests/_registryServer.mjs new file mode 100644 index 00000000..5925478f --- /dev/null +++ b/tests/_registryServer.mjs @@ -0,0 +1,109 @@ +import {createHash} from 'node:crypto'; +import {once} from 'node:events'; +import {createServer} from 'node:http'; +import {gzipSync} from 'node:zlib'; + +function createSimpleTarArchive(fileName, fileContent, mode = 0o644) { + const contentBuffer = Buffer.from(fileContent); + + const header = Buffer.alloc(512); // TAR headers are 512 bytes + header.write(fileName); + header.write(`100${mode.toString(8)} `, 100, 7, `utf-8`); // File mode (octal) followed by a space + header.write(`0001750 `, 108, 8, `utf-8`); // Owner's numeric user ID (octal) followed by a space + header.write(`0001750 `, 116, 8, `utf-8`); // Group's numeric user ID (octal) followed by a space + header.write(`${contentBuffer.length.toString(8)} `, 124, 12, `utf-8`); // File size in bytes (octal) followed by a space + header.write(`${Math.floor(Date.now() / 1000).toString(8)} `, 136, 12, `utf-8`); // Last modification time in numeric Unix time format (octal) followed by a space + header.fill(` `, 148, 156); // Fill checksum area with spaces for calculation + header.write(`ustar `, 257, 8, `utf-8`); // UStar indicator + + // Calculate and write the checksum. Note: This is a simplified calculation not recommended for production + const checksum = header.reduce((sum, value) => sum + value, 0); + header.write(`${checksum.toString(8)}\0 `, 148, 8, `utf-8`); // Write checksum in octal followed by null and space + + + return Buffer.concat([ + header, + contentBuffer, + Buffer.alloc(512 - (contentBuffer.length % 512)), + ]); +} + +const mockPackageTarGz = gzipSync(Buffer.concat([ + createSimpleTarArchive(`package/bin/pnpm.js`, `#!/usr/bin/env node\nconsole.log("pnpm: Hello from custom registry");\n`, 0o755), + createSimpleTarArchive(`package/bin/yarn.js`, `#!/usr/bin/env node\nconsole.log("yarn: Hello from custom registry");\n`, 0o755), + createSimpleTarArchive(`package/package.json`, JSON.stringify({bin: {yarn: `bin/yarn.js`, pnpm: `bin/pnpm.js`}})), + Buffer.alloc(1024), +])); +const shasum = createHash(`sha1`).update(mockPackageTarGz).digest(`hex`); + + +const server = createServer((req, res) => { + const auth = req.headers.authorization; + if (!auth?.startsWith(`Bearer `) || Buffer.from(auth.slice(`Bearer `.length), `base64`).toString() !== `user:pass`) { + res.statusCode = 401; + res.end(`Unauthorized`); + return; + } + switch (req.url) { + case `/yarn`: { + res.end(JSON.stringify({"dist-tags": { + latest: `1.9998.9999`, + }, versions: {'1.9998.9999': { + dist: { + shasum, + size: mockPackageTarGz.length, + noattachment: false, + tarball: `${process.env.COREPACK_NPM_REGISTRY}/yarn.tgz`, + }, + }}})); + break; + } + + case `/pnpm`: { + res.end(JSON.stringify({"dist-tags": { + latest: `1.9998.9999`, + }, versions: {'1.9998.9999': { + dist: { + shasum, + size: mockPackageTarGz.length, + noattachment: false, + tarball: `${process.env.COREPACK_NPM_REGISTRY}/pnpm/-/pnpm-1.9998.9999.tgz`, + }, + }}})); + break; + } + + case `/@yarnpkg/cli-dist`: { + res.end(JSON.stringify({"dist-tags": { + latest: `5.9999.9999`, + }, versions: {'5.9999.9999': { + bin: { + yarn: `./bin/yarn.js`, + yarnpkg: `./bin/yarn.js`, + }, + dist: { + shasum, + size: mockPackageTarGz.length, + noattachment: false, + tarball: `${process.env.COREPACK_NPM_REGISTRY}/yarn.tgz`, + }, + }}})); + break; + } + + case `/pnpm/-/pnpm-1.9998.9999.tgz`: + case `/yarn.tgz`: + res.end(mockPackageTarGz); + break; + + default: + throw new Error(`unsupported request`, {cause: req.url}); + } +}).listen(0, `localhost`); + +await once(server, `listening`); + +const {address, port} = server.address(); +process.env.COREPACK_NPM_REGISTRY = `http://user:pass@${address.includes(`:`) ? `[${address}]` : address}:${port}`; + +server.unref(); diff --git a/tests/_runCli.ts b/tests/_runCli.ts index e028af75..4cc22216 100644 --- a/tests/_runCli.ts +++ b/tests/_runCli.ts @@ -1,14 +1,16 @@ import {PortablePath, npath} from '@yarnpkg/fslib'; import {spawn} from 'child_process'; +import * as path from 'path'; +import {pathToFileURL} from 'url'; -export async function runCli(cwd: PortablePath, argv: Array): Promise<{exitCode: number | null, stdout: string, stderr: string}> { +export async function runCli(cwd: PortablePath, argv: Array, withCustomRegistry?: boolean): Promise<{exitCode: number | null, stdout: string, stderr: string}> { const out: Array = []; const err: Array = []; return new Promise((resolve, reject) => { if (process.env.RUN_CLI_ID) (process.env.RUN_CLI_ID as any)++; - const child = spawn(process.execPath, [`--no-warnings`, `-r`, require.resolve(`./recordRequests.js`), require.resolve(`../dist/corepack.js`), ...argv], { + const child = spawn(process.execPath, [`--no-warnings`, `-r`, require.resolve(`./recordRequests.js`), ...(withCustomRegistry ? [`--import`, pathToFileURL(path.join(__dirname, `_registryServer.mjs`))] : []), require.resolve(`../dist/corepack.js`), ...argv], { cwd: npath.fromPortablePath(cwd), env: process.env, stdio: `pipe`, diff --git a/tests/main.test.ts b/tests/main.test.ts index b874ac65..ac4aa060 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -758,3 +758,37 @@ it(`should be able to show the latest version`, async () => { }); }); }); + +it(`should download yarn classic from custom registry with auth`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `yarn: Hello from custom registry\n`, + stderr: ``, + }); + }); +}); + +it(`should download yarn berry from custom registry with auth`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@3.0.0`, + }); + + await expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `yarn: Hello from custom registry\n`, + stderr: ``, + }); + }); +}); + +it(`should download pnpm from custom registry with auth`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: ``, + }); + }); +}); From aa25d622fd250b40c419888b138a9e95727cf54e Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 16 Mar 2024 18:32:34 +0100 Subject: [PATCH 2/7] add support for custom URLs --- sources/corepackUtils.ts | 6 ++++++ tests/_registryServer.mjs | 21 ++++++++++++++++++++- tests/main.test.ts | 10 ++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/sources/corepackUtils.ts b/sources/corepackUtils.ts index 9d17342a..b2ddd261 100644 --- a/sources/corepackUtils.ts +++ b/sources/corepackUtils.ts @@ -160,6 +160,12 @@ export async function installVersion(installTarget: string, locator: Locator, {s defaultNpmRegistryURL; } else { url = decodeURIComponent(version); + if (process.env.COREPACK_NPM_REGISTRY && url.startsWith(npmRegistryUtils.DEFAULT_NPM_REGISTRY_URL)) { + url = url.replace( + npmRegistryUtils.DEFAULT_NPM_REGISTRY_URL, + () => process.env.COREPACK_NPM_REGISTRY!, + ); + } } // Creating a temporary folder inside the install folder means that we diff --git a/tests/_registryServer.mjs b/tests/_registryServer.mjs index 5925478f..db9c00fb 100644 --- a/tests/_registryServer.mjs +++ b/tests/_registryServer.mjs @@ -29,9 +29,10 @@ function createSimpleTarArchive(fileName, fileContent, mode = 0o644) { } const mockPackageTarGz = gzipSync(Buffer.concat([ + createSimpleTarArchive(`package/bin/customPkgManager.js`, `#!/usr/bin/env node\nconsole.log("customPkgManager: Hello from custom registry");\n`, 0o755), createSimpleTarArchive(`package/bin/pnpm.js`, `#!/usr/bin/env node\nconsole.log("pnpm: Hello from custom registry");\n`, 0o755), createSimpleTarArchive(`package/bin/yarn.js`, `#!/usr/bin/env node\nconsole.log("yarn: Hello from custom registry");\n`, 0o755), - createSimpleTarArchive(`package/package.json`, JSON.stringify({bin: {yarn: `bin/yarn.js`, pnpm: `bin/pnpm.js`}})), + createSimpleTarArchive(`package/package.json`, JSON.stringify({bin: {yarn: `bin/yarn.js`, pnpm: `bin/pnpm.js`, customPkgManager: `bin/customPkgManager.js`}})), Buffer.alloc(1024), ])); const shasum = createHash(`sha1`).update(mockPackageTarGz).digest(`hex`); @@ -91,8 +92,26 @@ const server = createServer((req, res) => { break; } + case `/customPkgManager`: { + res.end(JSON.stringify({"dist-tags": { + latest: `1.0.0`, + }, versions: {'1.0.0': { + bin: { + customPkgManager: `./bin/customPkgManager.js`, + }, + dist: { + shasum, + size: mockPackageTarGz.length, + noattachment: false, + tarball: `${process.env.COREPACK_NPM_REGISTRY}/customPkgManager/-/customPkgManager-1.0.0.tgz`, + }, + }}})); + break; + } + case `/pnpm/-/pnpm-1.9998.9999.tgz`: case `/yarn.tgz`: + case `/customPkgManager/-/customPkgManager-1.0.0.tgz`: res.end(mockPackageTarGz); break; diff --git a/tests/main.test.ts b/tests/main.test.ts index ac4aa060..5e8ec552 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -792,3 +792,13 @@ it(`should download pnpm from custom registry with auth`, async () => { }); }); }); + +it(`should download custom package manager from custom registry with auth`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`customPkgManager@https://registry.npmjs.org/customPkgManager/-/customPkgManager-1.0.0.tgz`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `customPkgManager: Hello from custom registry\n`, + stderr: ``, + }); + }); +}); From 0733180ac2281947e6671eb45776cdb12ccbfe21 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 17 Mar 2024 13:37:10 +0100 Subject: [PATCH 3/7] add more tests --- tests/_registryServer.mjs | 19 +- tests/_runCli.ts | 2 +- tests/main.test.ts | 1564 +++++++++++++++++++------------------ 3 files changed, 805 insertions(+), 780 deletions(-) diff --git a/tests/_registryServer.mjs b/tests/_registryServer.mjs index db9c00fb..759e35e7 100644 --- a/tests/_registryServer.mjs +++ b/tests/_registryServer.mjs @@ -123,6 +123,23 @@ const server = createServer((req, res) => { await once(server, `listening`); const {address, port} = server.address(); -process.env.COREPACK_NPM_REGISTRY = `http://user:pass@${address.includes(`:`) ? `[${address}]` : address}:${port}`; +switch (process.env.AUTH_TYPE) { + case `COREPACK_NPM_REGISTRY`: + process.env.COREPACK_NPM_REGISTRY = `http://user:pass@${address.includes(`:`) ? `[${address}]` : address}:${port}`; + break; + + case `COREPACK_NPM_TOKEN`: + process.env.COREPACK_NPM_REGISTRY = `http://${address.includes(`:`) ? `[${address}]` : address}:${port}`; + process.env.COREPACK_NPM_TOKEN = Buffer.from(`user:pass`).toString(`base64`); + break; + + case `COREPACK_NPM_PASSWORD`: + process.env.COREPACK_NPM_REGISTRY = `http://${address.includes(`:`) ? `[${address}]` : address}:${port}`; + process.env.COREPACK_NPM_USER = `user`; + process.env.COREPACK_NPM_PASSWORD = `pass`; + break; + + default: throw new Error(`Invalid AUTH_TYPE in env`, {cause: process.env.AUTH_TYPE}); +} server.unref(); diff --git a/tests/_runCli.ts b/tests/_runCli.ts index 4cc22216..3710691f 100644 --- a/tests/_runCli.ts +++ b/tests/_runCli.ts @@ -10,7 +10,7 @@ export async function runCli(cwd: PortablePath, argv: Array, withCustomR return new Promise((resolve, reject) => { if (process.env.RUN_CLI_ID) (process.env.RUN_CLI_ID as any)++; - const child = spawn(process.execPath, [`--no-warnings`, `-r`, require.resolve(`./recordRequests.js`), ...(withCustomRegistry ? [`--import`, pathToFileURL(path.join(__dirname, `_registryServer.mjs`))] : []), require.resolve(`../dist/corepack.js`), ...argv], { + const child = spawn(process.execPath, [`--no-warnings`, ...(withCustomRegistry ? [`--import`, pathToFileURL(path.join(__dirname, `_registryServer.mjs`)) as any as string] : [`-r`, require.resolve(`./recordRequests.js`)]), require.resolve(`../dist/corepack.js`), ...argv], { cwd: npath.fromPortablePath(cwd), env: process.env, stdio: `pipe`, diff --git a/tests/main.test.ts b/tests/main.test.ts index 5e8ec552..6afc58cd 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1,4 +1,4 @@ -import {beforeEach, it, expect} from '@jest/globals'; +import {beforeEach, it, expect, describe} from '@jest/globals'; import {Filename, ppath, xfs, npath, PortablePath} from '@yarnpkg/fslib'; import process from 'node:process'; @@ -14,791 +14,799 @@ beforeEach(async () => { process.env.COREPACK_DEFAULT_TO_LATEST = `0`; }); -it(`should refuse to download a package manager if the hash doesn't match`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.22.4+sha1.deadbeef`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - stdout: /Mismatch hashes/, - }); - }); -}); - -it(`should refuse to download a known package manager from a URL`, async () => { - await xfs.mktempPromise(async cwd => { - // Package managers known by Corepack cannot be loaded from a URL. - await expect(runCli(cwd, [`yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - stdout: /Illegal use of URL for known package manager/, - }); - - // Unknown package managers can be loaded from a URL. - await expect(runCli(cwd, [`corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `0.24.1\n`, - }); - }); -}); - -it.failing(`should refuse to download a known package manager from a URL in package.json`, async () => { - await xfs.mktempPromise(async cwd => { - // Package managers known by Corepack cannot be loaded from a URL. - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - stdout: /Illegal use of URL for known package manager/, - }); - - // Unknown package managers can be loaded from a URL. - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, - }); - - await expect(runCli(cwd, [`corepack`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `0.24.1\n`, - }); - }); -}); - -it(`should require a version to be specified`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - stdout: /expected a semver version/, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@stable`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - stdout: /expected a semver version/, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@^1.0.0`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - stdout: /expected a semver version/, - }); - }); -}); - -const testedPackageManagers: Array<[string, string] | [string, string, string]> = [ - [`yarn`, `1.22.4`], - [`yarn`, `1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`], - [`yarn`, `1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`], - [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `1.22.21`], - [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz#sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72`, `1.22.21`], - [`yarn`, `2.0.0-rc.30`], - [`yarn`, `2.0.0-rc.30+sha1.4f0423b01bcb57f8e390b4e0f1990831f92dd1da`], - [`yarn`, `2.0.0-rc.30+sha224.0e7a64468c358596db21c401ffeb11b6534fce7367afd3ae640eadf1`], - [`yarn`, `3.0.0-rc.2`], - [`yarn`, `3.0.0-rc.2+sha1.694bdad81703169e203febd57f9dc97d3be867bd`], - [`yarn`, `3.0.0-rc.2+sha224.f83f6d1cbfac10ba6b516a62ccd2a72ccd857aa6c514d1cd7185ec60`], - [`pnpm`, `4.11.6`], - [`pnpm`, `4.11.6+sha1.7cffc04295f4db4740225c6c37cc345eb923c06a`], - [`pnpm`, `4.11.6+sha224.7783c4b01916b7a69e6ff05d328df6f83cb7f127e9c96be88739386d`], - [`pnpm`, `6.6.2`], - [`pnpm`, `6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`], - [`pnpm`, `6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`], - [`npm`, `6.14.2`], - [`npm`, `6.14.2+sha1.f057d35cd4792c4c511bb1fa332edb43143d07b0`], - [`npm`, `6.14.2+sha224.50512c1eb404900ee78586faa6d756b8d867ff46a328e6fb4cdf3a87`], -]; - -for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of testedPackageManagers) { - it(`should use the right package manager version for a given project (${name}@${version})`, async () => { - process.env.COREPACK_ENABLE_UNSAFE_CUSTOM_URLS = `1`; - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`${name}@${version}`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `${expectedVersion}\n`, +// it(`should refuse to download a package manager if the hash doesn't match`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@1.22.4+sha1.deadbeef`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// stdout: /Mismatch hashes/, +// }); +// }); +// }); + +// it(`should refuse to download a known package manager from a URL`, async () => { +// await xfs.mktempPromise(async cwd => { +// // Package managers known by Corepack cannot be loaded from a URL. +// await expect(runCli(cwd, [`yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// stdout: /Illegal use of URL for known package manager/, +// }); + +// // Unknown package managers can be loaded from a URL. +// await expect(runCli(cwd, [`corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `0.24.1\n`, +// }); +// }); +// }); + +// it.failing(`should refuse to download a known package manager from a URL in package.json`, async () => { +// await xfs.mktempPromise(async cwd => { +// // Package managers known by Corepack cannot be loaded from a URL. +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// stdout: /Illegal use of URL for known package manager/, +// }); + +// // Unknown package managers can be loaded from a URL. +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, +// }); + +// await expect(runCli(cwd, [`corepack`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `0.24.1\n`, +// }); +// }); +// }); + +// it(`should require a version to be specified`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// stdout: /expected a semver version/, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@stable`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// stdout: /expected a semver version/, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@^1.0.0`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// stdout: /expected a semver version/, +// }); +// }); +// }); + +// const testedPackageManagers: Array<[string, string] | [string, string, string]> = [ +// [`yarn`, `1.22.4`], +// [`yarn`, `1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`], +// [`yarn`, `1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`], +// [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `1.22.21`], +// [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz#sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72`, `1.22.21`], +// [`yarn`, `2.0.0-rc.30`], +// [`yarn`, `2.0.0-rc.30+sha1.4f0423b01bcb57f8e390b4e0f1990831f92dd1da`], +// [`yarn`, `2.0.0-rc.30+sha224.0e7a64468c358596db21c401ffeb11b6534fce7367afd3ae640eadf1`], +// [`yarn`, `3.0.0-rc.2`], +// [`yarn`, `3.0.0-rc.2+sha1.694bdad81703169e203febd57f9dc97d3be867bd`], +// [`yarn`, `3.0.0-rc.2+sha224.f83f6d1cbfac10ba6b516a62ccd2a72ccd857aa6c514d1cd7185ec60`], +// [`pnpm`, `4.11.6`], +// [`pnpm`, `4.11.6+sha1.7cffc04295f4db4740225c6c37cc345eb923c06a`], +// [`pnpm`, `4.11.6+sha224.7783c4b01916b7a69e6ff05d328df6f83cb7f127e9c96be88739386d`], +// [`pnpm`, `6.6.2`], +// [`pnpm`, `6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`], +// [`pnpm`, `6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`], +// [`npm`, `6.14.2`], +// [`npm`, `6.14.2+sha1.f057d35cd4792c4c511bb1fa332edb43143d07b0`], +// [`npm`, `6.14.2+sha224.50512c1eb404900ee78586faa6d756b8d867ff46a328e6fb4cdf3a87`], +// ]; + +// for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of testedPackageManagers) { +// it(`should use the right package manager version for a given project (${name}@${version})`, async () => { +// process.env.COREPACK_ENABLE_UNSAFE_CUSTOM_URLS = `1`; +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`${name}@${version}`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `${expectedVersion}\n`, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `${name}@${version}`, +// }); + +// await expect(runCli(cwd, [name, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `${expectedVersion}\n`, +// }); +// }); +// }); +// } + +// it(`should update the Known Good Release only when the major matches`, async () => { +// await xfs.writeJsonPromise(ppath.join(npath.toPortablePath(folderUtils.getCorepackHomeFolder()), `lastKnownGood.json`), { +// yarn: `1.0.0`, +// }); + +// process.env.COREPACK_DEFAULT_TO_LATEST = `1`; + +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `1.22.4\n`, +// }); + +// await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `1.22.4\n`, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `2.2.2\n`, +// }); + +// await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `1.22.4\n`, +// }); +// }); +// }); + +// it(`should ignore the packageManager field when found within a node_modules vendor`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.mkdirPromise(ppath.join(cwd, `node_modules/foo` as PortablePath), {recursive: true}); +// await xfs.mkdirPromise(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), {recursive: true}); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { +// packageManager: `yarn@1.22.4`, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/foo/package.json` as PortablePath), { +// packageManager: `npm@6.14.2`, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/@foo/bar/package.json` as PortablePath), { +// packageManager: `npm@6.14.2`, +// }); + +// await expect(runCli(ppath.join(cwd, `node_modules/foo` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `1.22.4\n`, +// }); + +// await expect(runCli(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `1.22.4\n`, +// }); +// }); +// }); + +// it(`should use the closest matching packageManager field`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.mkdirPromise(ppath.join(cwd, `foo` as PortablePath), {recursive: true}); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { +// packageManager: `yarn@1.22.4`, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `foo/package.json` as PortablePath), { +// packageManager: `npm@6.14.2`, +// }); + +// await expect(runCli(ppath.join(cwd, `foo` as PortablePath), [`npm`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// stdout: `6.14.2\n`, +// }); +// }); +// }); + +// it(`should expose its root to spawned processes`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `npm@6.14.2`, +// }); + +// await expect(runCli(cwd, [`npm`, `run`, `env`])).resolves.toMatchObject({ +// exitCode: 0, +// stdout: expect.stringContaining(`COREPACK_ROOT=${npath.dirname(__dirname)}`), +// }); +// }); +// }); + +// it(`shouldn't allow using regular Yarn commands on npm-configured projects`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `npm@6.14.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stderr: ``, +// }); +// }); +// }); + +// it(`should allow using transparent commands on npm-configured projects`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `npm@6.14.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `dlx`, `--help`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); +// }); +// }); + +// it(`should transparently use the preconfigured version when there is no local project`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); +// }); +// }); + +// it(`should use the pinned version when local projects don't list any spec`, async () => { +// // Note that we don't prevent using any package manager. This ensures that +// // projects will receive as little disruption as possible (for example, we +// // don't prompt to set the packageManager field). + +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// // empty package.json file +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, +// stderr: ``, +// exitCode: 0, +// }); + +// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ +// stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, +// stderr: ``, +// exitCode: 0, +// }); + +// await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ +// stdout: `${config.definitions.npm.default.split(`+`, 1)[0]}\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should allow updating the pinned version using the "corepack install -g" command`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`install`, `-g`, `yarn@1.0.0`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// // empty package.json file +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `1.0.0\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should allow to call "corepack install -g" with a tag`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`install`, `-g`, `npm@latest-7`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// // empty package.json file +// }); + +// await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ +// stdout: expect.stringMatching(/^7\./), +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should allow to call "corepack install -g" without any range`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`install`, `-g`, `yarn`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// // empty package.json file +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: expect.not.stringMatching(/^[123]\./), +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should allow to call "corepack install" without arguments within a configured project`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@1.0.0`, +// }); + +// await expect(runCli(cwd, [`install`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); + +// // Disable the network to make sure we don't succeed by accident +// process.env.COREPACK_ENABLE_NETWORK = `0`; + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `1.0.0\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should refuse to run a different package manager within a configured project`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@1.0.0`, +// }); + +// process.env.FORCE_COLOR = `0`; + +// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ +// stdout: `Usage Error: This project is configured to use yarn\n\n$ pnpm ...\n`, +// exitCode: 1, +// }); + +// // Disable strict checking to workaround the UsageError. +// process.env.COREPACK_ENABLE_STRICT = `0`; + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `1.0.0\n`, +// stderr: ``, +// exitCode: 0, +// }); +// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ +// stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + + +// it(`should always use fallback version when project spec env is disabled`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@1.0.0`, +// }); +// process.env.COREPACK_ENABLE_PROJECT_SPEC = `0`; + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, +// stderr: ``, +// exitCode: 0, +// }); +// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ +// stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should support disabling the network accesses from the environment`, async () => { +// process.env.COREPACK_ENABLE_NETWORK = `0`; + +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: expect.stringContaining(`Network access disabled by the environment`), +// stderr: ``, +// exitCode: 1, +// }); +// }); +// }); + +// it(`should support hydrating package managers from cached archives`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ +// stderr: ``, +// exitCode: 0, +// }); + +// // Use a new cache +// process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + +// // Disable the network to make sure we don't succeed by accident +// process.env.COREPACK_ENABLE_NETWORK = `0`; + +// await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ +// stderr: ``, +// exitCode: 0, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should support hydrating package managers if cache folder was removed`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); + +// // Use a new cache +// process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + +// // Simulate cache removal +// await xfs.removePromise(npath.toPortablePath(process.env.COREPACK_HOME)); + +// // Disable the network to make sure we don't succeed by accident +// process.env.COREPACK_ENABLE_NETWORK = `0`; + +// await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ +// stderr: ``, +// exitCode: 0, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should support hydrating multiple package managers from cached archives`, async () => { +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`pack`, `yarn@2.2.2`, `pnpm@5.8.0`])).resolves.toMatchObject({ +// exitCode: 0, +// stderr: ``, +// }); + +// // Use a new cache +// process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + +// // Disable the network to make sure we don't succeed by accident +// process.env.COREPACK_ENABLE_NETWORK = `0`; + +// await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ +// stderr: ``, +// exitCode: 0, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }); + +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `pnpm@5.8.0`, +// }); + +// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ +// stdout: `5.8.0\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }, 180_000); + +// it(`should support running package managers with bin array`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(runCli(cwd, [`yarnpkg`, `--version`])).resolves.toMatchObject({ +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }); +// }); +// }); + +// it(`should handle parallel installs`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// await expect(Promise.all([ +// runCli(cwd, [`yarn`, `--version`]), +// runCli(cwd, [`yarn`, `--version`]), +// runCli(cwd, [`yarn`, `--version`]), +// ])).resolves.toMatchObject([ +// { +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }, +// { +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }, +// { +// stdout: `2.2.2\n`, +// stderr: ``, +// exitCode: 0, +// }, +// ]); +// }); +// }); + +// it(`should not override the package manager exit code`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); +// await xfs.mkdirPromise(yarnFolder, {recursive: true}); +// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + +// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` +// process.exitCode = 42; +// `); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 42, +// stdout: ``, +// stderr: ``, +// }); +// }); +// }); + +// it(`should not preserve the process.exitCode when a package manager throws`, async () => { +// // Node.js doesn't preserve process.exitCode when an exception is thrown +// // so we need to make sure we don't break this behaviour. + +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); +// await xfs.mkdirPromise(yarnFolder, {recursive: true}); +// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + +// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` +// process.exitCode = 42; +// throw new Error('foo'); +// `); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 1, +// stdout: ``, +// stderr: expect.stringContaining(`foo`), +// }); +// }); +// }); + +// it(`should not set the exit code after successfully launching the package manager`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); +// await xfs.mkdirPromise(yarnFolder, {recursive: true}); +// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + +// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` +// process.once('beforeExit', () => { +// if (process.exitCode === undefined) { +// process.exitCode = 42; +// } +// }); +// `); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 42, +// stdout: ``, +// stderr: ``, +// }); +// }); +// }); + +// it(`should support package managers in ESM format`, async () => { +// await xfs.mktempPromise(async cwd => { +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@2.2.2`, +// }); + +// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); +// await xfs.mkdirPromise(yarnFolder, {recursive: true}); +// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + +// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` +// import 'fs'; +// console.log(42); +// `); + +// await xfs.writeJsonPromise(ppath.join(yarnFolder, `package.json`), { +// type: `module`, +// }); + +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stdout: `42\n`, +// stderr: ``, +// }); +// }); +// }); + +// it(`should show a warning on stderr before downloading when enable`, async() => { +// await xfs.mktempPromise(async cwd => { +// process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`; +// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +// packageManager: `yarn@3.0.0`, +// }); +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stdout: `3.0.0\n`, +// stderr: `Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js.\n`, +// }); +// }); +// }); + +// it(`should be able to show the latest version`, async () => { +// process.env.COREPACK_DEFAULT_TO_LATEST = `1`; +// await xfs.mktempPromise(async cwd => { +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stdout: /^1\.\d+\.\d+\r?\n$/, +// stderr: ``, +// }); + +// // Should keep working if the home folder is removed +// await xfs.rmdirPromise(process.env.COREPACK_HOME as any, {recursive: true}); +// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ +// exitCode: 0, +// stdout: /^1\.\d+\.\d+\r?\n$/, +// stderr: ``, +// }); +// }); +// }); + +for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK_NPM_PASSWORD`]) { + describe(`custom registry with auth ${authType}`, () => { + beforeEach(() => { + process.env.AUTH_TYPE = authType; // See `_registryServer.mjs` + }); + + it.only(`should download yarn classic`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `yarn: Hello from custom registry\n`, + stderr: ``, + }); }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `${name}@${version}`, - }); - - await expect(runCli(cwd, [name, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `${expectedVersion}\n`, - }); - }); - }); -} - -it(`should update the Known Good Release only when the major matches`, async () => { - await xfs.writeJsonPromise(ppath.join(npath.toPortablePath(folderUtils.getCorepackHomeFolder()), `lastKnownGood.json`), { - yarn: `1.0.0`, - }); - - process.env.COREPACK_DEFAULT_TO_LATEST = `1`; - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - - await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `2.2.2\n`, - }); - - await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - }); -}); - -it(`should ignore the packageManager field when found within a node_modules vendor`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.mkdirPromise(ppath.join(cwd, `node_modules/foo` as PortablePath), {recursive: true}); - await xfs.mkdirPromise(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), {recursive: true}); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { - packageManager: `yarn@1.22.4`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/foo/package.json` as PortablePath), { - packageManager: `npm@6.14.2`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/@foo/bar/package.json` as PortablePath), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(ppath.join(cwd, `node_modules/foo` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - - await expect(runCli(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - }); -}); - -it(`should use the closest matching packageManager field`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.mkdirPromise(ppath.join(cwd, `foo` as PortablePath), {recursive: true}); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { - packageManager: `yarn@1.22.4`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `foo/package.json` as PortablePath), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(ppath.join(cwd, `foo` as PortablePath), [`npm`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `6.14.2\n`, - }); - }); -}); - -it(`should expose its root to spawned processes`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(cwd, [`npm`, `run`, `env`])).resolves.toMatchObject({ - exitCode: 0, - stdout: expect.stringContaining(`COREPACK_ROOT=${npath.dirname(__dirname)}`), - }); - }); -}); - -it(`shouldn't allow using regular Yarn commands on npm-configured projects`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - }); - }); -}); - -it(`should allow using transparent commands on npm-configured projects`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(cwd, [`yarn`, `dlx`, `--help`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - }); -}); - -it(`should transparently use the preconfigured version when there is no local project`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - }); -}); - -it(`should use the pinned version when local projects don't list any spec`, async () => { - // Note that we don't prevent using any package manager. This ensures that - // projects will receive as little disruption as possible (for example, we - // don't prompt to set the packageManager field). - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - - await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.npm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow updating the pinned version using the "corepack install -g" command`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`install`, `-g`, `yarn@1.0.0`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `1.0.0\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow to call "corepack install -g" with a tag`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`install`, `-g`, `npm@latest-7`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ - stdout: expect.stringMatching(/^7\./), - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow to call "corepack install -g" without any range`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`install`, `-g`, `yarn`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: expect.not.stringMatching(/^[123]\./), - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow to call "corepack install" without arguments within a configured project`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.0.0`, - }); - - await expect(runCli(cwd, [`install`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, }); - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; + it(`should download yarn berry`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@3.0.0`, + }); - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `1.0.0\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should refuse to run a different package manager within a configured project`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.0.0`, - }); - - process.env.FORCE_COLOR = `0`; - - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `Usage Error: This project is configured to use yarn\n\n$ pnpm ...\n`, - exitCode: 1, - }); - - // Disable strict checking to workaround the UsageError. - process.env.COREPACK_ENABLE_STRICT = `0`; - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `1.0.0\n`, - stderr: ``, - exitCode: 0, - }); - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - - -it(`should always use fallback version when project spec env is disabled`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.0.0`, - }); - process.env.COREPACK_ENABLE_PROJECT_SPEC = `0`; - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should support disabling the network accesses from the environment`, async () => { - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: expect.stringContaining(`Network access disabled by the environment`), - stderr: ``, - exitCode: 1, - }); - }); -}); - -it(`should support hydrating package managers from cached archives`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - // Use a new cache - process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should support hydrating package managers if cache folder was removed`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - // Use a new cache - process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - - // Simulate cache removal - await xfs.removePromise(npath.toPortablePath(process.env.COREPACK_HOME)); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should support hydrating multiple package managers from cached archives`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pack`, `yarn@2.2.2`, `pnpm@5.8.0`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - // Use a new cache - process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `pnpm@5.8.0`, - }); - - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `5.8.0\n`, - stderr: ``, - exitCode: 0, - }); - }); -}, 180_000); - -it(`should support running package managers with bin array`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarnpkg`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should handle parallel installs`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(Promise.all([ - runCli(cwd, [`yarn`, `--version`]), - runCli(cwd, [`yarn`, `--version`]), - runCli(cwd, [`yarn`, `--version`]), - ])).resolves.toMatchObject([ - { - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }, - { - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }, - { - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }, - ]); - }); -}); - -it(`should not override the package manager exit code`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - process.exitCode = 42; - `); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 42, - stdout: ``, - stderr: ``, - }); - }); -}); - -it(`should not preserve the process.exitCode when a package manager throws`, async () => { - // Node.js doesn't preserve process.exitCode when an exception is thrown - // so we need to make sure we don't break this behaviour. - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - process.exitCode = 42; - throw new Error('foo'); - `); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stdout: ``, - stderr: expect.stringContaining(`foo`), - }); - }); -}); - -it(`should not set the exit code after successfully launching the package manager`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - process.once('beforeExit', () => { - if (process.exitCode === undefined) { - process.exitCode = 42; - } + await expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `yarn: Hello from custom registry\n`, + stderr: ``, + }); }); - `); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 42, - stdout: ``, - stderr: ``, - }); - }); -}); - -it(`should support package managers in ESM format`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, }); - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - import 'fs'; - console.log(42); - `); - - await xfs.writeJsonPromise(ppath.join(yarnFolder, `package.json`), { - type: `module`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: `42\n`, - stderr: ``, - }); - }); -}); - -it(`should show a warning on stderr before downloading when enable`, async() => { - await xfs.mktempPromise(async cwd => { - process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`; - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@3.0.0`, - }); - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: `3.0.0\n`, - stderr: `Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js.\n`, - }); - }); -}); - -it(`should be able to show the latest version`, async () => { - process.env.COREPACK_DEFAULT_TO_LATEST = `1`; - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: /^1\.\d+\.\d+\r?\n$/, - stderr: ``, - }); - - // Should keep working if the home folder is removed - await xfs.rmdirPromise(process.env.COREPACK_HOME as any, {recursive: true}); - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: /^1\.\d+\.\d+\r?\n$/, - stderr: ``, - }); - }); -}); - -it(`should download yarn classic from custom registry with auth`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `yarn: Hello from custom registry\n`, - stderr: ``, - }); - }); -}); - -it(`should download yarn berry from custom registry with auth`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@3.0.0`, - }); - - await expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `yarn: Hello from custom registry\n`, - stderr: ``, - }); - }); -}); - -it(`should download pnpm from custom registry with auth`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `pnpm: Hello from custom registry\n`, - stderr: ``, + it(`should download pnpm`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: ``, + }); + }); }); - }); -}); -it(`should download custom package manager from custom registry with auth`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`customPkgManager@https://registry.npmjs.org/customPkgManager/-/customPkgManager-1.0.0.tgz`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `customPkgManager: Hello from custom registry\n`, - stderr: ``, + it(`should download custom package manager`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`customPkgManager@https://registry.npmjs.org/customPkgManager/-/customPkgManager-1.0.0.tgz`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `customPkgManager: Hello from custom registry\n`, + stderr: ``, + }); + }); }); }); -}); +} From e993c5852771bdeb2c1d1f79ae9dc01e076bc322 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 17 Mar 2024 13:52:18 +0100 Subject: [PATCH 4/7] fix merge conflicts and remove debug only changes --- tests/main.test.ts | 1490 ++++++++++++++++++++++---------------------- 1 file changed, 745 insertions(+), 745 deletions(-) diff --git a/tests/main.test.ts b/tests/main.test.ts index 836d97fa..bd434e99 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -15,750 +15,750 @@ beforeEach(async () => { process.env.COREPACK_DEFAULT_TO_LATEST = `0`; }); -// it(`should refuse to download a package manager if the hash doesn't match`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@1.22.4+sha1.deadbeef`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// stdout: /Mismatch hashes/, -// }); -// }); -// }); - -// it(`should refuse to download a known package manager from a URL`, async () => { -// await xfs.mktempPromise(async cwd => { -// // Package managers known by Corepack cannot be loaded from a URL. -// await expect(runCli(cwd, [`yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// stdout: /Illegal use of URL for known package manager/, -// }); - -// // Unknown package managers can be loaded from a URL. -// await expect(runCli(cwd, [`corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `0.24.1\n`, -// }); -// }); -// }); - -// it.failing(`should refuse to download a known package manager from a URL in package.json`, async () => { -// await xfs.mktempPromise(async cwd => { -// // Package managers known by Corepack cannot be loaded from a URL. -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// stdout: /Illegal use of URL for known package manager/, -// }); - -// // Unknown package managers can be loaded from a URL. -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, -// }); - -// await expect(runCli(cwd, [`corepack`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `0.24.1\n`, -// }); -// }); -// }); - -// it(`should require a version to be specified`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// stdout: /expected a semver version/, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@stable`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// stdout: /expected a semver version/, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@^1.0.0`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// stdout: /expected a semver version/, -// }); -// }); -// }); - -// const testedPackageManagers: Array<[string, string] | [string, string, string]> = [ -// [`yarn`, `1.22.4`], -// [`yarn`, `1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`], -// [`yarn`, `1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`], -// [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `1.22.21`], -// [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz#sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72`, `1.22.21`], -// [`yarn`, `2.0.0-rc.30`], -// [`yarn`, `2.0.0-rc.30+sha1.4f0423b01bcb57f8e390b4e0f1990831f92dd1da`], -// [`yarn`, `2.0.0-rc.30+sha224.0e7a64468c358596db21c401ffeb11b6534fce7367afd3ae640eadf1`], -// [`yarn`, `3.0.0-rc.2`], -// [`yarn`, `3.0.0-rc.2+sha1.694bdad81703169e203febd57f9dc97d3be867bd`], -// [`yarn`, `3.0.0-rc.2+sha224.f83f6d1cbfac10ba6b516a62ccd2a72ccd857aa6c514d1cd7185ec60`], -// [`pnpm`, `4.11.6`], -// [`pnpm`, `4.11.6+sha1.7cffc04295f4db4740225c6c37cc345eb923c06a`], -// [`pnpm`, `4.11.6+sha224.7783c4b01916b7a69e6ff05d328df6f83cb7f127e9c96be88739386d`], -// [`pnpm`, `6.6.2`], -// [`pnpm`, `6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`], -// [`pnpm`, `6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`], -// [`npm`, `6.14.2`], -// [`npm`, `6.14.2+sha1.f057d35cd4792c4c511bb1fa332edb43143d07b0`], -// [`npm`, `6.14.2+sha224.50512c1eb404900ee78586faa6d756b8d867ff46a328e6fb4cdf3a87`], -// ]; - -// for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of testedPackageManagers) { -// it(`should use the right package manager version for a given project (${name}@${version})`, async () => { -// process.env.COREPACK_ENABLE_UNSAFE_CUSTOM_URLS = `1`; -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`${name}@${version}`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `${expectedVersion}\n`, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `${name}@${version}`, -// }); - -// await expect(runCli(cwd, [name, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `${expectedVersion}\n`, -// }); -// }); -// }); -// } - -// it(`should update the Known Good Release only when the major matches`, async () => { -// await xfs.writeJsonPromise(ppath.join(npath.toPortablePath(folderUtils.getCorepackHomeFolder()), `lastKnownGood.json`), { -// yarn: `1.0.0`, -// }); - -// process.env.COREPACK_DEFAULT_TO_LATEST = `1`; - -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `1.22.4\n`, -// }); - -// await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `1.22.4\n`, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `2.2.2\n`, -// }); - -// await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `1.22.4\n`, -// }); -// }); -// }); - -// it(`should ignore the packageManager field when found within a node_modules vendor`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.mkdirPromise(ppath.join(cwd, `node_modules/foo` as PortablePath), {recursive: true}); -// await xfs.mkdirPromise(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), {recursive: true}); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { -// packageManager: `yarn@1.22.4`, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/foo/package.json` as PortablePath), { -// packageManager: `npm@6.14.2`, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/@foo/bar/package.json` as PortablePath), { -// packageManager: `npm@6.14.2`, -// }); - -// await expect(runCli(ppath.join(cwd, `node_modules/foo` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `1.22.4\n`, -// }); - -// await expect(runCli(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `1.22.4\n`, -// }); -// }); -// }); - -// it(`should use the closest matching packageManager field`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.mkdirPromise(ppath.join(cwd, `foo` as PortablePath), {recursive: true}); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { -// packageManager: `yarn@1.22.4`, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `foo/package.json` as PortablePath), { -// packageManager: `npm@6.14.2`, -// }); - -// await expect(runCli(ppath.join(cwd, `foo` as PortablePath), [`npm`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// stdout: `6.14.2\n`, -// }); -// }); -// }); - -// it(`should expose its root to spawned processes`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `npm@6.14.2`, -// }); - -// await expect(runCli(cwd, [`npm`, `run`, `env`])).resolves.toMatchObject({ -// exitCode: 0, -// stdout: expect.stringContaining(`COREPACK_ROOT=${npath.dirname(__dirname)}`), -// }); -// }); -// }); - -// it(`shouldn't allow using regular Yarn commands on npm-configured projects`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `npm@6.14.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stderr: ``, -// }); -// }); -// }); - -// it(`should allow using transparent commands on npm-configured projects`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `npm@6.14.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `dlx`, `--help`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); -// }); -// }); - -// it(`should transparently use the preconfigured version when there is no local project`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); -// }); -// }); - -// it(`should use the pinned version when local projects don't list any spec`, async () => { -// // Note that we don't prevent using any package manager. This ensures that -// // projects will receive as little disruption as possible (for example, we -// // don't prompt to set the packageManager field). - -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// // empty package.json file -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, -// stderr: ``, -// exitCode: 0, -// }); - -// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ -// stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, -// stderr: ``, -// exitCode: 0, -// }); - -// await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ -// stdout: `${config.definitions.npm.default.split(`+`, 1)[0]}\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should allow updating the pinned version using the "corepack install -g" command`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`install`, `-g`, `yarn@1.0.0`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// // empty package.json file -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `1.0.0\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should allow to call "corepack install -g" with a tag`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`install`, `-g`, `npm@latest-7`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// // empty package.json file -// }); - -// await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ -// stdout: expect.stringMatching(/^7\./), -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should allow to call "corepack install -g" without any range`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`install`, `-g`, `yarn`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// // empty package.json file -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: expect.not.stringMatching(/^[123]\./), -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should allow to call "corepack install" without arguments within a configured project`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@1.0.0`, -// }); - -// await expect(runCli(cwd, [`install`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); - -// // Disable the network to make sure we don't succeed by accident -// process.env.COREPACK_ENABLE_NETWORK = `0`; - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `1.0.0\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should refuse to run a different package manager within a configured project`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@1.0.0`, -// }); - -// process.env.FORCE_COLOR = `0`; - -// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ -// stdout: `Usage Error: This project is configured to use yarn\n\n$ pnpm ...\n`, -// exitCode: 1, -// }); - -// // Disable strict checking to workaround the UsageError. -// process.env.COREPACK_ENABLE_STRICT = `0`; - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `1.0.0\n`, -// stderr: ``, -// exitCode: 0, -// }); -// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ -// stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - - -// it(`should always use fallback version when project spec env is disabled`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@1.0.0`, -// }); -// process.env.COREPACK_ENABLE_PROJECT_SPEC = `0`; - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, -// stderr: ``, -// exitCode: 0, -// }); -// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ -// stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should support disabling the network accesses from the environment`, async () => { -// process.env.COREPACK_ENABLE_NETWORK = `0`; - -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: expect.stringContaining(`Network access disabled by the environment`), -// stderr: ``, -// exitCode: 1, -// }); -// }); -// }); - -// it(`should support hydrating package managers from cached archives`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ -// stderr: ``, -// exitCode: 0, -// }); - -// // Use a new cache -// process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - -// // Disable the network to make sure we don't succeed by accident -// process.env.COREPACK_ENABLE_NETWORK = `0`; - -// await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ -// stderr: ``, -// exitCode: 0, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should support hydrating package managers if cache folder was removed`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); - -// // Use a new cache -// process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - -// // Simulate cache removal -// await xfs.removePromise(npath.toPortablePath(process.env.COREPACK_HOME)); - -// // Disable the network to make sure we don't succeed by accident -// process.env.COREPACK_ENABLE_NETWORK = `0`; - -// await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ -// stderr: ``, -// exitCode: 0, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should support hydrating multiple package managers from cached archives`, async () => { -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`pack`, `yarn@2.2.2`, `pnpm@5.8.0`])).resolves.toMatchObject({ -// exitCode: 0, -// stderr: ``, -// }); - -// // Use a new cache -// process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - -// // Disable the network to make sure we don't succeed by accident -// process.env.COREPACK_ENABLE_NETWORK = `0`; - -// await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ -// stderr: ``, -// exitCode: 0, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }); - -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `pnpm@5.8.0`, -// }); - -// await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ -// stdout: `5.8.0\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }, 180_000); - -// it(`should support running package managers with bin array`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(runCli(cwd, [`yarnpkg`, `--version`])).resolves.toMatchObject({ -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }); -// }); -// }); - -// it(`should handle parallel installs`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// await expect(Promise.all([ -// runCli(cwd, [`yarn`, `--version`]), -// runCli(cwd, [`yarn`, `--version`]), -// runCli(cwd, [`yarn`, `--version`]), -// ])).resolves.toMatchObject([ -// { -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }, -// { -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }, -// { -// stdout: `2.2.2\n`, -// stderr: ``, -// exitCode: 0, -// }, -// ]); -// }); -// }); - -// it(`should not override the package manager exit code`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); -// await xfs.mkdirPromise(yarnFolder, {recursive: true}); -// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - -// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` -// process.exitCode = 42; -// `); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 42, -// stdout: ``, -// stderr: ``, -// }); -// }); -// }); - -// it(`should not preserve the process.exitCode when a package manager throws`, async () => { -// // Node.js doesn't preserve process.exitCode when an exception is thrown -// // so we need to make sure we don't break this behaviour. - -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); -// await xfs.mkdirPromise(yarnFolder, {recursive: true}); -// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - -// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` -// process.exitCode = 42; -// throw new Error('foo'); -// `); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 1, -// stdout: ``, -// stderr: expect.stringContaining(`foo`), -// }); -// }); -// }); - -// it(`should not set the exit code after successfully launching the package manager`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); -// await xfs.mkdirPromise(yarnFolder, {recursive: true}); -// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - -// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` -// process.once('beforeExit', () => { -// if (process.exitCode === undefined) { -// process.exitCode = 42; -// } -// }); -// `); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 42, -// stdout: ``, -// stderr: ``, -// }); -// }); -// }); - -// it(`should support package managers in ESM format`, async () => { -// await xfs.mktempPromise(async cwd => { -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@2.2.2`, -// }); - -// const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); -// await xfs.mkdirPromise(yarnFolder, {recursive: true}); -// await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - -// await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` -// import 'fs'; -// console.log(42); -// `); - -// await xfs.writeJsonPromise(ppath.join(yarnFolder, `package.json`), { -// type: `module`, -// }); - -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stdout: `42\n`, -// stderr: ``, -// }); -// }); -// }); - -// it(`should show a warning on stderr before downloading when enable`, async() => { -// await xfs.mktempPromise(async cwd => { -// process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`; -// await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { -// packageManager: `yarn@3.0.0`, -// }); -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stdout: `3.0.0\n`, -// stderr: `Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js.\n`, -// }); -// }); -// }); - -// it(`should be able to show the latest version`, async () => { -// process.env.COREPACK_DEFAULT_TO_LATEST = `1`; -// await xfs.mktempPromise(async cwd => { -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stdout: /^1\.\d+\.\d+\r?\n$/, -// stderr: ``, -// }); - -// // Should keep working if the home folder is removed -// await xfs.rmdirPromise(process.env.COREPACK_HOME as any, {recursive: true}); -// await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ -// exitCode: 0, -// stdout: /^1\.\d+\.\d+\r?\n$/, -// stderr: ``, -// }); -// }); -// }); +it(`should refuse to download a package manager if the hash doesn't match`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@1.22.4+sha1.deadbeef`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /Mismatch hashes/, + }); + }); +}); + +it(`should refuse to download a known package manager from a URL`, async () => { + await xfs.mktempPromise(async cwd => { + // Package managers known by Corepack cannot be loaded from a URL. + await expect(runCli(cwd, [`yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /Illegal use of URL for known package manager/, + }); + + // Unknown package managers can be loaded from a URL. + await expect(runCli(cwd, [`corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `0.24.1\n`, + }); + }); +}); + +it.failing(`should refuse to download a known package manager from a URL in package.json`, async () => { + await xfs.mktempPromise(async cwd => { + // Package managers known by Corepack cannot be loaded from a URL. + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /Illegal use of URL for known package manager/, + }); + + // Unknown package managers can be loaded from a URL. + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `corepack@https://registry.npmjs.com/corepack/-/corepack-0.24.1.tgz`, + }); + + await expect(runCli(cwd, [`corepack`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `0.24.1\n`, + }); + }); +}); + +it(`should require a version to be specified`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /expected a semver version/, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@stable`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /expected a semver version/, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@^1.0.0`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + stdout: /expected a semver version/, + }); + }); +}); + +const testedPackageManagers: Array<[string, string] | [string, string, string]> = [ + [`yarn`, `1.22.4`], + [`yarn`, `1.22.4+sha1.01c1197ca5b27f21edc8bc472cd4c8ce0e5a470e`], + [`yarn`, `1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`], + [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz`, `1.22.21`], + [`yarn`, `https://registry.npmjs.com/yarn/-/yarn-1.22.21.tgz#sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72`, `1.22.21`], + [`yarn`, `2.0.0-rc.30`], + [`yarn`, `2.0.0-rc.30+sha1.4f0423b01bcb57f8e390b4e0f1990831f92dd1da`], + [`yarn`, `2.0.0-rc.30+sha224.0e7a64468c358596db21c401ffeb11b6534fce7367afd3ae640eadf1`], + [`yarn`, `3.0.0-rc.2`], + [`yarn`, `3.0.0-rc.2+sha1.694bdad81703169e203febd57f9dc97d3be867bd`], + [`yarn`, `3.0.0-rc.2+sha224.f83f6d1cbfac10ba6b516a62ccd2a72ccd857aa6c514d1cd7185ec60`], + [`pnpm`, `4.11.6`], + [`pnpm`, `4.11.6+sha1.7cffc04295f4db4740225c6c37cc345eb923c06a`], + [`pnpm`, `4.11.6+sha224.7783c4b01916b7a69e6ff05d328df6f83cb7f127e9c96be88739386d`], + [`pnpm`, `6.6.2`], + [`pnpm`, `6.6.2+sha1.7b4d6b176c1b93b5670ed94c24babb7d80c13854`], + [`pnpm`, `6.6.2+sha224.eb5c0acad3b0f40ecdaa2db9aa5a73134ad256e17e22d1419a2ab073`], + [`npm`, `6.14.2`], + [`npm`, `6.14.2+sha1.f057d35cd4792c4c511bb1fa332edb43143d07b0`], + [`npm`, `6.14.2+sha224.50512c1eb404900ee78586faa6d756b8d867ff46a328e6fb4cdf3a87`], +]; + +for (const [name, version, expectedVersion = version.split(`+`, 1)[0]] of testedPackageManagers) { + it(`should use the right package manager version for a given project (${name}@${version})`, async () => { + process.env.COREPACK_ENABLE_UNSAFE_CUSTOM_URLS = `1`; + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`${name}@${version}`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `${expectedVersion}\n`, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `${name}@${version}`, + }); + + await expect(runCli(cwd, [name, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `${expectedVersion}\n`, + }); + }); + }); +} + +it(`should update the Known Good Release only when the major matches`, async () => { + await xfs.writeJsonPromise(ppath.join(npath.toPortablePath(folderUtils.getCorepackHomeFolder()), `lastKnownGood.json`), { + yarn: `1.0.0`, + }); + + process.env.COREPACK_DEFAULT_TO_LATEST = `1`; + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `1.22.4\n`, + }); + + await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `1.22.4\n`, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `2.2.2\n`, + }); + + await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `1.22.4\n`, + }); + }); +}); + +it(`should ignore the packageManager field when found within a node_modules vendor`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.mkdirPromise(ppath.join(cwd, `node_modules/foo` as PortablePath), {recursive: true}); + await xfs.mkdirPromise(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), {recursive: true}); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { + packageManager: `yarn@1.22.4`, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/foo/package.json` as PortablePath), { + packageManager: `npm@6.14.2`, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/@foo/bar/package.json` as PortablePath), { + packageManager: `npm@6.14.2`, + }); + + await expect(runCli(ppath.join(cwd, `node_modules/foo` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `1.22.4\n`, + }); + + await expect(runCli(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `1.22.4\n`, + }); + }); +}); + +it(`should use the closest matching packageManager field`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.mkdirPromise(ppath.join(cwd, `foo` as PortablePath), {recursive: true}); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { + packageManager: `yarn@1.22.4`, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `foo/package.json` as PortablePath), { + packageManager: `npm@6.14.2`, + }); + + await expect(runCli(ppath.join(cwd, `foo` as PortablePath), [`npm`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + stdout: `6.14.2\n`, + }); + }); +}); + +it(`should expose its root to spawned processes`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `npm@6.14.2`, + }); + + await expect(runCli(cwd, [`npm`, `run`, `env`])).resolves.toMatchObject({ + exitCode: 0, + stdout: expect.stringContaining(`COREPACK_ROOT=${npath.dirname(__dirname)}`), + }); + }); +}); + +it(`shouldn't allow using regular Yarn commands on npm-configured projects`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `npm@6.14.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stderr: ``, + }); + }); +}); + +it(`should allow using transparent commands on npm-configured projects`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `npm@6.14.2`, + }); + + await expect(runCli(cwd, [`yarn`, `dlx`, `--help`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + }); +}); + +it(`should transparently use the preconfigured version when there is no local project`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + }); +}); + +it(`should use the pinned version when local projects don't list any spec`, async () => { + // Note that we don't prevent using any package manager. This ensures that + // projects will receive as little disruption as possible (for example, we + // don't prompt to set the packageManager field). + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, + stderr: ``, + exitCode: 0, + }); + + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, + stderr: ``, + exitCode: 0, + }); + + await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ + stdout: `${config.definitions.npm.default.split(`+`, 1)[0]}\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should allow updating the pinned version using the "corepack install -g" command`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`install`, `-g`, `yarn@1.0.0`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `1.0.0\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should allow to call "corepack install -g" with a tag`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`install`, `-g`, `npm@latest-7`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + + await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ + stdout: expect.stringMatching(/^7\./), + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should allow to call "corepack install -g" without any range`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`install`, `-g`, `yarn`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: expect.not.stringMatching(/^[123]\./), + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should allow to call "corepack install" without arguments within a configured project`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@1.0.0`, + }); + + await expect(runCli(cwd, [`install`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + // Disable the network to make sure we don't succeed by accident + process.env.COREPACK_ENABLE_NETWORK = `0`; + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `1.0.0\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should refuse to run a different package manager within a configured project`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@1.0.0`, + }); + + process.env.FORCE_COLOR = `0`; + + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + stdout: `Usage Error: This project is configured to use yarn\n\n$ pnpm ...\n`, + exitCode: 1, + }); + + // Disable strict checking to workaround the UsageError. + process.env.COREPACK_ENABLE_STRICT = `0`; + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `1.0.0\n`, + stderr: ``, + exitCode: 0, + }); + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + + +it(`should always use fallback version when project spec env is disabled`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@1.0.0`, + }); + process.env.COREPACK_ENABLE_PROJECT_SPEC = `0`; + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, + stderr: ``, + exitCode: 0, + }); + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should support disabling the network accesses from the environment`, async () => { + process.env.COREPACK_ENABLE_NETWORK = `0`; + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: expect.stringContaining(`Network access disabled by the environment`), + stderr: ``, + exitCode: 1, + }); + }); +}); + +it(`should support hydrating package managers from cached archives`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ + stderr: ``, + exitCode: 0, + }); + + // Use a new cache + process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + + // Disable the network to make sure we don't succeed by accident + process.env.COREPACK_ENABLE_NETWORK = `0`; + + await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ + stderr: ``, + exitCode: 0, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should support hydrating package managers if cache folder was removed`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + // Use a new cache + process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + + // Simulate cache removal + await xfs.removePromise(npath.toPortablePath(process.env.COREPACK_HOME)); + + // Disable the network to make sure we don't succeed by accident + process.env.COREPACK_ENABLE_NETWORK = `0`; + + await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ + stderr: ``, + exitCode: 0, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should support hydrating multiple package managers from cached archives`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pack`, `yarn@2.2.2`, `pnpm@5.8.0`])).resolves.toMatchObject({ + exitCode: 0, + stderr: ``, + }); + + // Use a new cache + process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); + + // Disable the network to make sure we don't succeed by accident + process.env.COREPACK_ENABLE_NETWORK = `0`; + + await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ + stderr: ``, + exitCode: 0, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }); + + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `pnpm@5.8.0`, + }); + + await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ + stdout: `5.8.0\n`, + stderr: ``, + exitCode: 0, + }); + }); +}, 180_000); + +it(`should support running package managers with bin array`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(runCli(cwd, [`yarnpkg`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }); + }); +}); + +it(`should handle parallel installs`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + await expect(Promise.all([ + runCli(cwd, [`yarn`, `--version`]), + runCli(cwd, [`yarn`, `--version`]), + runCli(cwd, [`yarn`, `--version`]), + ])).resolves.toMatchObject([ + { + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }, + { + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }, + { + stdout: `2.2.2\n`, + stderr: ``, + exitCode: 0, + }, + ]); + }); +}); + +it(`should not override the package manager exit code`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); + await xfs.mkdirPromise(yarnFolder, {recursive: true}); + await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + + await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` + process.exitCode = 42; + `); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 42, + stdout: ``, + stderr: ``, + }); + }); +}); + +it(`should not preserve the process.exitCode when a package manager throws`, async () => { + // Node.js doesn't preserve process.exitCode when an exception is thrown + // so we need to make sure we don't break this behaviour. + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); + await xfs.mkdirPromise(yarnFolder, {recursive: true}); + await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + + await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` + process.exitCode = 42; + throw new Error('foo'); + `); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`foo`), + }); + }); +}); + +it(`should not set the exit code after successfully launching the package manager`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); + await xfs.mkdirPromise(yarnFolder, {recursive: true}); + await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + + await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` + process.once('beforeExit', () => { + if (process.exitCode === undefined) { + process.exitCode = 42; + } + }); + `); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 42, + stdout: ``, + stderr: ``, + }); + }); +}); + +it(`should support package managers in ESM format`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@2.2.2`, + }); + + const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); + await xfs.mkdirPromise(yarnFolder, {recursive: true}); + await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); + + await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` + import 'fs'; + console.log(42); + `); + + await xfs.writeJsonPromise(ppath.join(yarnFolder, `package.json`), { + type: `module`, + }); + + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stdout: `42\n`, + stderr: ``, + }); + }); +}); + +it(`should show a warning on stderr before downloading when enable`, async() => { + await xfs.mktempPromise(async cwd => { + process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`; + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@3.0.0`, + }); + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stdout: `3.0.0\n`, + stderr: `Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js.\n`, + }); + }); +}); + +it(`should be able to show the latest version`, async () => { + process.env.COREPACK_DEFAULT_TO_LATEST = `1`; + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stdout: /^1\.\d+\.\d+\r?\n$/, + stderr: ``, + }); + + // Should keep working if the home folder is removed + await xfs.rmdirPromise(process.env.COREPACK_HOME as any, {recursive: true}); + await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ + exitCode: 0, + stdout: /^1\.\d+\.\d+\r?\n$/, + stderr: ``, + }); + }); +}); for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK_NPM_PASSWORD`]) { describe(`custom registry with auth ${authType}`, () => { @@ -766,7 +766,7 @@ for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK process.env.AUTH_TYPE = authType; // See `_registryServer.mjs` }); - it.only(`should download yarn classic`, async () => { + it(`should download yarn classic`, async () => { await xfs.mktempPromise(async cwd => { await expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ exitCode: 0, From af269388755cd5c0a87849d737effdfe3fda4e26 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 17 Mar 2024 13:52:51 +0100 Subject: [PATCH 5/7] fix failing tests --- sources/httpUtils.ts | 52 +++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/sources/httpUtils.ts b/sources/httpUtils.ts index 48154fb6..e995d1e9 100644 --- a/sources/httpUtils.ts +++ b/sources/httpUtils.ts @@ -1,8 +1,10 @@ -import assert from 'assert'; -import {UsageError} from 'clipanion'; -import {once} from 'events'; -import {stderr, stdin} from 'process'; -import {Readable} from 'stream'; +import assert from 'assert'; +import {UsageError} from 'clipanion'; +import {once} from 'events'; +import {stderr, stdin} from 'process'; +import {Readable} from 'stream'; + +import {DEFAULT_NPM_REGISTRY_URL} from './npmRegistryUtils'; async function fetch(input: string | URL, init?: RequestInit) { if (process.env.COREPACK_ENABLE_NETWORK === `0`) @@ -10,26 +12,40 @@ async function fetch(input: string | URL, init?: RequestInit) { const agent = await getProxyAgent(input); + if (typeof input === `string`) + input = new URL(input); + + let headers = init?.headers; + const {username, password} = input; + if (username || password) { + headers = { + ...headers, + authorization: `Bearer ${Buffer.from(`${username}:${password}`).toString(`base64`)}`, + }; + input.username = input.password = ``; + } else if (input.origin === process.env.COREPACK_NPM_REGISTRY || DEFAULT_NPM_REGISTRY_URL) { + if (process.env.COREPACK_NPM_TOKEN) { + headers = { + ...headers, + authorization: `Bearer ${process.env.COREPACK_NPM_TOKEN}`, + }; + } else if (`COREPACK_NPM_PASSWORD` in process.env) { + headers = { + ...headers, + authorization: `Bearer ${Buffer.from(`${process.env.COREPACK_NPM_USER}:${process.env.COREPACK_NPM_PASSWORD}`).toString(`base64`)}`, + }; + } + } + + let response; try { response = await globalThis.fetch(input, { ...init, dispatcher: agent, + headers, }); } catch (error) { - if (error?.message?.includes?.(`Request cannot be constructed from a URL that includes credentials`)) { - const url = new URL(input as string); - const authorization = `Bearer ${Buffer.from(`${url.username}:${url.password}`).toString(`base64`)}`; - url.username = ``; - url.password = ``; - return fetch(url, { - ...init, - headers: { - ...init?.headers, - authorization, - }, - }); - } throw new Error( `Error when performing the request to ${input}; for troubleshooting help, see https://github.com/nodejs/corepack#troubleshooting`, {cause: error}, From ad9fe3ff21208453654d59247b118ea1e32c2c05 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 17 Mar 2024 14:00:50 +0100 Subject: [PATCH 6/7] remove merge residus --- tests/main.test.ts | 713 ++++----------------------------------------- 1 file changed, 53 insertions(+), 660 deletions(-) diff --git a/tests/main.test.ts b/tests/main.test.ts index bd434e99..0d68ced9 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -1,4 +1,4 @@ -import {beforeEach, it, expect, describe} from '@jest/globals'; +import {beforeEach, describe, expect, it} from '@jest/globals'; import {Filename, ppath, xfs, npath, PortablePath} from '@yarnpkg/fslib'; import process from 'node:process'; @@ -298,665 +298,6 @@ it(`should transparently use the preconfigured version when there is no local pr }); }); -it(`should use the pinned version when local projects don't list any spec`, async () => { - // Note that we don't prevent using any package manager. This ensures that - // projects will receive as little disruption as possible (for example, we - // don't prompt to set the packageManager field). - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - - await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.npm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow updating the pinned version using the "corepack install -g" command`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`install`, `-g`, `yarn@1.0.0`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `1.0.0\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow to call "corepack install -g" with a tag`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`install`, `-g`, `npm@latest-7`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`npm`, `--version`])).resolves.toMatchObject({ - stdout: expect.stringMatching(/^7\./), - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow to call "corepack install -g" without any range`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`install`, `-g`, `yarn`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - // empty package.json file - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: expect.not.stringMatching(/^[123]\./), - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should allow to call "corepack install" without arguments within a configured project`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.0.0`, - }); - - await expect(runCli(cwd, [`install`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `1.0.0\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should refuse to run a different package manager within a configured project`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.0.0`, - }); - - process.env.FORCE_COLOR = `0`; - - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `Usage Error: This project is configured to use yarn\n\n$ pnpm ...\n`, - exitCode: 1, - }); - - // Disable strict checking to workaround the UsageError. - process.env.COREPACK_ENABLE_STRICT = `0`; - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `1.0.0\n`, - stderr: ``, - exitCode: 0, - }); - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - - -it(`should always use fallback version when project spec env is disabled`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.0.0`, - }); - process.env.COREPACK_ENABLE_PROJECT_SPEC = `0`; - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.yarn.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `${config.definitions.pnpm.default.split(`+`, 1)[0]}\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should support disabling the network accesses from the environment`, async () => { - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: expect.stringContaining(`Network access disabled by the environment`), - stderr: ``, - exitCode: 1, - }); - }); -}); - -it(`should support hydrating package managers from cached archives`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - // Use a new cache - process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should support hydrating package managers if cache folder was removed`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pack`, `yarn@2.2.2`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - // Use a new cache - process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - - // Simulate cache removal - await xfs.removePromise(npath.toPortablePath(process.env.COREPACK_HOME)); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should support hydrating multiple package managers from cached archives`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pack`, `yarn@2.2.2`, `pnpm@5.8.0`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - - // Use a new cache - process.env.COREPACK_HOME = npath.fromPortablePath(await xfs.mktempPromise()); - - // Disable the network to make sure we don't succeed by accident - process.env.COREPACK_ENABLE_NETWORK = `0`; - - await expect(runCli(cwd, [`install`, `-g`, `corepack.tgz`])).resolves.toMatchObject({ - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `pnpm@5.8.0`, - }); - - await expect(runCli(cwd, [`pnpm`, `--version`])).resolves.toMatchObject({ - stdout: `5.8.0\n`, - stderr: ``, - exitCode: 0, - }); - }); -}, 180_000); - -it(`should support running package managers with bin array`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarnpkg`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }); - }); -}); - -it(`should handle parallel installs`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(Promise.all([ - runCli(cwd, [`yarn`, `--version`]), - runCli(cwd, [`yarn`, `--version`]), - runCli(cwd, [`yarn`, `--version`]), - ])).resolves.toMatchObject([ - { - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }, - { - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }, - { - stdout: `2.2.2\n`, - stderr: ``, - exitCode: 0, - }, - ]); - }); -}); - -it(`should not override the package manager exit code`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - process.exitCode = 42; - `); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 42, - stdout: ``, - stderr: ``, - }); - }); -}); - -it(`should not preserve the process.exitCode when a package manager throws`, async () => { - // Node.js doesn't preserve process.exitCode when an exception is thrown - // so we need to make sure we don't break this behaviour. - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - process.exitCode = 42; - throw new Error('foo'); - `); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stdout: ``, - stderr: expect.stringContaining(`foo`), - }); - }); -}); - -it(`should not set the exit code after successfully launching the package manager`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - process.once('beforeExit', () => { - if (process.exitCode === undefined) { - process.exitCode = 42; - } - }); - `); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 42, - stdout: ``, - stderr: ``, - }); - }); -}); - -it(`should support package managers in ESM format`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - const yarnFolder = ppath.join(npath.toPortablePath(folderUtils.getInstallFolder()), `yarn/2.2.2`); - await xfs.mkdirPromise(yarnFolder, {recursive: true}); - await xfs.writeJsonPromise(ppath.join(yarnFolder, `.corepack`), {}); - - await xfs.writeFilePromise(ppath.join(yarnFolder, `yarn.js`), ` - import 'fs'; - console.log(42); - `); - - await xfs.writeJsonPromise(ppath.join(yarnFolder, `package.json`), { - type: `module`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: `42\n`, - stderr: ``, - }); - }); -}); - -it(`should show a warning on stderr before downloading when enable`, async() => { - await xfs.mktempPromise(async cwd => { - process.env.COREPACK_ENABLE_DOWNLOAD_PROMPT = `1`; - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@3.0.0`, - }); - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: `3.0.0\n`, - stderr: `Corepack is about to download https://repo.yarnpkg.com/3.0.0/packages/yarnpkg-cli/bin/yarn.js.\n`, - }); - }); -}); - -it(`should be able to show the latest version`, async () => { - process.env.COREPACK_DEFAULT_TO_LATEST = `1`; - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: /^1\.\d+\.\d+\r?\n$/, - stderr: ``, - }); - - // Should keep working if the home folder is removed - await xfs.rmdirPromise(process.env.COREPACK_HOME as any, {recursive: true}); - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stdout: /^1\.\d+\.\d+\r?\n$/, - stderr: ``, - }); - }); -}); - -for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK_NPM_PASSWORD`]) { - describe(`custom registry with auth ${authType}`, () => { - beforeEach(() => { - process.env.AUTH_TYPE = authType; // See `_registryServer.mjs` - }); - - it(`should download yarn classic`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `yarn: Hello from custom registry\n`, - stderr: ``, - }); - }); - }); - - it(`should download yarn berry`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@3.0.0`, - }); - - await expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `yarn: Hello from custom registry\n`, - stderr: ``, - }); - }); - }); - - it(`should download pnpm`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `pnpm: Hello from custom registry\n`, - stderr: ``, - }); - }); - }); - - it(`should download custom package manager`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`customPkgManager@https://registry.npmjs.org/customPkgManager/-/customPkgManager-1.0.0.tgz`, `--version`], true)).resolves.toMatchObject({ - exitCode: 0, - stdout: `customPkgManager: Hello from custom registry\n`, - stderr: ``, - }); - }); - }); - }); -} - -it(`should update the Known Good Release only when the major matches`, async () => { - await xfs.writeJsonPromise(ppath.join(npath.toPortablePath(folderUtils.getCorepackHomeFolder()), `lastKnownGood.json`), { - yarn: `1.0.0`, - }); - - process.env.COREPACK_DEFAULT_TO_LATEST = `1`; - - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@1.22.4+sha224.0d6eecaf4d82ec12566fdd97143794d0f0c317e0d652bd4d1b305430`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - - await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `yarn@2.2.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `2.2.2\n`, - }); - - await xfs.removePromise(ppath.join(cwd, `package.json` as Filename)); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - }); -}); - -it(`should ignore the packageManager field when found within a node_modules vendor`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.mkdirPromise(ppath.join(cwd, `node_modules/foo` as PortablePath), {recursive: true}); - await xfs.mkdirPromise(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), {recursive: true}); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { - packageManager: `yarn@1.22.4`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/foo/package.json` as PortablePath), { - packageManager: `npm@6.14.2`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `node_modules/@foo/bar/package.json` as PortablePath), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(ppath.join(cwd, `node_modules/foo` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - - await expect(runCli(ppath.join(cwd, `node_modules/@foo/bar` as PortablePath), [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `1.22.4\n`, - }); - }); -}); - -it(`should use the closest matching packageManager field`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.mkdirPromise(ppath.join(cwd, `foo` as PortablePath), {recursive: true}); - - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as PortablePath), { - packageManager: `yarn@1.22.4`, - }); - - await xfs.writeJsonPromise(ppath.join(cwd, `foo/package.json` as PortablePath), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(ppath.join(cwd, `foo` as PortablePath), [`npm`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - stdout: `6.14.2\n`, - }); - }); -}); - -it(`should expose its root to spawned processes`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(cwd, [`npm`, `run`, `env`])).resolves.toMatchObject({ - exitCode: 0, - stdout: expect.stringContaining(`COREPACK_ROOT=${npath.dirname(__dirname)}`), - }); - }); -}); - -it(`shouldn't allow using regular Yarn commands on npm-configured projects`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 1, - stderr: ``, - }); - }); -}); - -it(`should allow using transparent commands on npm-configured projects`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { - packageManager: `npm@6.14.2`, - }); - - await expect(runCli(cwd, [`yarn`, `dlx`, `--help`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - }); -}); - -it(`should transparently use the preconfigured version when there is no local project`, async () => { - await xfs.mktempPromise(async cwd => { - await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({ - exitCode: 0, - stderr: ``, - }); - }); -}); - // Note that we don't prevent using any package manager. This ensures that // projects will receive as little disruption as possible (for example, we // don't prompt to set the packageManager field). @@ -1463,3 +804,55 @@ it(`should download yarn berry from custom registry`, async () => { }); }); }); + +for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK_NPM_PASSWORD`]) { + describe(`custom registry with auth ${authType}`, () => { + beforeEach(() => { + process.env.AUTH_TYPE = authType; // See `_registryServer.mjs` + }); + + it(`should download yarn classic`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`yarn@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `yarn: Hello from custom registry\n`, + stderr: ``, + }); + }); + }); + + it(`should download yarn berry`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + packageManager: `yarn@3.0.0`, + }); + + await expect(runCli(cwd, [`yarn@5.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `yarn: Hello from custom registry\n`, + stderr: ``, + }); + }); + }); + + it(`should download pnpm`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`pnpm@1.x`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: ``, + }); + }); + }); + + it(`should download custom package manager`, async () => { + await xfs.mktempPromise(async cwd => { + await expect(runCli(cwd, [`customPkgManager@https://registry.npmjs.org/customPkgManager/-/customPkgManager-1.0.0.tgz`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `customPkgManager: Hello from custom registry\n`, + stderr: ``, + }); + }); + }); + }); +} From 8cb977f25785a8d3ad5386a53ee8871471da7a3d Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 17 Mar 2024 15:49:35 +0100 Subject: [PATCH 7/7] Ensure no internet access during tests --- tests/_registryServer.mjs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/_registryServer.mjs b/tests/_registryServer.mjs index 759e35e7..9d62b99f 100644 --- a/tests/_registryServer.mjs +++ b/tests/_registryServer.mjs @@ -142,4 +142,14 @@ switch (process.env.AUTH_TYPE) { default: throw new Error(`Invalid AUTH_TYPE in env`, {cause: process.env.AUTH_TYPE}); } +if (process.env.NOCK_ENV === `replay`) { + const originalFetch = globalThis.fetch; + globalThis.fetch = function fetch(i) { + if (!`${i}`.startsWith(`http://${address.includes(`:`) ? `[${address}]` : address}:${port}`)) + throw new Error; + + return Reflect.apply(originalFetch, this, arguments); + }; +} + server.unref();