Skip to content

Commit 58b6d7b

Browse files
authored
fix: add OS version to cache key to prevent binary incompatibility (#716)
## Summary - Adds OS name and version (e.g., `ubuntu-22.04`, `macos-14`, `windows-2022`) to cache keys to prevent binary incompatibility when GitHub updates runner images - Fixes issue where cached uv binaries compiled against older glibc/library versions fail on newer runner OS versions ## Changes - Added `getOSNameVersion()` function to `src/utils/platforms.ts` with OS-specific detection for Linux (via `/etc/os-release`), macOS (Darwin kernel version mapping), and Windows - Updated cache key format to include OS version, bumped `CACHE_VERSION` to `"2"` - Added `cache-key` output to expose the generated cache key for debugging - Added `test-cache-key-os-version` job testing across multiple OS versions - Updated `docs/caching.md` with cache key documentation Closes #703
1 parent e8b52af commit 58b6d7b

File tree

7 files changed

+306
-7
lines changed

7 files changed

+306
-7
lines changed

.github/workflows/test.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,60 @@ jobs:
385385
with:
386386
persist-credentials: false
387387
- name: Install latest version
388+
id: setup-uv
388389
uses: ./
390+
with:
391+
enable-cache: true
392+
- name: Verify cache key contains alpine
393+
run: |
394+
echo "Cache key: $CACHE_KEY"
395+
if echo "$CACHE_KEY" | grep -qv "alpine"; then
396+
echo "Cache key does not contain 'alpine'"
397+
exit 1
398+
fi
399+
shell: sh
400+
env:
401+
CACHE_KEY: ${{ steps.setup-uv.outputs.cache-key }}
389402
- run: uv sync
390403
working-directory: __tests__/fixtures/uv-project
391404

405+
test-cache-key-os-version:
406+
runs-on: ${{ matrix.os }}
407+
strategy:
408+
matrix:
409+
include:
410+
- os: ubuntu-22.04
411+
expected-os: "ubuntu-22.04"
412+
- os: ubuntu-24.04
413+
expected-os: "ubuntu-24.04"
414+
- os: macos-14
415+
expected-os: "macos-14"
416+
- os: macos-15
417+
expected-os: "macos-15"
418+
- os: windows-2022
419+
expected-os: "windows-2022"
420+
- os: windows-2025
421+
expected-os: "windows-2025"
422+
steps:
423+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
424+
with:
425+
persist-credentials: false
426+
- name: Setup uv
427+
id: setup-uv
428+
uses: ./
429+
with:
430+
enable-cache: true
431+
- name: Verify cache key contains OS version
432+
run: |
433+
echo "Cache key: $CACHE_KEY"
434+
if [[ "$CACHE_KEY" != *"${{ matrix.expected-os }}"* ]]; then
435+
echo "Cache key does not contain expected OS version: ${{ matrix.expected-os }}"
436+
exit 1
437+
fi
438+
shell: bash
439+
env:
440+
CACHE_KEY: ${{ steps.setup-uv.outputs.cache-key }}
441+
392442
test-setup-cache:
393443
runs-on: ${{ matrix.os }}
394444
strategy:
@@ -1002,6 +1052,7 @@ jobs:
10021052
- test-python-version
10031053
- test-activate-environment
10041054
- test-musl
1055+
- test-cache-key-os-version
10051056
- test-cache-local
10061057
- test-cache-local-cache-disabled
10071058
- test-cache-local-cache-disabled-but-explicit-path

action.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ outputs:
8989
description: "The path to the installed uvx binary."
9090
cache-hit:
9191
description: "A boolean value to indicate a cache entry was found"
92+
cache-key:
93+
description: "The cache key used for storing/restoring the cache"
9294
venv:
9395
description: "Path to the activated venv if activate-environment is true"
9496
runs:

dist/save-cache/index.js

Lines changed: 75 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/setup/index.js

Lines changed: 75 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/caching.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@
22

33
This document covers all caching-related configuration options for setup-uv.
44

5+
## Cache key
6+
7+
The cache key is automatically generated based on:
8+
9+
- **Architecture**: CPU architecture (e.g., `x86_64`, `aarch64`)
10+
- **Platform**: OS platform type (e.g., `unknown-linux-gnu`, `unknown-linux-musl`, `apple-darwin`,
11+
`pc-windows-msvc`)
12+
- **OS version**: OS name and version (e.g., `ubuntu-22.04`, `macos-14`, `windows-2022`)
13+
- **Python version**: The Python version in use
14+
- **Cache options**: Whether pruning and Python caching are enabled
15+
- **Dependency hash**: Hash of files matching `cache-dependency-glob`
16+
- **Suffix**: Optional `cache-suffix` if provided
17+
18+
Including the OS version ensures that caches are not shared between different OS versions,
19+
preventing binary incompatibility issues when runner images change.
20+
21+
The computed cache key is available as the `cache-key` output:
22+
23+
```yaml
24+
- name: Setup uv
25+
id: setup-uv
26+
uses: astral-sh/setup-uv@v7
27+
with:
28+
enable-cache: true
29+
- name: Print cache key
30+
run: echo "Cache key: ${{ steps.setup-uv.outputs.cache-key }}"
31+
```
32+
533
## Enable caching
634
735
> [!NOTE]

src/cache/restore-cache.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@ import {
1313
restoreCache as shouldRestoreCache,
1414
workingDirectory,
1515
} from "../utils/inputs";
16-
import { getArch, getPlatform } from "../utils/platforms";
16+
import { getArch, getOSNameVersion, getPlatform } from "../utils/platforms";
1717

1818
export const STATE_CACHE_KEY = "cache-key";
1919
export const STATE_CACHE_MATCHED_KEY = "cache-matched-key";
20-
const CACHE_VERSION = "1";
20+
const CACHE_VERSION = "2";
2121

2222
export async function restoreCache(): Promise<void> {
2323
const cacheKey = await computeKeys();
2424
core.saveState(STATE_CACHE_KEY, cacheKey);
25+
core.setOutput("cache-key", cacheKey);
2526

2627
if (!shouldRestoreCache) {
2728
core.info("restore-cache is false. Skipping restore cache step.");
@@ -72,9 +73,10 @@ async function computeKeys(): Promise<string> {
7273
const suffix = cacheSuffix ? `-${cacheSuffix}` : "";
7374
const pythonVersion = await getPythonVersion();
7475
const platform = await getPlatform();
76+
const osNameVersion = getOSNameVersion();
7577
const pruned = pruneCache ? "-pruned" : "";
7678
const python = cachePython ? "-py" : "";
77-
return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
79+
return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${osNameVersion}-${pythonVersion}${pruned}${python}${cacheDependencyPathHash}${suffix}`;
7880
}
7981

8082
async function getPythonVersion(): Promise<string> {

0 commit comments

Comments
 (0)