From 634203727cdf49eff8a185bcfbfdbe44648ded84 Mon Sep 17 00:00:00 2001 From: Tim Keir Date: Thu, 4 Jun 2026 15:09:20 +1000 Subject: [PATCH] Ignore cache misses prior to fetch step --- .yarn/versions/216387e5.yml | 36 +++++++++++++++++++++ packages/yarnpkg-core/sources/Project.ts | 11 +++++-- packages/yarnpkg-core/tests/Project.test.ts | 33 +++++++++++++++---- 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 .yarn/versions/216387e5.yml diff --git a/.yarn/versions/216387e5.yml b/.yarn/versions/216387e5.yml new file mode 100644 index 000000000000..6c24923445d8 --- /dev/null +++ b/.yarn/versions/216387e5.yml @@ -0,0 +1,36 @@ +releases: + "@yarnpkg/core": patch + +declined: + - "@yarnpkg/plugin-catalog" + - "@yarnpkg/plugin-compat" + - "@yarnpkg/plugin-constraints" + - "@yarnpkg/plugin-dlx" + - "@yarnpkg/plugin-essentials" + - "@yarnpkg/plugin-exec" + - "@yarnpkg/plugin-file" + - "@yarnpkg/plugin-git" + - "@yarnpkg/plugin-github" + - "@yarnpkg/plugin-http" + - "@yarnpkg/plugin-init" + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-jsr" + - "@yarnpkg/plugin-link" + - "@yarnpkg/plugin-nm" + - "@yarnpkg/plugin-npm" + - "@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/cli" + - "@yarnpkg/doctor" + - "@yarnpkg/extensions" + - "@yarnpkg/nm" + - "@yarnpkg/pnpify" + - "@yarnpkg/sdks" diff --git a/packages/yarnpkg-core/sources/Project.ts b/packages/yarnpkg-core/sources/Project.ts index 8e42251dc68c..ebe9089d09bd 100644 --- a/packages/yarnpkg-core/sources/Project.ts +++ b/packages/yarnpkg-core/sources/Project.ts @@ -1097,6 +1097,7 @@ export class Project { mockedPackages: this.disabledLocators, unstablePackages: this.conditionalLocators, }; + const initialCacheMisses = new Set(report.cacheMisses); const fetcher = userFetcher || this.configuration.makeFetcher(); const fetcherOptions = {checksums: this.storedChecksums, project: this, cache, fetcher, report, cacheOptions}; @@ -1165,8 +1166,12 @@ export class Project { ? await this.cacheCleanup({cache, report}) : null; - if (report.cacheMisses.size > 0 || cleanInfo) { - const addedSizes = await Promise.all([...report.cacheMisses].map(async locatorHash => { + const fetchCacheMisses = [...report.cacheMisses].filter(locatorHash => { + return !initialCacheMisses.has(locatorHash); + }); + + if (fetchCacheMisses.length > 0 || cleanInfo) { + const addedSizes = await Promise.all(fetchCacheMisses.map(async locatorHash => { const locator = this.storedPackages.get(locatorHash); const checksum = this.storedChecksums.get(locatorHash) ?? null; @@ -1178,7 +1183,7 @@ export class Project { const finalSizeChange = addedSizes.reduce((sum, size) => sum + size, 0) - (cleanInfo?.size ?? 0); - const addedCount = report.cacheMisses.size; + const addedCount = fetchCacheMisses.length; const removedCount = cleanInfo?.count ?? 0; const addedLine = `${miscUtils.plural(addedCount, { diff --git a/packages/yarnpkg-core/tests/Project.test.ts b/packages/yarnpkg-core/tests/Project.test.ts index c00b449da738..f345856c0854 100644 --- a/packages/yarnpkg-core/tests/Project.test.ts +++ b/packages/yarnpkg-core/tests/Project.test.ts @@ -1,10 +1,10 @@ -import {Cache, Configuration, Project, ThrowReport, structUtils, LocatorHash, Package} from '@yarnpkg/core'; -import {Filename, PortablePath, ppath, xfs} from '@yarnpkg/fslib'; -import LinkPlugin from '@yarnpkg/plugin-link'; -import PnpPlugin from '@yarnpkg/plugin-pnp'; -import v8 from 'v8'; +import {Cache, Configuration, Project, ThrowReport, structUtils, LocatorHash, Package, InstallMode} from '@yarnpkg/core'; +import {Filename, PortablePath, ppath, xfs} from '@yarnpkg/fslib'; +import LinkPlugin from '@yarnpkg/plugin-link'; +import PnpPlugin from '@yarnpkg/plugin-pnp'; +import v8 from 'v8'; -import {TestPlugin} from './TestPlugin'; +import {TestPlugin} from './TestPlugin'; const getConfiguration = (p: PortablePath) => { return Configuration.create(p, p, new Map([ @@ -301,4 +301,25 @@ describe(`Project`, () => { await expect(project.restoreInstallState()).resolves.toBeUndefined(); }); }); + + it(`should ignore cache misses recorded before the fetch step`, async() => { + await xfs.mktempPromise(async dir => { + await xfs.writeJsonPromise(ppath.join(dir, Filename.manifest), {name: `foo`}); + await xfs.writeFilePromise(ppath.join(dir, Filename.lockfile), ``); + + const configuration = getConfiguration(dir); + const {project} = await Project.find(configuration, dir); + const cache = await Cache.find(configuration); + const report = new ThrowReport(); + + report.cacheMisses.add(`preexisting-cache-miss` as LocatorHash); + + await expect(project.fetchEverything({ + cache, + report, + mode: InstallMode.UpdateLockfile, + persistProject: false, + })).resolves.toBeUndefined(); + }); + }); });