BUILD-11220 Skip redundant cache save when content unchanged - #86
BUILD-11220 Skip redundant cache save when content unchanged#86mikolaj-matuszny-ext-sonarsource wants to merge 17 commits into
Conversation
Agentic Analysis: Early ResultsAgentic Analysis and Context Augmentation are available on your project. Here are some issues that could have been prevented. Follow the links to learn how to put them into action. 14 issue(s) found across 6 file(s):
Analyzed by SonarQube Agentic Analysis in 6.3 s |
…dles from pre-commit
…laceAll, safe shell glob
|
Pushed fixes for the CI failures and review feedback: CI blockers (fixed)
SonarCloud (safe findings fixed)
Design observations (gitar-bot) — not code-changed, flagging for discussion
The branch is ready for your testing. Note the |
| // Relativise each matched file against the longest search-path base that contains it, so the | ||
| // manifest records a stable logical sub-path (machine-independent, identical in main and post). | ||
| const searchPaths = globber.getSearchPaths(); | ||
|
|
||
| const entries: string[] = []; | ||
| for await (const file of globber.globGenerator()) { | ||
| const stat = await fs.lstat(file); | ||
| if (stat.isDirectory()) { | ||
| continue; | ||
| } | ||
| const base = searchPaths.find((p) => file === p || file.startsWith(p + path.sep)) ?? path.dirname(file); | ||
| const rel = path.relative(base, file).split(path.sep).join('/'); |
There was a problem hiding this comment.
💡 Quality: Comment claims 'longest base' but code uses first-match find()
In computeContentDigest, the comment at src/content-manifest.ts:43-44 says each file is relativised "against the longest search-path base that contains it," but the code at line 53 uses searchPaths.find(...), which returns the first matching base in array order, not the longest. In practice this is harmless: @actions/glob reduces overlapping patterns to their common-ancestor root, so a file is contained in at most one search path, and the relativisation is deterministic across the main and post invocations on the same runner (which is all the digest comparison requires). The comment is simply inaccurate and could mislead future maintainers into assuming longest-prefix semantics that aren't implemented. Recommend rewording the comment (e.g. "against the search-path base that contains it") or, if longest-prefix is actually intended, replacing find with a reduce that selects the longest matching p.
Reword the comment to match the actual first-match behavior.:
// Relativise each matched file against the search-path base that contains it (@actions/glob
// reduces overlapping patterns to a single common-ancestor root, so at most one base matches),
// so the manifest records a stable logical sub-path identical in main and post.
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
|
Code Review 👍 Approved with suggestions 2 resolved / 3 findingsImplements a redundant cache save bypass by splitting the action into restore and post-execution save steps. Update the comment in 💡 Quality: Comment claims 'longest base' but code uses first-match find()📄 src/content-manifest.ts:43-54 In Reword the comment to match the actual first-match behavior.✅ 2 resolved✅ Edge Case: Skip rule infers "content unchanged" from restore-time key equality
✅ Quality: Cache save failures are swallowed as warnings only
🤖 Prompt for agentsOptionsAuto-apply is off → Gitar will not commit updates to this branch. Comment with these commands to change:
Was this helpful? React with 👍 / 👎 | Gitar |
|




BUILD-11220 — Skip redundant cache save when content unchanged
Problem
When a feature branch restores the default-branch fallback cache and the cached content is never modified, the action still uploads a full duplicate to S3 under the branch-scoped key. Same content hash, different branch prefix:
The combined
runs-on/cacheaction only skips saving on a full exact-key match; our branch-prefixed keys never match the fallback key, so it always saves. This is a missing capability upstream, not a bug.Fix
Split the combined
runs-on/cachestep into restore-only + a new internalcache-savenode sub-action whose post step performs the save — but skips it when the restored content is provably identical to the default-branch cache.Skip rule: skip when the S3 restore's
cache-matched-keyequals thefallback-exact-keycomputed byprepare-keys.sh(refs/heads/<fallback>/<key>). That equality proves the branch save would be a byte-identical duplicate.fallback-exact-keyempty)lookup-onlyOpt out with
skip-redundant-save: false(defaulttrue).Why a vendored bundle (design note)
The S3 upload is a
runs-on/cachepatch of@actions/cache— stock@actions/cachewrites to GitHub, not S3 — so the save cannot be reimplemented. We also can't useuses: runs-on/cache/save(it runs inline, too early for caches populated mid-job) and a composite can't attach apost:hook to an inneruses:. Socache-save's post step forks the prebuiltdist/save-onlybundle vendored from the exactruns-on/cacheSHA already pinned inaction.yml(88d9064, v5.0.7). Same bytes GitHub already runs — same trust boundary, now SHA256-pinned in-repo (cache-save/vendor/runs-on-save-only/PROVENANCE.md). Refresh viascripts/refresh-runs-on-save.sh <sha>whenever the pin bumps.LIFO post-ordering
cache-saveis placed beforecredential-guardso that, under reverse-order post execution, credential-guard's post re-exports AWS creds toGITHUB_ENVbefore cache-save's post performs the upload.Tests
62 unit tests (vitest), all green. Coverage: decision (all branches),
prepare-keysoutput (feature + default branch), fork wrapper (resolve / exit-nonzero / signal-kill / path resolution), cache-save main (record + error), cache-save post (skip / save / disabled / lookup-only / empty-key).cache-save/distbundles match a freshnpm run build(reproducible).Reviewer testing checklist (e2e — not yet run on a runner)
The highest-risk integration point is mocked in unit tests, so please verify on real runners:
Cache content is identical to the default-branch cache … skipping redundant save, and no S3 object is created for the branch key.path.joinbundle resolution + cred propagation work.skip-redundant-save: false→ duplicate save still occurs.Notes
upload-chunk-sizeis not threaded onto the S3 save path (no SonarSource repo sets it). Documented in README.cache-metrics/distonmasterdiffers from a fresh ncc build (ncc nondeterminism). Left untouched.Refs: BUILD-11220