mirror of
https://github.com/jdx/mise-action.git
synced 2026-05-18 23:41:53 +00:00
Problem
-------
mise-action hashes ALL mise config files in the repo to compute a single
default cache key. In a monorepo with multiple projects (e.g., apps/frontend,
apps/backend), this causes cache pollution:
1. Job A runs for apps/frontend, installs only frontend tools
2. Cache is saved with a key based on ALL configs
3. Job B runs for apps/backend, gets cache HIT (same key)
4. Job B finds frontend tools but not backend tools
5. Job B has to install all tools because they are missing from cache
Additionally, any change to an unrelated project config would bust the
cache for all projects.
Solution
--------
When working_directory is set, compute the default cache key using only the
config files that affect that directory (detected via `mise config ls --json`)
instead of globbing all configs in the repo.
This required separating binary and tools caching:
- Binary cache: restored first so mise is available for `mise config ls`
- Tools cache: default key computed after mise is installed
Key Implementation Details
--------------------------
1. Cache separation:
- restoreMiseBinaryCache/saveMiseBinaryCache for the mise binary
- restoreToolsCache/saveToolsCache for the full mise directory
- Binary cache key: `{prefix}-binary-{platform}-{version}-{dirHash}`
- Tools default cache key: based on config file contents for working_directory
2. Binary backup during tools cache restore:
The tools cache includes bin/, which could overwrite the binary that
setupMise() just installed. We use withBinaryBackup() to backup the
binary before restoring the tools cache and restore it afterward.
An alternative approach would be to only cache installs/ and shims/
instead of the full miseDir(), but that would change the caching
behavior for existing users. Using withBinaryBackup() retains the
original caching behavior while preventing the binary from being
overwritten.
3. Binary cache key includes mise_dir hash:
Prevents cache collision when users change mise_dir between runs.
Without this, a cache hit could restore the binary to the wrong location.
4. Explicit mise binary path:
Uses full path to mise binary instead of relying on PATH lookup,
avoiding potential race conditions with core.addPath().
5. Lock file handling:
- .toml files: look for corresponding .lock file
- .tool-versions: look for mise.lock in the same directory
6. Graceful degradation:
If `mise config ls` fails when working_directory is set, caching is
disabled with a warning rather than:
- Failing the action entirely, or
- Falling back to glob patterns (which would reintroduce the bug)
Backward Compatibility
----------------------
- working_directory not set: No change, uses existing glob of all configs
- working_directory set: Default cache key based on `mise config ls` output
Note on cache_key input: The `cache_key` input now only controls the tools
cache key. The binary cache key is always computed automatically based on
platform, version, and mise_dir. This is generally better since the binary
cache is version-stable and does not need custom key logic.
Test Coverage
-------------
Added test-monorepo-cache.yml with 8 test scenarios:
- install-backend/restore-frontend: Verify cache isolation
- install-frontend/unrelated-change-no-bust: Verify unrelated changes do not bust cache
- parent-config-change: Verify parent config changes bust child cache
- lock-file-change: Verify lock file changes bust cache
- install-default-mise-dir/restore-custom-mise-dir: Verify mise_dir in cache key
|
||
|---|---|---|
| .. | ||
| index.js | ||
| index.js.map | ||
| licenses.txt | ||
| sourcemap-register.js | ||