mirror of https://github.com/nodejs/corepack.git
Merge 43e3feb475 into 273237a110
This commit is contained in:
commit
cb7fca0d08
|
|
@ -286,6 +286,10 @@ same major line. Should you need to upgrade to a new major, use an explicit
|
|||
package manager, and to not update the Last Known Good version when it
|
||||
downloads a new version of the same major line.
|
||||
|
||||
- `COREPACK_DEV_ENGINES_${UPPER_CASE_PACKAGE_MANAGER_NAME}` can be set to give
|
||||
Corepack a specific version matching the range defined in `package.json`'s
|
||||
`devEngines.packageManager` field.
|
||||
|
||||
- `COREPACK_ENABLE_AUTO_PIN` can be set to `0` to prevent Corepack from
|
||||
updating the `packageManager` field when it detects that the local package
|
||||
doesn't list it. In general we recommend to always list a `packageManager`
|
||||
|
|
|
|||
|
|
@ -103,6 +103,17 @@ function parsePackageJSON(packageJSONContent: CorepackPackageJSON) {
|
|||
|
||||
debugUtils.log(`devEngines.packageManager defines that ${name}@${version} is the local package manager`);
|
||||
|
||||
const localEnvKey = `COREPACK_DEV_ENGINES_${packageManager.name.toUpperCase()}`;
|
||||
const localEnvVersion = process.env[localEnvKey];
|
||||
if (localEnvVersion) {
|
||||
debugUtils.log(`Environment defines that ${name}@${localEnvVersion} is the local package manager`);
|
||||
|
||||
if (!semverSatisfies(localEnvVersion, version))
|
||||
warnOrThrow(`"${localEnvKey}" environment variable is set to ${JSON.stringify(localEnvVersion)} which does not match the value defined in "devEngines.packageManager" for ${JSON.stringify(name)} of ${JSON.stringify(version)}`, onFail);
|
||||
|
||||
return `${name}@${localEnvVersion}`;
|
||||
}
|
||||
|
||||
if (pm) {
|
||||
if (!pm.startsWith?.(`${name}@`))
|
||||
warnOrThrow(`"packageManager" field is set to ${JSON.stringify(pm)} which does not match the "devEngines.packageManager" field set to ${JSON.stringify(name)}`, onFail);
|
||||
|
|
@ -131,16 +142,33 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM
|
|||
}
|
||||
|
||||
const content = lookup.type !== `NoProject`
|
||||
? await fs.promises.readFile(lookup.target, `utf8`)
|
||||
? await fs.promises.readFile((lookup as FoundSpecResult).envFilePath ?? lookup.target, `utf8`)
|
||||
: ``;
|
||||
|
||||
const {data, indent} = nodeUtils.readPackageJson(content);
|
||||
let previousPackageManager: string;
|
||||
let newContent: string;
|
||||
if ((lookup as FoundSpecResult).envFilePath) {
|
||||
const {name} = range || (lookup as FoundSpecResult).getSpec();
|
||||
const envKey = `COREPACK_DEV_ENGINES_${name.toUpperCase()}`;
|
||||
const index = content.lastIndexOf(`\n${envKey}=`) + 1;
|
||||
if (index === 0 && !content.startsWith(`${envKey}=`))
|
||||
throw new Error(`INTERNAL ASSERTION ERROR: missing expected ${envKey} in .corepack.env`);
|
||||
|
||||
const previousPackageManager = data.packageManager ?? (range ? `${range.name}@${range.range}` : `unknown`);
|
||||
data.packageManager = `${info.locator.name}@${info.locator.reference}`;
|
||||
const lineEndIndex = content.indexOf(`\n`, index);
|
||||
|
||||
const newContent = nodeUtils.normalizeLineEndings(content, `${JSON.stringify(data, null, indent)}\n`);
|
||||
await fs.promises.writeFile(lookup.target, newContent, `utf8`);
|
||||
previousPackageManager = content.slice(index, lineEndIndex === -1 ? undefined : lineEndIndex);
|
||||
newContent = `${content.slice(0, index)}\n${envKey}=${info.locator.reference}\n${lineEndIndex === -1 ? `` : content.slice(lineEndIndex)}`;
|
||||
} else {
|
||||
const {data, indent} = nodeUtils.readPackageJson(content);
|
||||
|
||||
previousPackageManager = data.packageManager ?? (range ? `${range.name}@${range.range}` : `unknown`);
|
||||
data.packageManager = `${info.locator.name}@${info.locator.reference}`;
|
||||
|
||||
newContent = `${JSON.stringify(data, null, indent)}\n`;
|
||||
}
|
||||
|
||||
newContent = nodeUtils.normalizeLineEndings(content, newContent);
|
||||
await fs.promises.writeFile((lookup as FoundSpecResult).envFilePath ?? lookup.target, newContent, `utf8`);
|
||||
|
||||
return {
|
||||
previousPackageManager,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import process from 'node:process';
|
||||
import {parseEnv} from 'node:util';
|
||||
import {describe, beforeEach, it, expect} from 'vitest';
|
||||
|
||||
import {runCli} from './_runCli';
|
||||
|
|
@ -133,4 +134,42 @@ describe(`UpCommand`, () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
it(`should update the ".corepack.env" file from the current project`, 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 Promise.all([
|
||||
`COREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`COREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
].map(originalEnv => xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines: {packageManager: {name: `yarn`, version: `1.x || 2.x`}},
|
||||
});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env`), originalEnv);
|
||||
|
||||
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@2\.4\.3 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
try {
|
||||
await expect(xfs.readFilePromise(ppath.join(cwd, `.corepack.env`), `utf-8`).then(parseEnv)).resolves.toMatchObject({
|
||||
COREPACK_DEV_ENGINES_YARN: `2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
|
||||
});
|
||||
} catch (cause) {
|
||||
throw new Error(JSON.stringify(originalEnv), {cause});
|
||||
}
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `2.4.3\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
})));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {ppath, xfs, npath} from '@yarnpkg/fslib';
|
||||
import process from 'node:process';
|
||||
import {parseEnv} from 'node:util';
|
||||
import {describe, beforeEach, it, expect} from 'vitest';
|
||||
|
||||
import {runCli} from './_runCli';
|
||||
|
|
@ -115,6 +116,85 @@ describe(`UseCommand`, () => {
|
|||
});
|
||||
});
|
||||
|
||||
it(`should update .corepack.env if present and contains definition for pm version`, 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 Promise.all([
|
||||
`COREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`COREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
].map(originalEnv => xfs.mktempPromise(async cwd => {
|
||||
const pJSONContent = {
|
||||
devEngines: {packageManager: {name: `yarn`, version: `1.x`}},
|
||||
license: `MIT`,
|
||||
};
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), pJSONContent);
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env`), originalEnv);
|
||||
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: expect.stringContaining(`Installing yarn@1.22.4 in the project...`),
|
||||
stderr: ``,
|
||||
});
|
||||
|
||||
try {
|
||||
await expect(xfs.readFilePromise(ppath.join(cwd, `.corepack.env`), `utf-8`).then(parseEnv)).resolves.toMatchObject({
|
||||
COREPACK_DEV_ENGINES_YARN: `1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
} catch (cause) {
|
||||
throw new Error(JSON.stringify(originalEnv), {cause});
|
||||
}
|
||||
// It should not have touched package.json.
|
||||
await expect(xfs.readJsonPromise(ppath.join(cwd, `package.json`))).resolves.toStrictEqual(pJSONContent);
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
});
|
||||
})));
|
||||
});
|
||||
|
||||
it(`should update .other.env if present`, 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 Promise.all([
|
||||
`COREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`COREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
|
||||
].map(originalEnv => xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines: {packageManager: {name: `yarn`, version: `1.x`}},
|
||||
});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.other.env`), `COREPACK_DEV_ENGINES_YARN=1.0.0\n`);
|
||||
|
||||
process.env.COREPACK_ENV_FILE = `.other.env`;
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
});
|
||||
|
||||
try {
|
||||
await expect(xfs.readFilePromise(ppath.join(cwd, `.other.env`), `utf-8`).then(parseEnv)).resolves.toMatchObject({
|
||||
COREPACK_DEV_ENGINES_YARN: `1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
} catch (cause) {
|
||||
throw new Error(JSON.stringify(originalEnv), {cause});
|
||||
}
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
});
|
||||
})));
|
||||
});
|
||||
|
||||
it(`should create a package.json if absent`, async () => {
|
||||
await xfs.mktempPromise(async cwd => {
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
|
|
@ -193,4 +273,43 @@ describe(`UseCommand`, () => {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
it(`should update the ".corepack.env" file from the current project`, 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 Promise.all([
|
||||
`COREPACK_DEV_ENGINES_YARN=2.1.0\n`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=2.1.0\n`,
|
||||
`COREPACK_DEV_ENGINES_YARN=2.1.0`,
|
||||
`\nCOREPACK_DEV_ENGINES_YARN=2.1.0`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=2.1.0\n`,
|
||||
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=2.1.0`,
|
||||
].map(originalEnv => xfs.mktempPromise(async cwd => {
|
||||
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
|
||||
devEngines: {packageManager: {name: `yarn`, version: `1.x || 2.x`}},
|
||||
license: `MIT`, // To avoid Yarn warning.
|
||||
});
|
||||
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env`), originalEnv);
|
||||
|
||||
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stderr: ``,
|
||||
stdout: expect.stringMatching(/^Installing yarn@1\.22\.4 in the project\.\.\.\n\n/),
|
||||
});
|
||||
|
||||
try {
|
||||
await expect(xfs.readFilePromise(ppath.join(cwd, `.corepack.env`), `utf-8`).then(parseEnv)).resolves.toMatchObject({
|
||||
COREPACK_DEV_ENGINES_YARN: `1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
|
||||
});
|
||||
} catch (cause) {
|
||||
throw new Error(JSON.stringify(originalEnv), {cause});
|
||||
}
|
||||
|
||||
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
|
||||
exitCode: 0,
|
||||
stdout: `1.22.4\n`,
|
||||
stderr: ``,
|
||||
});
|
||||
})));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue