From 425709b3cd6ac5bbcd14ed3987ea3f87d0dd8c94 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 8 Feb 2025 12:10:09 +0100 Subject: [PATCH 1/9] feat: add support for `.corepack.env` --- README.md | 9 +++ sources/npmRegistryUtils.ts | 2 + sources/specUtils.ts | 60 ++++++++++++---- sources/types.ts | 2 + tests/main.test.ts | 138 ++++++++++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index fea1e2c8f..47eb8f8b6 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,7 @@ same major line. Should you need to upgrade to a new major, use an explicit set to `1` to have the URL shown. By default, when Corepack is called explicitly (e.g. `corepack pnpm …`), it is set to `0`; when Corepack is called implicitly (e.g. `pnpm …`), it is set to `1`. + The default value cannot be overridden in a `.corepack.env` file. When standard input is a TTY and no CI environment is detected, Corepack will ask for user input before starting the download. @@ -292,6 +293,14 @@ same major line. Should you need to upgrade to a new major, use an explicit project. This means that it will always use the system-wide package manager regardless of what is being specified in the project's `packageManager` field. +- `COREPACK_ENV_FILE` can be set to `0` to request Corepack to not attempt to + load `.corepack.env`; it can be set to a path to specify a different env file. + Only keys that starts with `COREPACK_` will be taken into account, not all + keys that start with `COREPACK_` will be taken into account ( + `COREPACK_ENABLE_DOWNLOAD_PROMPT` and `COREPACK_ENV_FILE` are ignored). + For Node.js 18.x users, this setting has no effect as that version doesn't + support parsing of `.env` files. + - `COREPACK_HOME` can be set in order to define where Corepack should install the package managers. By default it is set to `%LOCALAPPDATA%\node\corepack` on Windows, and to `$HOME/.cache/node/corepack` everywhere else. diff --git a/sources/npmRegistryUtils.ts b/sources/npmRegistryUtils.ts index 963241755..04274321c 100644 --- a/sources/npmRegistryUtils.ts +++ b/sources/npmRegistryUtils.ts @@ -38,6 +38,8 @@ export function verifySignature({signatures, integrity, packageName, version}: { packageName: string; version: string; }) { + if (signatures == null) throw new Error(`No compatible signature found in package metadata for ${packageName}@${version}`); + const {npm: keys} = process.env.COREPACK_INTEGRITY_KEYS ? JSON.parse(process.env.COREPACK_INTEGRITY_KEYS) as typeof defaultConfig.keys : defaultConfig.keys; diff --git a/sources/specUtils.ts b/sources/specUtils.ts index a75b10ffd..5f83cca29 100644 --- a/sources/specUtils.ts +++ b/sources/specUtils.ts @@ -1,13 +1,15 @@ -import {UsageError} from 'clipanion'; -import fs from 'fs'; -import path from 'path'; -import semverValid from 'semver/functions/valid'; - -import {PreparedPackageManagerInfo} from './Engine'; -import * as debugUtils from './debugUtils'; -import {NodeError} from './nodeUtils'; -import * as nodeUtils from './nodeUtils'; -import {Descriptor, isSupportedPackageManager} from './types'; +import {UsageError} from 'clipanion'; +import fs from 'fs'; +import path from 'path'; +import semverValid from 'semver/functions/valid'; +import {parseEnv} from 'util'; + +import type {PreparedPackageManagerInfo} from './Engine'; +import * as debugUtils from './debugUtils'; +import type {NodeError} from './nodeUtils'; +import * as nodeUtils from './nodeUtils'; +import {isSupportedPackageManager} from './types'; +import type {LocalEnvFile, Descriptor} from './types'; const nodeModulesRegExp = /[\\/]node_modules[\\/](@[^\\/]*[\\/])?([^@\\/][^\\/]*)$/; @@ -72,10 +74,11 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM }; } +type FoundSpecResult = {type: `Found`, target: string, spec: Descriptor, envFilePath?: string}; export type LoadSpecResult = | {type: `NoProject`, target: string} | {type: `NoSpec`, target: string} - | {type: `Found`, target: string, spec: Descriptor}; + | FoundSpecResult; export async function loadSpec(initialCwd: string): Promise { let nextCwd = initialCwd; @@ -84,6 +87,8 @@ export async function loadSpec(initialCwd: string): Promise { let selection: { data: any; manifestPath: string; + envFilePath?: string; + localEnv: LocalEnvFile; } | null = null; while (nextCwd !== currCwd && (!selection || !selection.data.packageManager)) { @@ -111,19 +116,50 @@ export async function loadSpec(initialCwd: string): Promise { if (typeof data !== `object` || data === null) throw new UsageError(`Invalid package.json in ${path.relative(initialCwd, manifestPath)}`); - selection = {data, manifestPath}; + let localEnv: LocalEnvFile; + const envFilePath = path.resolve(currCwd, process.env.COREPACK_ENV_FILE ?? `.corepack.env`); + if (process.env.COREPACK_ENV_FILE == `0`) { + debugUtils.log(`Skipping env file as configured with COREPACK_ENV_FILE`); + localEnv = process.env; + } else { + debugUtils.log(`Checking ${envFilePath}`); + try { + localEnv = { + ...Object.fromEntries(Object.entries(parseEnv(await fs.promises.readFile(envFilePath, `utf8`))).filter(e => e[0].startsWith(`COREPACK_`))), + ...process.env, + }; + debugUtils.log(`Successfully loaded env file found at ${envFilePath}`); + } catch (err) { + if ((err as NodeError)?.code !== `ENOENT`) + throw err; + + debugUtils.log(`No env file found at ${envFilePath}`); + localEnv = process.env; + } + } + + selection = {data, manifestPath, localEnv, envFilePath}; } if (selection === null) return {type: `NoProject`, target: path.join(initialCwd, `package.json`)}; + let envFilePath: string | undefined; + if (selection.localEnv !== process.env) { + envFilePath = selection.envFilePath; + process.env = selection.localEnv; + } + const rawPmSpec = selection.data.packageManager; if (typeof rawPmSpec === `undefined`) return {type: `NoSpec`, target: selection.manifestPath}; + debugUtils.log(`${selection.manifestPath} defines ${rawPmSpec} as local package manager`); + return { type: `Found`, target: selection.manifestPath, + envFilePath, spec: parseSpec(rawPmSpec, path.relative(initialCwd, selection.manifestPath)), }; } diff --git a/sources/types.ts b/sources/types.ts index b9fe3e370..1af427ce1 100644 --- a/sources/types.ts +++ b/sources/types.ts @@ -160,3 +160,5 @@ export interface LazyLocator { */ reference: () => Promise; } + +export type LocalEnvFile = Record; diff --git a/tests/main.test.ts b/tests/main.test.ts index 92cc0e687..535ba0128 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -906,6 +906,144 @@ it(`should download latest pnpm from custom registry`, async () => { }); }); +describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => { + beforeEach(() => { + process.env.AUTH_TYPE = `COREPACK_NPM_TOKEN`; // See `_registryServer.mjs` + process.env.COREPACK_DEFAULT_TO_LATEST = `1`; + }); + + it(`from env variable`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + }); + + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`No compatible signature found in package metadata`), + }); + + process.env.COREPACK_INTEGRITY_KEYS = `0`; + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: expect.stringContaining(`The local project doesn't define a 'packageManager' field`), + }); + }); + }); + + it(`from .corepack.env file`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + }); + + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`No compatible signature found in package metadata`), + }); + + await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`); + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: expect.stringContaining(`The local project doesn't define a 'packageManager' field`), + }); + }); + }); + + it(`from env file defined by COREPACK_ENV_FILE`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + }); + + await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS={}\n`); + await xfs.writeFilePromise(ppath.join(cwd, `.other.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`); + + // By default, Corepack should be using .corepack.env and fail. + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`No compatible signature found in package metadata`), + }); + + process.env.COREPACK_ENV_FILE = `.other.env`; + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: expect.stringContaining(`The local project doesn't define a 'packageManager' field`), + }); + }); + }); + + it(`from env even if there's a .corepack.env file`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + }); + + await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS={}\n`); + + // By default, Corepack should be using .corepack.env and fail. + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`No compatible signature found in package metadata`), + }); + + process.env.COREPACK_INTEGRITY_KEYS = ``; + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: expect.stringContaining(`The local project doesn't define a 'packageManager' field`), + }); + }); + }); + + it(`should ignore .corepack.env file if COREPACK_ENV_FILE is set to 0`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + }); + + await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`); + + process.env.COREPACK_ENV_FILE = `0`; + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`No compatible signature found in package metadata`), + }); + + delete process.env.COREPACK_ENV_FILE; + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: expect.stringContaining(`The local project doesn't define a 'packageManager' field`), + }); + }); + }); + + it(`from env file defined by COREPACK_ENV_FILE`, async () => { + process.env.COREPACK_ENV_FILE = `.other.env`; + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + }); + + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 1, + stdout: ``, + stderr: expect.stringContaining(`No compatible signature found in package metadata`), + }); + + await xfs.writeFilePromise(ppath.join(cwd, `.other.env` as Filename), `COREPACK_INTEGRITY_KEYS=0\n`); + await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ + exitCode: 0, + stdout: `pnpm: Hello from custom registry\n`, + stderr: expect.stringContaining(`The local project doesn't define a 'packageManager' field`), + }); + }); + }); +}); + for (const authType of [`COREPACK_NPM_REGISTRY`, `COREPACK_NPM_TOKEN`, `COREPACK_NPM_PASSWORD`, `PROXY`]) { describe(`custom registry with auth ${authType}`, () => { beforeEach(() => { From 4f492c9b7dd0a9fc8d0b865bc01c6e3a93c70236 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 8 Feb 2025 19:55:40 +0100 Subject: [PATCH 2/9] skip env file tests on Node.js 18.x --- tests/main.test.ts | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/main.test.ts b/tests/main.test.ts index 535ba0128..615537cb5 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -932,7 +932,10 @@ describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => { }); }); - it(`from .corepack.env file`, async () => { + it(`from .corepack.env file`, async t => { + // Skip that test on Node.js 18.x as it lacks support for .env files. + if (process.version.startsWith(`v18.`)) t.skip(); + await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { }); @@ -952,7 +955,10 @@ describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => { }); }); - it(`from env file defined by COREPACK_ENV_FILE`, async () => { + it(`from env file defined by COREPACK_ENV_FILE`, async t => { + // Skip that test on Node.js 18.x as it lacks support for .env files. + if (process.version.startsWith(`v18.`)) t.skip(); + await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { }); @@ -983,7 +989,7 @@ describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => { await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_INTEGRITY_KEYS={}\n`); - // By default, Corepack should be using .corepack.env and fail. + // By default, Corepack should be using .corepack.env (or the built-in ones on Node.js 18.x) and fail. await expect(runCli(cwd, [`pnpm`, `--version`], true)).resolves.toMatchObject({ exitCode: 1, stdout: ``, @@ -999,7 +1005,10 @@ describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => { }); }); - it(`should ignore .corepack.env file if COREPACK_ENV_FILE is set to 0`, async () => { + it(`should ignore .corepack.env file if COREPACK_ENV_FILE is set to 0`, async t => { + // Skip that test on Node.js 18.x as it lacks support for .env files. + if (process.version.startsWith(`v18.`)) t.skip(); + await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { }); @@ -1022,7 +1031,10 @@ describe(`should pick up COREPACK_INTEGRITY_KEYS from env`, () => { }); }); - it(`from env file defined by COREPACK_ENV_FILE`, async () => { + it(`from env file defined by COREPACK_ENV_FILE`, async t => { + // Skip that test on Node.js 18.x as it lacks support for .env files. + if (process.version.startsWith(`v18.`)) t.skip(); + process.env.COREPACK_ENV_FILE = `.other.env`; await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { From dbb2cc414acaa0f55a2199ce8f73138f0724af46 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 10 Feb 2025 23:59:14 +0100 Subject: [PATCH 3/9] fixup --- sources/specUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sources/specUtils.ts b/sources/specUtils.ts index 5f83cca29..56ee80405 100644 --- a/sources/specUtils.ts +++ b/sources/specUtils.ts @@ -121,6 +121,10 @@ export async function loadSpec(initialCwd: string): Promise { if (process.env.COREPACK_ENV_FILE == `0`) { debugUtils.log(`Skipping env file as configured with COREPACK_ENV_FILE`); localEnv = process.env; + } else if (typeof parseEnv !== `function`) { + // TODO: remove this block when support for Node.js 18.x is dropped. + debugUtils.log(`Skipping env file as it is not supported by the current version of Node.js`); + localEnv = process.env; } else { debugUtils.log(`Checking ${envFilePath}`); try { From f53f22025416ec812d557728bd8cc140f7874b7d Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 12 Feb 2025 11:18:52 +0100 Subject: [PATCH 4/9] add test for `COREPACK_ENABLE_AUTO_PIN` --- tests/main.test.ts | 68 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/tests/main.test.ts b/tests/main.test.ts index 615537cb5..eb760ff9c 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -318,18 +318,72 @@ for (const name of SupportedPackageManagerSet) { }); } -it(`should configure the project when calling a package manager on it for the first time`, async () => { - await xfs.mktempPromise(async cwd => { - await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { +describe.only(`when called on a project without any defined packageManager`, () => { + it(`should append the field to package.json by default`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + + await runCli(cwd, [`yarn`]); + + const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename)); + + expect(data).toMatchObject({ + packageManager: `yarn@${config.definitions.yarn.default}`, + }); + }); + }); + + it(`should not modify package.json if disabled by env`, async () => { + process.env.COREPACK_ENABLE_AUTO_PIN = `0`; + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { // empty package.json file + }); + + await runCli(cwd, [`yarn`]); + + const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename)); + + expect(Object.hasOwn(data, `packageManager`)).toBeFalsy(); }); + }); + + it(`should not modify package.json if disabled by .corepack.env`, async t => { + // Skip that test on Node.js 18.x as it lacks support for .env files. + if (process.version.startsWith(`v18.`)) t.skip(); + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_ENABLE_AUTO_PIN=0\n`); + + await runCli(cwd, [`yarn`]); - await runCli(cwd, [`yarn`]); + const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename)); - const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename)); + expect(Object.hasOwn(data, `packageManager`)).toBeFalsy(); + }); + }); + it(`should modify package.json if .corepack.env if disabled`, async () => { + process.env.COREPACK_ENV_FILE = `0`; + + await xfs.mktempPromise(async cwd => { + await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { + // empty package.json file + }); + await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env` as Filename), `COREPACK_ENABLE_AUTO_PIN=0\n`); + + await runCli(cwd, [`yarn`]); - expect(data).toMatchObject({ - packageManager: `yarn@${config.definitions.yarn.default}`, + const data = await xfs.readJsonPromise(ppath.join(cwd, `package.json` as Filename)); + + expect(data).toMatchObject({ + packageManager: `yarn@${config.definitions.yarn.default}`, + }); }); }); }); From 54365fb9865d209747d31879c69bde8090d58761 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 12 Feb 2025 11:20:13 +0100 Subject: [PATCH 5/9] fixup! add test for `COREPACK_ENABLE_AUTO_PIN` --- tests/main.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/main.test.ts b/tests/main.test.ts index eb760ff9c..7bf860e23 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -318,7 +318,7 @@ for (const name of SupportedPackageManagerSet) { }); } -describe.only(`when called on a project without any defined packageManager`, () => { +describe(`when called on a project without any defined packageManager`, () => { it(`should append the field to package.json by default`, async () => { await xfs.mktempPromise(async cwd => { await xfs.writeJsonPromise(ppath.join(cwd, `package.json` as Filename), { From fc05286e4ba0cc4c14c428d846ce6ffd3a6333f1 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 15 Feb 2025 00:02:55 +0100 Subject: [PATCH 6/9] add test for `COREPACK_ENABLE_DOWNLOAD_PROMPT` --- tests/main.test.ts | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/tests/main.test.ts b/tests/main.test.ts index 992b088a1..f4348a28b 100644 --- a/tests/main.test.ts +++ b/tests/main.test.ts @@ -860,16 +860,35 @@ it(`should support package managers in ESM format`, async () => { }); }); -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`, +describe(`should show a warning on stderr before downloading when enable`, () => { + it(`when enabled by the environment`, 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`, + }); }); - 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 ignore setting in .corepack.env`, async () => { + await xfs.mktempPromise(async cwd => { + await xfs.writeFilePromise( + ppath.join(cwd, `.corepack.env` as Filename), + `COREPACK_ENABLE_DOWNLOAD_PROMPT=1\n`, + ); + 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: ``, + }); }); }); }); From ce92d700eec5d23e0adffc68c6dbfb024e69d6ef Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 20 Feb 2025 17:14:23 +0100 Subject: [PATCH 7/9] Update README.md Co-authored-by: Mike McCready <66998419+MikeMcC399@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 47eb8f8b6..183709acc 100644 --- a/README.md +++ b/README.md @@ -295,7 +295,7 @@ same major line. Should you need to upgrade to a new major, use an explicit - `COREPACK_ENV_FILE` can be set to `0` to request Corepack to not attempt to load `.corepack.env`; it can be set to a path to specify a different env file. - Only keys that starts with `COREPACK_` will be taken into account, not all + Only keys that start with `COREPACK_` will be taken into account, not all keys that start with `COREPACK_` will be taken into account ( `COREPACK_ENABLE_DOWNLOAD_PROMPT` and `COREPACK_ENV_FILE` are ignored). For Node.js 18.x users, this setting has no effect as that version doesn't From 5911687280ef728d954de3e06903598edb535b70 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 20 Feb 2025 18:45:07 +0100 Subject: [PATCH 8/9] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 183709acc..c71f58e5d 100644 --- a/README.md +++ b/README.md @@ -295,9 +295,9 @@ same major line. Should you need to upgrade to a new major, use an explicit - `COREPACK_ENV_FILE` can be set to `0` to request Corepack to not attempt to load `.corepack.env`; it can be set to a path to specify a different env file. - Only keys that start with `COREPACK_` will be taken into account, not all - keys that start with `COREPACK_` will be taken into account ( - `COREPACK_ENABLE_DOWNLOAD_PROMPT` and `COREPACK_ENV_FILE` are ignored). + Only keys that start with `COREPACK_` and are not in the exception list + (`COREPACK_ENABLE_DOWNLOAD_PROMPT` and `COREPACK_ENV_FILE` are ignored) + will be taken into account. For Node.js 18.x users, this setting has no effect as that version doesn't support parsing of `.env` files. From 3aad295c8720d0014abcf6af0f8ac3db74629751 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 28 Feb 2025 20:13:12 +0100 Subject: [PATCH 9/9] fixup! Merge branch 'main' into corepack-dot-env --- sources/specUtils.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sources/specUtils.ts b/sources/specUtils.ts index f09f04048..8a015984d 100644 --- a/sources/specUtils.ts +++ b/sources/specUtils.ts @@ -4,6 +4,7 @@ import path from 'path'; import semverSatisfies from 'semver/functions/satisfies'; import semverValid from 'semver/functions/valid'; import semverValidRange from 'semver/ranges/valid'; +import {parseEnv} from 'util'; import {PreparedPackageManagerInfo} from './Engine'; import * as debugUtils from './debugUtils'; @@ -146,7 +147,13 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM }; } -type FoundSpecResult = {type: `Found`, target: string, getSpec: () => Descriptor, range?: Descriptor, envFilePath?: string} & {onFail?: DevEngineDependency['onFail']}}; +interface FoundSpecResult { + type: `Found`; + target: string; + getSpec: () => Descriptor; + range?: Descriptor & {onFail?: DevEngineDependency['onFail']}; + envFilePath?: string; +} export type LoadSpecResult = | {type: `NoProject`, target: string} | {type: `NoSpec`, target: string}