Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/integration-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ jobs:
run: |
node ./scripts/run-yarn.js --immutable --immutable-cache
shell: bash
env:
YARN_ENABLE_NETWORK: 0

- name: 'Check that the cache files are consistent with their remote sources'
run: |
Expand Down
23 changes: 23 additions & 0 deletions .yarn/versions/bcc9db40.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
releases:
"@yarnpkg/cli": minor
"@yarnpkg/plugin-essentials": minor

declined:
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-nm"
- "@yarnpkg/plugin-npm-cli"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-pnpm"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/builder"
- "@yarnpkg/core"
- "@yarnpkg/doctor"
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,107 @@ describe(`Commands`, () => {
}),
);

test(
`it should update the lockfile when using --refresh-lockfile`,
makeTemporaryEnv({
dependencies: {
[`one-fixed-dep`]: `1.0.0`,
},
}, async ({path, run, source}) => {
await run(`install`);

// Sanity check
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
name: `one-fixed-dep`,
version: `1.0.0`,
dependencies: {
[`no-deps`]: {
name: `no-deps`,
version: `1.0.0`,
},
},
});

const lockfilePath = ppath.join(path, Filename.lockfile);
const lockfileContent = await xfs.readFilePromise(lockfilePath, `utf8`);
const modifiedLockfile = lockfileContent.replace(/no-deps: 1.0.0/, `no-deps: 2.0.0`);
await xfs.writeFilePromise(lockfilePath, modifiedLockfile);

await run(`install`);

// Sanity check
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
name: `one-fixed-dep`,
version: `1.0.0`,
dependencies: {
[`no-deps`]: {
name: `no-deps`,
version: `2.0.0`,
},
},
});

await run(`install`, `--refresh-lockfile`);

// Actual test
await expect(source(`require('one-fixed-dep')`)).resolves.toMatchObject({
name: `one-fixed-dep`,
version: `1.0.0`,
dependencies: {
[`no-deps`]: {
name: `no-deps`,
version: `1.0.0`,
},
},
});
}),
);

test(
`it should block invalid lockfiles when using --refresh-lockfile with --immutable`,
makeTemporaryEnv({
dependencies: {
[`one-fixed-dep`]: `1.0.0`,
},
}, async ({path, run, source}) => {
await run(`install`);

const lockfilePath = ppath.join(path, Filename.lockfile);
const lockfileContent = await xfs.readFilePromise(lockfilePath, `utf8`);
const modifiedLockfile = lockfileContent.replace(/no-deps: 1.0.0/, `no-deps: 2.0.0`);
await xfs.writeFilePromise(lockfilePath, modifiedLockfile);

await run(`install`);

await expect(run(`install`, `--immutable`, `--refresh-lockfile`)).rejects.toThrow(/YN0028/);
}),
);

test(
`it should enable --refresh-lockfile --immutable by default in PR CIs`,
makeTemporaryEnv({
dependencies: {
[`one-fixed-dep`]: `1.0.0`,
},
}, async ({path, run, source}) => {
await run(`install`);

const lockfilePath = ppath.join(path, Filename.lockfile);
const lockfileContent = await xfs.readFilePromise(lockfilePath, `utf8`);
const modifiedLockfile = lockfileContent.replace(/no-deps: 1.0.0/, `no-deps: 2.0.0`);
await xfs.writeFilePromise(lockfilePath, modifiedLockfile);

await run(`install`);

await expect(run(`install`, {
env: {
GITHUB_ACTIONS: `true`,
GITHUB_EVENT_NAME: `pull_request`,
},
})).rejects.toThrow(/YN0028/);
}),
);

test(
`it should accept to add files to the cache when using --immutable without --immutable-cache`,
makeTemporaryEnv({
Expand Down
11 changes: 10 additions & 1 deletion packages/plugin-essentials/sources/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export default class YarnCommand extends BaseCommand {

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).

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.

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.

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.
Expand Down Expand Up @@ -66,7 +68,11 @@ export default class YarnCommand extends BaseCommand {
description: `Abort with an error exit code if the cache folder was to be modified`,
});

checkCache = Option.Boolean(`--check-cache`, false, {
refreshLockfile = Option.Boolean(`--refresh-lockfile`, {
description: `Refresh the package metadata stored in the lockfile`,
});

checkCache = Option.Boolean(`--check-cache`, {
description: `Always refetch the packages and ensure that their checksums are consistent`,
});

Expand Down Expand Up @@ -305,6 +311,9 @@ export default class YarnCommand extends BaseCommand {
restoreResolutions: false,
});

if (this.refreshLockfile ?? CI.isPR)
project.lockfileNeedsRefresh = true;

// Important: Because other commands also need to run installs, if you
// get in a situation where you need to change this file in order to
// customize the install it's very likely you're doing something wrong.
Expand Down