Skip to content

Cache by default (mirror setup-node) + DX fixes#4

Merged
colinhacks merged 2 commits into
mainfrom
cache-default-dx-fixes
Jun 22, 2026
Merged

Cache by default (mirror setup-node) + DX fixes#4
colinhacks merged 2 commits into
mainfrom
cache-default-dx-fixes

Conversation

@colinhacks

Copy link
Copy Markdown
Contributor

Cache by default (mirror setup-node)

actions/setup-node enables caching by default via its package-manager-cache input (default true) — caching turns on whenever the project looks installable. setup-nub previously required opt-in cache: true, so drop-in migrators silently got zero caching. This PR mirrors setup-node:

  • New package-manager-cache input (default true) — the disable knob, same name/semantics as setup-node.
  • cache default changed from "false" to "" (unset). Caching now auto-enables when a lockfile (pnpm-lock.yaml, package-lock.json, bun.lock/bun.lockb, yarn.lock) is present, or package.json declares a packageManager/devEngines field.
  • Precedence: an explicit cache value wins (a setup-node PM name like npm/pnpm is still accepted and treated as truthy) → else package-manager-cache: false disables → else auto-detect.
  • Backward-compat preserved: cache: false / package-manager-cache: false disables; cache: npm/pnpm/yarn enables.

The cached set (nub's CAS store, the node toolchain dir, the PM packument cache), keyed on OS/arch + lockfile hash with a restore-keys ladder, is unchanged — only the default flips on plus the disable knob is added.

Smoke jobs added

  • cache-default-on — a lockfile project with no cache: input asserts caching auto-enabled (cache-hit output is a defined boolean).
  • cache-disablepackage-manager-cache: false on a lockfile project asserts caching disabled (cache-hit output empty).

DX fixes (clear, low-risk wins from top setup-node issues)

Folded in alongside the cache change:

  • working-directory input (setup-node #706, 47 reactions) — resolve the Node pin + lockfile from a subdirectory, for monorepos. setup-node has no first-class support for this; it's a recurring monorepo papercut.
  • cache-key-prefix input (setup-node #1320) — inject a prefix segment into the cache key to scope/bust caches independently of the lockfile.
  • Node pin in the cache key (setup-node #1171) — the key now hashes the project's Node-pin source files (.node-version/.nvmrc), so a Node-version bump invalidates the stale toolchain cache instead of restoring it.

Already handled by setup-nub today (no change needed, noted for context):

  • cache: yarn/pnpm fails (setup-node #1027, #1357) — setup-nub normalizes any PM name to a single boolean store, so these never fail.
  • .node-version by default (setup-node #683) — setup-nub already eager-provisions from the full pin chain with no input.
  • Cache restore-keys fallback (setup-node #328, #1120) — setup-nub already ships a restore-keys ladder.
  • node-version-file absolute paths (setup-node #852) — setup-nub's provision reads the file by path directly; absolute paths work.

Recommended but NOT implemented (maintainer decisions / larger features)

Prioritized by upstream demand. These are product/default calls or non-trivial features — flagged for your decision, not landed here:

  1. Pin/manage the PM version (setup-node #531 Corepack, 245 reactions; #213, 131; #529, 53). The single largest demand cluster. nub owns package management itself, so "install pnpm/yarn at version X" is a product-shape question: does setup-nub expose any PM-version surface, or is it deliberately N/A because nub is the PM? Worth an explicit documented stance either way.
  2. Save cache even when the job fails (setup-node #1168). setup-node only saves on success; a save-always-style behavior (or actions/cache/restore + actions/cache/save with if: always()) would save partial-install progress. A behavior-default decision.
  3. Multiple private registries / multi-scope auth (setup-node #67, 41; #934). setup-nub (like setup-node) writes a single registry/scope. Supporting multiple registries is a real feature; recommend scoping separately.
  4. scope defaults to package.json scope (setup-node #128). Small, but it's an auth-default behavior change — recommend maintainer sign-off.
  5. mise / .tool-versions support (setup-node #1304). Depends on nub's own pin-resolution chain; align with nub core before adding here.
  6. Silent fallback on download/extract failure (setup-node #1555, #1556). setup-nub already warns (not fails) on eager-provision failure and falls back to lazy runtime provisioning. Consider whether a hard-fail mode is wanted; it's a default decision.

Verification

  • actionlint -shellcheck=shellcheck .github/workflows/smoke.yml — no new findings (4 pre-existing infos/warnings unchanged: SC2193 from [[ == ]] expression substitution, SC2016 from literal ${NODE_AUTH_TOKEN} in auth jobs).
  • action.yml and smoke.yml parse as valid YAML.
  • The cache-state precedence logic was tested locally across 10 scenarios (lockfile / packageManager / devEngines / plain package.json / explicit cache values / package-manager-cache false) — all correct.

Mirror actions/setup-node's default-on caching: add a package-manager-cache
input (default true) and change cache to auto-enable when the project looks
installable (a lockfile, or a package.json packageManager/devEngines field).
An explicit cache value still wins; package-manager-cache: false (or
cache: false) disables. Previously caching required opt-in cache: true, which
silently gave drop-in migrators no caching.

Also add three low-risk DX inputs drawn from top actions/setup-node issues:

- working-directory: resolve the Node pin and lockfile from a subdirectory,
  for monorepos (setup-node#706).
- cache-key-prefix: inject a prefix segment into the cache key to scope or
  bust caches independently of the lockfile (setup-node#1320).
- fold the project's Node pin into the cache key so a Node-version bump
  invalidates the stale toolchain cache (setup-node#1171).

Extend smoke.yml with jobs asserting caching auto-enables by default on a
lockfile project and that package-manager-cache: false disables it. Update
README and action.yml input docs.
Copilot AI review requested due to automatic review settings June 22, 2026 18:26

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

The cache-default-on smoke job asserted on cache-hit to detect whether
caching was active, but actions/cache sets cache-hit to an empty string on a
full miss (always the case on a first CI run) even when caching is enabled
and the cache will be saved at job end. The auto-enable implementation was
correct — the cache step ran and reported a miss — but the assertion was
wrong.

Add a caching-enabled action output sourced from the resolved cache decision
(steps.cacheflag.outputs.enabled), independent of whether a cache was hit,
and assert on it in both the auto-enable and disable smoke jobs. Document the
new output and clarify cache-hit's miss-is-empty semantics in the README.
@colinhacks colinhacks merged commit 45fe48f into main Jun 22, 2026
30 checks passed
@colinhacks colinhacks deleted the cache-default-dx-fixes branch June 22, 2026 18:38
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.

2 participants