## Summary
Roll up the remaining net changes from the open Dependabot updates:
- release-drafter/release-drafter 7.7.0 (#990)
- github/codeql-action 4.37.4 (#987, #988, #989)
- zizmorcore/zizmor-action 0.6.1 (#986)
- @actions/cache 6.2.0 (#975)
- @biomejs/biome 2.5.4 (#974)
- undici 8.7.0 (#973)
The Jest 30.4.2 (#905) and @renovatebot/pep440 5.0.0 (#907) updates are
already present on main and require no additional changes.
This also updates the Biome schema, applies the formatter changes from
Biome 2.5.4, and regenerates the published bundles.
## Testing
- `npm run all`
- `actionlint`
- `git diff --check`
Refs: pi-session 019ff01b-f917-73c1-950e-2966956f263c
## Summary
- add `latest-known` as an explicit version selector
- resolve it locally to the newest version in the bundled checksum table
- preserve existing default and `latest` behavior
- document custom-manifest checksum semantics and update published
bundles
## Testing
- `npm ci --ignore-scripts`
- `npm run all` (99 tests passed)
Closes#919
Refs: pi-session 019fed0e-6019-7504-911b-bd9955cbbd49
## Summary
- disable `enable-cache: auto` for `pull_request_target`,
`workflow_run`, and `release` events
- disable automatic caching for tag pushes while leaving branch pushes
unchanged
- preserve explicit `enable-cache: true` as an override
- run a `workflow_run` integration fixture with `act` in pull request CI
and verify caching is disabled
- document the behavior and update the published bundles
## Testing
- `npm run all`
- `actionlint .github/workflows/test.yml
__tests__/workflows/workflow-run.yml`
- `uvx zizmor __tests__/workflows/workflow-run.yml`
Closes#984
Refs: pi-session 019fec42-9b26-714e-a359-830ac4401ecd
## Summary
Roll up the remaining dependency changes from Dependabot PRs:
- #966: update `actions/setup-node` from 6.4.0 to 7.0.0
- #965: update `js-yaml` from 4.1.1 to 5.2.1
- #964: update `@types/node` from 26.0.1 to 26.1.1
- #963: update `esbuild` from 0.28.0 to 0.28.1
PRs #907 and #905 require no net changes because `@renovatebot/pep440`
5.0.0 and Jest 30.4.2 are already on `main`.
## Validation
- `npm run all`
Refs: pi-session 019f854e-4714-73ad-8de2-e79900f41b4d
## Summary
This changes the default for `prune-cache` from `true` to `false`,
motivated by [#745](https://github.com/astral-sh/setup-uv/issues/745).
Users that want the existing behavior can continue to set `prune-cache:
true` explicitly.
Some history: I originally added [`uv cache prune
--ci`](https://github.com/astral-sh/uv/pull/5391) after looking at a
workload where the uv cache was ~2.2 GB, almost entirely due to the
enormous pre-built `torch` and `nvidia_cudnn_cu12` wheels ([original
analysis](https://github.com/actions/setup-python/issues/822#issuecomment-2248728264)).
Persisting and restoring thousands of extracted files through the GitHub
Actions cache could be slower than downloading the wheels again. In
contrast, wheels built from source can be very expensive to recreate.
The intent was to remove pre-built wheels while retaining locally-built
wheels.
`setup-uv` subsequently made pruning configurable, but defaulted
`prune-cache` to `true`; it also later enabled caching by default on
GitHub-hosted runners. As a result, the default configuration repeatedly
downloads pre-built wheels from PyPI even on a cache hit. That tradeoff
has become more important as uv adoption has grown: [the PyPI analysis
in
#745](https://github.com/astral-sh/setup-uv/issues/745#issuecomment-3867334064)
estimates that uv accounts for roughly half of reported CI downloads
from PyPI, and roughly 65-75% for `boto3`.
I ran the comparison across a few different workloads:
| Workload | PR | Packages | Cache: keep / prune / prune-ci | Warm
restore+sync: keep / prune / prune-ci | Downloads: prune / prune-ci |
|---|---:|---:|---:|---:|---:|
| Tiny | [#1](https://github.com/astral-sh/setup-uv-benchmarks/pull/1) |
19 | 6 / 6 / 2 MB | 0.3-0.4 / 0.3 / 0.4-0.5 s | 0 / 2 |
| Web | [#2](https://github.com/astral-sh/setup-uv-benchmarks/pull/2) |
65 | 43 / 43 / 7 MB | 0.6-1.0 / 0.5-0.6 / 1.5-1.7 s | 0 / 6 |
| Scientific |
[#3](https://github.com/astral-sh/setup-uv-benchmarks/pull/3) | 118 |
586 / 586 / 8 MB | 8.2-16.0 / 7.0-8.2 / 8.9-12.1 s | 0 / 19 |
| PySpark |
[#4](https://github.com/astral-sh/setup-uv-benchmarks/pull/4) | 19 |
1820 / 1820 / 436 MB | 9.9-21.1 / 10.5-11.0 / 5.0-7.0 s | 0 / 4 |
| CPU PyTorch |
[#5](https://github.com/astral-sh/setup-uv-benchmarks/pull/5) | 14 | 182
/ 182 / 1 MB | 3.0-6.0 / 3.6-4.0 / 5.7-6.4 s | 0 / 6 |
| CPU-PyTorch ML |
[#6](https://github.com/astral-sh/setup-uv-benchmarks/pull/6) | 137 |
346 / 346 / 10 MB | 7.4-18.0 / 8.8-8.9 / 9.7-11.9 s | 0 / 20 |
| CUDA PyTorch |
[#7](https://github.com/astral-sh/setup-uv-benchmarks/pull/7) | 201 |
2316 / 2315 / 16 MB | 30.2-67.9 / 31.0-63.6 / 33.3-36.7 s | 0 / 40 |
The CUDA workload intentionally reproduces the original `torch==2.1.1`
example. Keeping wheels again produces a ~2.3 GB Actions cache. Across
nine warm runs, restoring that cache ranged from slightly faster than
re-downloading to roughly twice as slow; pruning consistently
re-downloaded 40 distributions in ~33-37 seconds ([original
runs](https://github.com/astral-sh/setup-uv-benchmarks/actions/runs/29750292738),
[additional
runs](https://github.com/astral-sh/setup-uv-benchmarks/actions/runs/29761705492)).
I also tried running `uv cache prune --force` without `--ci` across
every workload, to see if it provided a useful middle ground. It did not
meaningfully reduce any of the caches: plain prune took 11-21 ms and
left the extracted cache and file count unchanged, including PySpark. On
these fresh caches, there are no dangling entries to remove; without
`--ci`, the pre-built wheels and unpacked source/build artifacts are
retained. The per-workload runs are linked in the table above.
So the original motivation still holds for very large CUDA or
source-heavy workloads, but it is not representative of the common case.
For smaller workloads, keeping pre-built wheels is generally faster and
avoids repeated PyPI traffic. This changes the default accordingly,
while retaining `prune-cache: true` as an opt-in for workloads where the
smaller cache is worthwhile.
Closes https://github.com/astral-sh/setup-uv/issues/745.
## Summary
- update all CodeQL actions from 4.36.2 to 4.37.0
- update `smol-toml` from 1.6.1 to 1.7.0
- update `@types/node` from 25.5.0 to 26.0.1
- update `@vercel/ncc` from 0.44.0 to 0.44.1
- regenerate bundled action artifacts
Supersedes #950, #951, #952, #957, #958, and #959. The updates from #905
and #907 are already present on `main`.
Refs: pi-session 019f796d-a374-7a76-a8e4-1699b89ec8e6
## Summary
`getLinuxOSNameVersion()` throws `Failed to determine Linux
distribution. Could not read /etc/os-release or /usr/lib/os-release` on
distributions whose os-release is readable but contains **no version
field at all** — no `VERSION_ID`, no `VERSION_CODENAME`, no `BUILD_ID`.
The error message is misleading in that case, and the action fails even
though the distribution is perfectly identifiable.
Void Linux is such a distribution. Its os-release is:
```sh
$ cat /etc/os-release
NAME="Void"
ID="void"
PRETTY_NAME="Void Linux"
HOME_URL="https://voidlinux.org/"
DOCUMENTATION_URL="https://docs.voidlinux.org/"
LOGO="void-logo"
ANSI_COLOR="0;38;2;71;128;97"
DISTRIB_ID="void"
```
Unlike Arch (fixed by #912 via `BUILD_ID`) and debian:unstable (fixed
via `VERSION_CODENAME`, #773), Void ships only `ID`, so both existing
fallbacks miss it. This breaks any workflow using `container:
ghcr.io/void-linux/void-glibc-full` with caching enabled — e.g.
SageMath's CI started failing after bumping to v8:
https://github.com/sagemath/sage/actions/runs/29456228986/job/87489892141
(worked around downstream in https://github.com/sagemath/sage/pull/42547
by injecting a fake `BUILD_ID` into the container's os-release).
This PR adds a last-resort fallback: if `ID` is present but no version
field is, return the plain `ID` (`void`), following the same reasoning
as #912 — a stable cache key for a rolling release is better than
crashing. Distributions with a version field are unaffected, and files
without even an `ID` still raise the existing error.
## Summary
- roll up remaining open Dependabot updates for zizmor-action,
@actions/cache, @biomejs/biome, and @vercel/ncc
- update Biome schema and migrate recommended rules to the new preset
field
- regenerate dist bundles
## Validation
- npm run check
- npm run all
Refs: pi-session 019f4055-b39c-778f-9d9f-092115939c33
## Summary
- strip PEP 508 environment markers before extracting uv versions from
dependency entries
- cover dependency-group pins with and without whitespace before the
marker
- cover requirements-style pins with markers
Fixes#920
## Validation
- npm ci --ignore-scripts
- npm run all
Refs: pi-session 019f316a-4108-7975-892f-ee5bf8abc7c3
## Summary
- URL-encode the Python version component before adding it to the cache
key
- URL-encode the user-provided cache suffix for the same reason
- Add cache key tests for Python ranges, comma-containing suffixes, and
unchanged simple inputs
Fixes#914
Refs: pi-session 019f3164-85e7-7817-bffd-501d89b3a1fd
## Tests
- npm run all
## Summary
- Roll up open Dependabot npm and GitHub Actions updates
- Update Biome schema to 2.4.16
- Regenerate bundled dist artifacts
## Validation
- npm run all
Refs: pi-session 019f3160-c4af-7606-b4be-648e0abff131
- replace the docs update tag-push trigger with manual and reusable
workflow entrypoints
- call the docs update reusable workflow after publishing a release
- keep manual docs updates available by selecting the latest semver tag
Refs: pi-session 019f2352-565c-7f60-b96b-f2546fb1690f
## Summary
- update README and docs `uses: astral-sh/setup-uv@...` examples to the
v8.2.0 commit SHA
- replace stale `v8.1.0` comments with `v8.2.0`
Fixes#931
## Validation
- npm ci --ignore-scripts
- npm run all
This adds a threat model for `setup-uv` so security scanners can use it
as a baseline in terms of what's in-, and out of scope.
The TM covers credential recipients, executable and cache boundaries,
and release authority. It treats checkout-selected interpreters, paths,
virtual environments, symlinks, and helpers as delegated project
authority unless they override an explicit workflow choice or cross an
independent cache, runner, remote, or publication boundary.
Adds `uv.lock` as a supported `version-file` source. When `uv` is locked
as a
dependency in `uv.lock`, the action now installs the exact pinned
version,
closing the gap reported in #682.
This is useful for deterministic CI: the same uv version is used until
the
lockfile is updated, which avoids "CI worked yesterday, fails today"
drift and
reduces supply-chain exposure from auto-installing the latest release.
The implementation mirrors the existing `version-file` parsers — a new
`uv.lock`
entry in the parser registry reads the `[[package]]` whose `name = "uv"`
and
returns its locked `version`. Scoped to explicit `version-file:
uv.lock`;
workspace auto-detection is left as a possible follow-up to avoid
precedence
ambiguity with `uv.toml` / `pyproject.toml`.
Validation (local, Node 23; dist build is esbuild-deterministic):
- `npm run all` → build clean, biome clean, package clean, jest 77/77
- New tests: 3 unit (`uv-lock-file.test.ts`) + 1 integration — exact pin
resolves
through the full pipeline (`uv.lock` → `0.8.17`)
- dist rebuilt + committed (single bundle, no spurious churn)
related: #682
On Arch Linux based runners, the setup fails with because
`/etc/os-release` does not contain `VERSION_ID` or `VERSION_CODENAME`.
It does contain a `BUILD_ID` which is set to `rolling`:
```sh
$ cat /etc/os-release
NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://archlinux.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux.org/"
BUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues"
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
LOGO=archlinux-logo
```
This PR makes `getLinuxOSNameVersion` return `arch-rolling`.
There is no update from arch that would change the returned value, so
the same cache will always be used. Is this an issue? I'm not sure. At
least it's better than crashing because `os-release` does not contain
the expected values :).
Rolls up the current open Dependabot npm updates:
- #848 esbuild from 0.27.5 to 0.28.0
- #847 undici from 8.0.0 to 8.3.0
- #846 ts-jest from 29.4.9 to 29.4.11
- #841 @biomejs/biome from 2.4.10 to 2.4.15, including the matching
biome.json schema URL update
Validation:
- npm run all
Updates the dependabot-pr-rollup skill to document that @biomejs/biome
dependency updates must also update the matching schema URL version in
biome.json.
Rolls up the current open Dependabot npm updates:
- #848 esbuild from 0.27.4 to 0.27.5
- #847 undici from 7.24.2 to 8.0.0
- #846 ts-jest from 29.4.6 to 29.4.9
- #841 @biomejs/biome from 2.4.7 to 2.4.10, including the matching
biome.json schema URL update
- #834 smol-toml from 1.6.0 to 1.6.1
Validation:
- npm run all
## Summary
Adds a new `quiet` input (default: `false`) that suppresses `info`-level
log output when set to `true`. Only warnings and errors are shown.
Contributes to: #868