Skip to content

Commit 34271ed

Browse files
authored
Implements --refresh-lockfile (#4299)
* Implements --refresh-lockfile * Allows network access in CI
1 parent 1d85482 commit 34271ed

File tree

4 files changed

+134
-3
lines changed

4 files changed

+134
-3
lines changed

.github/workflows/integration-workflow.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ jobs:
3232
run: |
3333
node ./scripts/run-yarn.js --immutable --immutable-cache
3434
shell: bash
35-
env:
36-
YARN_ENABLE_NETWORK: 0
3735

3836
- name: 'Check that the cache files are consistent with their remote sources'
3937
run: |

.yarn/versions/bcc9db40.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
releases:
2+
"@yarnpkg/cli": minor
3+
"@yarnpkg/plugin-essentials": minor
4+
5+
declined:
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-init"
10+
- "@yarnpkg/plugin-interactive-tools"
11+
- "@yarnpkg/plugin-nm"
12+
- "@yarnpkg/plugin-npm-cli"
13+
- "@yarnpkg/plugin-pack"
14+
- "@yarnpkg/plugin-patch"
15+
- "@yarnpkg/plugin-pnp"
16+
- "@yarnpkg/plugin-pnpm"
17+
- "@yarnpkg/plugin-stage"
18+
- "@yarnpkg/plugin-typescript"
19+
- "@yarnpkg/plugin-version"
20+
- "@yarnpkg/plugin-workspace-tools"
21+
- "@yarnpkg/builder"
22+
- "@yarnpkg/core"
23+
- "@yarnpkg/doctor"

packages/acceptance-tests/pkg-tests-specs/sources/commands/install.test.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,107 @@ describe(`Commands`, () => {
7979
}),
8080
);
8181

82+
test(
83+
`it should update the lockfile when using --refresh-lockfile`,
84+
makeTemporaryEnv({
85+
dependencies: {
86+
[`one-fixed-dep`]: `1.0.0`,
87+
},
88+
}, async ({path, run, source}) => {
89+
await run(`install`);
90+
91+
// Sanity check
92+
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
93+
name: `one-fixed-dep`,
94+
version: `1.0.0`,
95+
dependencies: {
96+
[`no-deps`]: {
97+
name: `no-deps`,
98+
version: `1.0.0`,
99+
},
100+
},
101+
});
102+
103+
const lockfilePath = ppath.join(path, Filename.lockfile);
104+
const lockfileContent = await xfs.readFilePromise(lockfilePath, `utf8`);
105+
const modifiedLockfile = lockfileContent.replace(/no-deps: 1.0.0/, `no-deps: 2.0.0`);
106+
await xfs.writeFilePromise(lockfilePath, modifiedLockfile);
107+
108+
await run(`install`);
109+
110+
// Sanity check
111+
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
112+
name: `one-fixed-dep`,
113+
version: `1.0.0`,
114+
dependencies: {
115+
[`no-deps`]: {
116+
name: `no-deps`,
117+
version: `2.0.0`,
118+
},
119+
},
120+
});
121+
122+
await run(`install`, `--refresh-lockfile`);
123+
124+
// Actual test
125+
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
126+
name: `one-fixed-dep`,
127+
version: `1.0.0`,
128+
dependencies: {
129+
[`no-deps`]: {
130+
name: `no-deps`,
131+
version: `1.0.0`,
132+
},
133+
},
134+
});
135+
}),
136+
);
137+
138+
test(
139+
`it should block invalid lockfiles when using --refresh-lockfile with --immutable`,
140+
makeTemporaryEnv({
141+
dependencies: {
142+
[`one-fixed-dep`]: `1.0.0`,
143+
},
144+
}, async ({path, run, source}) => {
145+
await run(`install`);
146+
147+
const lockfilePath = ppath.join(path, Filename.lockfile);
148+
const lockfileContent = await xfs.readFilePromise(lockfilePath, `utf8`);
149+
const modifiedLockfile = lockfileContent.replace(/no-deps: 1.0.0/, `no-deps: 2.0.0`);
150+
await xfs.writeFilePromise(lockfilePath, modifiedLockfile);
151+
152+
await run(`install`);
153+
154+
await expect(run(`install`, `--immutable`, `--refresh-lockfile`)).rejects.toThrow(/YN0028/);
155+
}),
156+
);
157+
158+
test(
159+
`it should enable --refresh-lockfile --immutable by default in PR CIs`,
160+
makeTemporaryEnv({
161+
dependencies: {
162+
[`one-fixed-dep`]: `1.0.0`,
163+
},
164+
}, async ({path, run, source}) => {
165+
await run(`install`);
166+
167+
const lockfilePath = ppath.join(path, Filename.lockfile);
168+
const lockfileContent = await xfs.readFilePromise(lockfilePath, `utf8`);
169+
const modifiedLockfile = lockfileContent.replace(/no-deps: 1.0.0/, `no-deps: 2.0.0`);
170+
await xfs.writeFilePromise(lockfilePath, modifiedLockfile);
171+
172+
await run(`install`);
173+
174+
await expect(run(`install`, {
175+
env: {
176+
GITHUB_ACTIONS: `true`,
177+
GITHUB_EVENT_NAME: `pull_request`,
178+
},
179+
})).rejects.toThrow(/YN0028/);
180+
}),
181+
);
182+
82183
test(
83184
`it should accept to add files to the cache when using --immutable without --immutable-cache`,
84185
makeTemporaryEnv({

packages/plugin-essentials/sources/commands/install.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export default class YarnCommand extends BaseCommand {
3232
3333
If the \`--immutable-cache\` option is set, Yarn will abort with an error exit code if the cache folder was to be modified (either because files would be added, or because they'd be removed).
3434
35+
If the \`--refresh-lockfile\` option is set, Yarn will keep the same resolution for the packages currently in the lockfile but will refresh their metadata. If used together with \`--immutable\`, it can validate that the lockfile information are consistent. This flag is enabled by default when Yarn detects it runs within a pull request context.
36+
3537
If the \`--check-cache\` option is set, Yarn will always refetch the packages and will ensure that their checksum matches what's 1/ described in the lockfile 2/ inside the existing cache files (if present). This is recommended as part of your CI workflow if you're both following the Zero-Installs model and accepting PRs from third-parties, as they'd otherwise have the ability to alter the checked-in packages before submitting them.
3638
3739
If the \`--inline-builds\` option is set, Yarn will verbosely print the output of the build steps of your dependencies (instead of writing them into individual files). This is likely useful mostly for debug purposes only when using Docker-like environments.
@@ -66,7 +68,11 @@ export default class YarnCommand extends BaseCommand {
6668
description: `Abort with an error exit code if the cache folder was to be modified`,
6769
});
6870

69-
checkCache = Option.Boolean(`--check-cache`, false, {
71+
refreshLockfile = Option.Boolean(`--refresh-lockfile`, {
72+
description: `Refresh the package metadata stored in the lockfile`,
73+
});
74+
75+
checkCache = Option.Boolean(`--check-cache`, {
7076
description: `Always refetch the packages and ensure that their checksums are consistent`,
7177
});
7278

@@ -309,6 +315,9 @@ export default class YarnCommand extends BaseCommand {
309315
restoreResolutions: false,
310316
});
311317

318+
if (this.refreshLockfile ?? CI.isPR)
319+
project.lockfileNeedsRefresh = true;
320+
312321
// Important: Because other commands also need to run installs, if you
313322
// get in a situation where you need to change this file in order to
314323
// customize the install it's very likely you're doing something wrong.

0 commit comments

Comments
 (0)