Skip to content

Compute Metro cache keys from resolved inputs, fix iOS cache overlap#161

Open
V3RON wants to merge 5 commits into
mainfrom
feat/cache-ci-keys
Open

Compute Metro cache keys from resolved inputs, fix iOS cache overlap#161
V3RON wants to merge 5 commits into
mainfrom
feat/cache-ci-keys

Conversation

@V3RON

@V3RON V3RON commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What is this?

Stacked on #160. Today the GitHub Action's Metro cache step keys off a static hashFiles() glob over lockfiles and Metro/Babel configs — it can't account for a Metro/bundler-metro upgrade, and it produces one static key with no notion of whether a given run actually added anything worth persisting. Separately, once #160 lands, the iOS "Harness cache" step ends up caching the entire .harness/cache root, which now also contains the Metro cache directories — so iOS runs redundantly re-upload Metro's cache under a second, unrelated lifecycle.

How does it work?

The GitHub Action now computes Metro's cache key itself instead of leaning on hashFiles(). A pre-run "plan restore" step walks the repo for the same lockfile/config files as before (fixing a latent bug where the old hashFiles('**/...') pattern could match vendored lockfiles inside node_modules), folds in the resolved @react-native-harness/bundler-metro version and your cache.version salt, and derives a restore key/prefix pair, writing them to .harness/cache/keys.json as a secondary/debug artifact. After the cache is restored, a snapshot step records what's actually on disk. Post-run, a "plan save" step takes a fresh snapshot, diffs it against that pre-run state, and only saves a new immutable cache entry when the content actually changed — gated by a new cacheSavePolicy action input (default-branch by default, so PR runs restore but never write; always or never also available). The key-computation and diffing logic itself lives in @react-native-harness/cache, staying domain-generic so the same mechanism can support other cache domains later. Separately, the iOS "Harness cache" step's cached path is narrowed from the whole .harness/cache root to its actual xctest-agent-simulator-* subdirectory, so it no longer overlaps with Metro's cache.

Why is this useful?

The Metro cache now invalidates correctly on a Metro/Harness upgrade instead of silently going stale, cache uploads only happen when there's genuinely new content to persist (bounding storage churn on an immutable-cache backend), and iOS CI runs stop double-uploading the same Metro cache contents under two different keys.

V3RON added 2 commits July 14, 2026 11:11
Introduce @react-native-harness/cache as the single owner of .harness/cache
layout and warmth checks. Metro's transform cache moves to
.harness/cache/metro and its file-map (haste) cache, previously left in
$TMPDIR, is now pinned to .harness/cache/metro-file-map. Both are enabled by
default via a new `cache` config option group; `unstable__enableMetroCache`
is kept as a deprecated alias for one release. The GitHub Action's cache
step now covers both directories under a bumped cache key.
…erlap

Replace the static hashFiles()-based Metro cache key with keys computed by
Harness itself: lockfiles and Metro/Babel configs (walked from the repo
root, excluding node_modules, fixing a latent overmatch in the old
hashFiles glob), the resolved @react-native-harness/bundler-metro version,
and the cache.version salt. A pre-run "plan restore" step derives the
restore key/prefixes and writes .harness/cache/keys.json; a post-run "plan
save" step diffs the actual cache contents against what was restored and
only saves a new immutable entry when content changed, gated by a new
cacheSavePolicy action input (default-branch/always/never).

Also narrows the iOS "Harness cache" step's cached path from the whole
.harness/cache root to its actual xctest-agent-simulator-* subdirectory,
fixing a double-upload of the Metro cache on iOS runs introduced when both
caches started sharing .harness/cache.
@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-native-harness Ready Ready Preview, Comment Jul 14, 2026 4:05pm

Request Review

The previous commit's plan.ts fix wasn't reflected in the compiled
actions/shared/*.cjs bundles.
Base automatically changed from feat/cache-package to main July 14, 2026 12:58
@V3RON V3RON changed the title feat: compute Metro cache keys from resolved inputs, fix iOS cache overlap Compute Metro cache keys from resolved inputs, fix iOS cache overlap Jul 14, 2026
# Conflicts:
#	action.yml
#	packages/cache/src/index.ts
#	packages/github-action/README.md
#	packages/github-action/src/action.yml
#	website/src/docs/guides/ci-cd.md
…pendency

Metro cache-key resolution always fell back to "unknown" for consumers
where @react-native-harness/bundler-metro is only reachable via
@react-native-harness/jest's own node_modules (e.g. pnpm workspaces,
where transitive workspace deps aren't hoisted to the project root).
Fall back to resolving through jest's package location, mirroring how
the Harness runtime actually loads bundler-metro.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant