mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-06-19 11:02:23 +00:00
feat: support uv.lock as a version-file source (#918)
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
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from "@jest/globals";
|
||||
import { getUvVersionFromUvLockContent } from "../../src/version/uv-lock-file";
|
||||
|
||||
const UV_LOCK = `version = 1
|
||||
requires-python = ">=3.12"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
|
||||
[[package]]
|
||||
name = "uv"
|
||||
version = "0.8.17"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
`;
|
||||
|
||||
describe("getUvVersionFromUvLockContent", () => {
|
||||
it("returns the exact uv version locked in uv.lock", () => {
|
||||
expect(getUvVersionFromUvLockContent(UV_LOCK)).toBe("0.8.17");
|
||||
});
|
||||
|
||||
it("returns undefined when uv is not a locked package", () => {
|
||||
const content = `version = 1
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.6.0"
|
||||
`;
|
||||
expect(getUvVersionFromUvLockContent(content)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns undefined when there are no packages", () => {
|
||||
expect(getUvVersionFromUvLockContent("version = 1\n")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -63,6 +63,24 @@ describe("resolveVersionRequest", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the exact uv version locked in uv.lock when it is passed via version-file", () => {
|
||||
const workingDirectory = createTempProject({
|
||||
"uv.lock": `version = 1\n\n[[package]]\nname = "uv"\nversion = "0.8.17"\nsource = { registry = "https://pypi.org/simple" }\n`,
|
||||
});
|
||||
|
||||
const request = resolveVersionRequest({
|
||||
versionFile: path.join(workingDirectory, "uv.lock"),
|
||||
workingDirectory,
|
||||
});
|
||||
|
||||
expect(request).toEqual({
|
||||
format: "uv.lock",
|
||||
source: "version-file",
|
||||
sourcePath: path.join(workingDirectory, "uv.lock"),
|
||||
specifier: "0.8.17",
|
||||
});
|
||||
});
|
||||
|
||||
it("uses requirements.txt when it is passed via version-file", () => {
|
||||
const workingDirectory = createTempProject({
|
||||
"requirements.txt": "uv==0.6.17\nuvicorn==0.35.0\n",
|
||||
|
||||
Reference in New Issue
Block a user