From b2963e0eb7ebf415001951bf90d08698eb30593b Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:50:05 -0700 Subject: [PATCH] fix(ci): update the setup-workspace cache assertions to the widened path list #9596/#9597 changed the node_modules cache to glob every workspace and added a generation salt to the key, but the composite-action test still asserted the old literal `apps/loopover-ui/node_modules`, so it has been failing on main and on every branch since. Assert the contract that now holds, and tighten it in two places the old test left open: - both workspace globs, matching what package.json declares; - the `npm-v2-` salt, asserted beside the paths, because widening the paths without bumping the salt is a no-op and the two must move together; - the SAVE step's path list equals the RESTORE step's -- the save list decides what a future run can restore, so a narrowing there would stay invisible until some later job failed on a missing workspace. --- test/unit/ci-composite-setup-workspace.test.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/unit/ci-composite-setup-workspace.test.ts b/test/unit/ci-composite-setup-workspace.test.ts index fdc5109d60..033df1210d 100644 --- a/test/unit/ci-composite-setup-workspace.test.ts +++ b/test/unit/ci-composite-setup-workspace.test.ts @@ -53,7 +53,15 @@ describe("setup-workspace composite action", () => { expect(restore.uses).toContain("actions/cache/restore@"); const restoreWith = record(restore.with, "restore.with"); expect(String(restoreWith.path)).toContain("node_modules"); - expect(String(restoreWith.path)).toContain("apps/loopover-ui/node_modules"); + // #9596: the path list must cover EVERY workspace, via the same globs package.json declares -- npm + // decides per dependency whether it hoists to the root or nests under a workspace, and pinning one app + // by name is what let a cache hit restore a tree with no apps/loopover-miner-ui/node_modules at all. + expect(String(restoreWith.path)).toContain("apps/*/node_modules"); + expect(String(restoreWith.path)).toContain("packages/*/node_modules"); + // #9597: the path list and the KEY must move together. Widening the paths alone changes nothing -- + // an unchanged lockfile keeps hitting the entry archived under the old list -- so the generation salt + // is asserted here, beside the paths, to keep the two from drifting apart again. + expect(String(restoreWith.key)).toContain("npm-v2-"); expect(String(restoreWith.key)).toContain("hashFiles('package.json', 'apps/*/package.json', 'packages/*/package.json', 'package-lock.json')"); expect(String(restoreWith.key)).toContain("package.json"); expect(String(restoreWith.key)).toContain("apps/*/package.json"); @@ -74,6 +82,9 @@ describe("setup-workspace composite action", () => { expect(save.uses).toContain("actions/cache/save@"); const saveWith = record(save.with, "save.with"); expect(saveWith.key).toBe("${{ steps.node-modules-cache.outputs.cache-primary-key }}"); + // The SAVE list is the one that decides what a future run can restore, so a narrowing here would be + // invisible until some later job failed on a missing workspace -- assert it matches the restore list. + expect(String(saveWith.path)).toBe(String(restoreWith.path)); // Save must come after install (a broken/partial node_modules from a failed install step is never reached). const stepNames = steps.map((s) => s.name);