Skip to content

Commit 7f848cd

Browse files
committed
fixup
1 parent 892749d commit 7f848cd

5 files changed

Lines changed: 104 additions & 12 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ same major line. Should you need to upgrade to a new major, use an explicit
300300
instruct Corepack to skip integrity checks, or to a JSON string containing
301301
custom keys.
302302

303-
- `COREPACK_DEV_ENGINE_${UPPER_CASE_PACKAGE_MANAGER_NAME}` can be set to give
303+
- `COREPACK_DEV_ENGINES_${UPPER_CASE_PACKAGE_MANAGER_NAME}` can be set to give
304304
Corepack a specific version matching the range defined in `package.json`'s
305305
`devEngines.packageManager` field.
306306

sources/commands/Base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export abstract class BaseCommand extends Command<Context> {
1616
throw new UsageError(`Couldn't find a project in the local directory - please explicit the package manager to pack, or run this command from a valid project`);
1717

1818
case `NoSpec`:
19-
throw new UsageError(`The local project doesn't feature a 'packageManager' field - please explicit the package manager to pack, or update the manifest to reference it`);
19+
throw new UsageError(`The local project doesn't feature a 'packageManager' field nor 'devEngines.packageManager' field - please explicit the package manager to pack, or update the manifest to reference it`);
2020

2121
default: {
2222
return [lookup.spec];

sources/specUtils.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ function parsePackageJSON(packageJSONContent: CorepackPackageJSON, localEnv?: Lo
7575
if (!version)
7676
throw new UsageError(`Providing no version nor ranger for package manager is currently not supported`);
7777

78+
debugUtils.log(`devEngines defines that ${packageManager.name}@${version} is the local package manager`);
79+
7880
const localEnvKey = `COREPACK_DEV_ENGINES_${packageManager.name.toUpperCase()}`;
7981
const localEnvVersion = localEnv?.[localEnvKey];
8082
if (localEnvVersion) {
@@ -107,26 +109,43 @@ export async function setLocalPackageManager(cwd: string, info: PreparedPackageM
107109
const lookup = await loadSpec(cwd);
108110

109111
const content = lookup.type !== `NoProject`
110-
? await fs.promises.readFile(lookup.target, `utf8`)
112+
? await fs.promises.readFile((lookup as FoundSpecResult).envFilePath ?? lookup.target, `utf8`)
111113
: ``;
112114

113-
const {data, indent} = nodeUtils.readPackageJson(content);
115+
let previousPackageManager: string;
116+
let newContent: string;
117+
if ((lookup as FoundSpecResult).envFilePath) {
118+
const envKey = `COREPACK_DEV_ENGINES_${(lookup as FoundSpecResult).spec.name.toUpperCase()}`;
119+
const index = content.lastIndexOf(`\n${envKey}=`) + 1;
120+
121+
if (index === 0 && !content.startsWith(`${envKey}=`))
122+
throw new Error(`INTERNAL ASSERTION ERROR: missing expected ${envKey} in .corepack.env`);
114123

115-
const previousPackageManager = data.packageManager ?? `unknown`;
116-
data.packageManager = `${info.locator.name}@${info.locator.reference}`;
124+
const lineEndIndex = content.indexOf(`\n`, index);
117125

118-
const newContent = nodeUtils.normalizeLineEndings(content, `${JSON.stringify(data, null, indent)}\n`);
119-
await fs.promises.writeFile(lookup.target, newContent, `utf8`);
126+
previousPackageManager = content.slice(index, lineEndIndex === -1 ? undefined : lineEndIndex);
127+
newContent = nodeUtils.normalizeLineEndings(content, `${content.slice(0, index)}\n${envKey}=${info.locator.reference}\n${lineEndIndex === -1 ? `` : content.slice(lineEndIndex)}`);
128+
} else {
129+
const {data, indent} = nodeUtils.readPackageJson(content);
130+
131+
previousPackageManager = data.packageManager ?? `unknown`;
132+
data.packageManager = `${info.locator.name}@${info.locator.reference}`;
133+
134+
newContent = nodeUtils.normalizeLineEndings(content, `${JSON.stringify(data, null, indent)}\n`);
135+
}
136+
137+
await fs.promises.writeFile((lookup as FoundSpecResult).envFilePath ?? lookup.target, newContent, `utf8`);
120138

121139
return {
122140
previousPackageManager,
123141
};
124142
}
125143

144+
type FoundSpecResult = {type: `Found`, target: string, spec: Descriptor, envFilePath?: string};
126145
export type LoadSpecResult =
127146
| {type: `NoProject`, target: string}
128147
| {type: `NoSpec`, target: string}
129-
| {type: `Found`, target: string, spec: Descriptor};
148+
| FoundSpecResult;
130149

131150
export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
132151
let nextCwd = initialCwd;
@@ -135,6 +154,7 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
135154
let selection: {
136155
data: any;
137156
manifestPath: string;
157+
envFilePath?: string;
138158
localEnv?: LocalEnvFile;
139159
} | null = null;
140160

@@ -175,7 +195,7 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
175195
localEnv = process.env;
176196
}
177197

178-
selection = {data, manifestPath, localEnv};
198+
selection = {data, manifestPath, localEnv, envFilePath};
179199
}
180200

181201
if (selection === null)
@@ -185,9 +205,12 @@ export async function loadSpec(initialCwd: string): Promise<LoadSpecResult> {
185205
if (typeof rawPmSpec === `undefined`)
186206
return {type: `NoSpec`, target: selection.manifestPath};
187207

208+
debugUtils.log(`${selection.manifestPath} defines ${rawPmSpec} as local package manager`);
209+
188210
return {
189211
type: `Found`,
190212
target: selection.manifestPath,
213+
envFilePath: selection.localEnv !== process.env ? selection.envFilePath : undefined,
191214
spec: parseSpec(rawPmSpec, path.relative(initialCwd, selection.manifestPath)),
192215
};
193216
}

tests/Up.test.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ppath, xfs, npath} from '@yarnpkg/fslib';
22
import process from 'node:process';
3+
import {parseEnv} from 'node:util';
34
import {describe, beforeEach, it, expect} from 'vitest';
45

56
import {runCli} from './_runCli';
@@ -11,7 +12,7 @@ beforeEach(async () => {
1112
});
1213

1314
describe(`UpCommand`, () => {
14-
it(`should upgrade the package manager from the current project`, async () => {
15+
it(`should update the "packageManager" field from the current project`, async () => {
1516
await xfs.mktempPromise(async cwd => {
1617
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
1718
packageManager: `yarn@2.1.0`,
@@ -32,4 +33,38 @@ describe(`UpCommand`, () => {
3233
});
3334
});
3435
});
36+
37+
it(`should update the ".corepack.env" file from the current project`, async () => {
38+
await Promise.all([
39+
`COREPACK_DEV_ENGINES_YARN=2.1.0\n`,
40+
`\nCOREPACK_DEV_ENGINES_YARN=2.1.0\n`,
41+
`COREPACK_DEV_ENGINES_YARN=2.1.0`,
42+
`\nCOREPACK_DEV_ENGINES_YARN=2.1.0`,
43+
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=2.1.0\n`,
44+
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=2.1.0`,
45+
].map(originalEnv => xfs.mktempPromise(async cwd => {
46+
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
47+
devEngines: {packageManager: {name: `yarn`, version: `2.x`}},
48+
});
49+
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env`), originalEnv);
50+
51+
await expect(runCli(cwd, [`up`])).resolves.toMatchObject({
52+
exitCode: 0,
53+
stderr: ``,
54+
});
55+
56+
try {
57+
await expect(xfs.readFilePromise(ppath.join(cwd, `.corepack.env`), `utf-8`).then(parseEnv)).resolves.toMatchObject({
58+
COREPACK_DEV_ENGINES_YARN: `2.4.3+sha512.8dd9fedc5451829619e526c56f42609ad88ae4776d9d3f9456d578ac085115c0c2f0fb02bb7d57fd2e1b6e1ac96efba35e80a20a056668f61c96934f67694fd0`,
59+
});
60+
} catch (cause) {
61+
throw new Error(JSON.stringify(originalEnv), {cause});
62+
}
63+
64+
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
65+
exitCode: 0,
66+
stdout: `2.4.3\n`,
67+
});
68+
})));
69+
});
3570
});

tests/Use.test.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {ppath, xfs, npath} from '@yarnpkg/fslib';
22
import process from 'node:process';
3+
import {parseEnv} from 'node:util';
34
import {describe, beforeEach, it, expect} from 'vitest';
45

56
import {runCli} from './_runCli';
@@ -11,7 +12,7 @@ beforeEach(async () => {
1112
});
1213

1314
describe(`UseCommand`, () => {
14-
it(`should set the package manager in the current project`, async () => {
15+
it(`should update the "packageManager" field in the current project`, async () => {
1516
await xfs.mktempPromise(async cwd => {
1617
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
1718
packageManager: `yarn@1.0.0`,
@@ -32,6 +33,39 @@ describe(`UseCommand`, () => {
3233
});
3334
});
3435

36+
it(`should update .corepack.env if present`, async () => {
37+
await Promise.all([
38+
`COREPACK_DEV_ENGINES_YARN=1.1.0\n`,
39+
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
40+
`COREPACK_DEV_ENGINES_YARN=1.1.0`,
41+
`\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
42+
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0\n`,
43+
`FOO=bar\nCOREPACK_DEV_ENGINES_YARN=1.1.0`,
44+
].map(originalEnv => xfs.mktempPromise(async cwd => {
45+
await xfs.writeJsonPromise(ppath.join(cwd, `package.json`), {
46+
devEngines: {packageManager: {name: `yarn`, version: `1.x`}},
47+
});
48+
await xfs.writeFilePromise(ppath.join(cwd, `.corepack.env`), `COREPACK_DEV_ENGINES_YARN=1.0.0\n`);
49+
50+
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({
51+
exitCode: 0,
52+
});
53+
54+
try {
55+
await expect(xfs.readFilePromise(ppath.join(cwd, `.corepack.env`), `utf-8`).then(parseEnv)).resolves.toMatchObject({
56+
COREPACK_DEV_ENGINES_YARN: `1.22.4+sha512.a1833b862fe52169bd6c2a033045a07df5bc6a23595c259e675fed1b2d035ab37abe6ce309720abb6636d68f03615054b6292dc0a70da31c8697fda228b50d18`,
57+
});
58+
} catch (cause) {
59+
throw new Error(JSON.stringify(originalEnv), {cause});
60+
}
61+
62+
await expect(runCli(cwd, [`yarn`, `--version`])).resolves.toMatchObject({
63+
exitCode: 0,
64+
stdout: `1.22.4\n`,
65+
});
66+
})));
67+
});
68+
3569
it(`should create a package.json if absent`, async () => {
3670
await xfs.mktempPromise(async cwd => {
3771
await expect(runCli(cwd, [`use`, `yarn@1.22.4`])).resolves.toMatchObject({

0 commit comments

Comments
 (0)