Skip to content

Commit cdfb2ee

Browse files
authored
Refactor version resolving (#852)
1 parent cb84d12 commit cdfb2ee

16 files changed

Lines changed: 7629 additions & 6831 deletions

__tests__/download/download-version.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,35 @@ describe("download-version", () => {
9595
expect(mockGetAllVersions).toHaveBeenCalledWith(undefined);
9696
});
9797

98+
it("treats == exact pins as explicit versions", async () => {
99+
const version = await resolveVersion("==0.9.26", undefined);
100+
101+
expect(version).toBe("0.9.26");
102+
expect(mockGetAllVersions).not.toHaveBeenCalled();
103+
expect(mockGetLatestVersion).not.toHaveBeenCalled();
104+
});
105+
106+
it("uses latest for minimum-only ranges when using the highest strategy", async () => {
107+
mockGetLatestVersion.mockResolvedValue("0.9.26");
108+
109+
const version = await resolveVersion(">=0.9.0", undefined, "highest");
110+
111+
expect(version).toBe("0.9.26");
112+
expect(mockGetLatestVersion).toHaveBeenCalledTimes(1);
113+
expect(mockGetLatestVersion).toHaveBeenCalledWith(undefined);
114+
expect(mockGetAllVersions).not.toHaveBeenCalled();
115+
});
116+
117+
it("uses the lowest compatible version when requested", async () => {
118+
mockGetAllVersions.mockResolvedValue(["0.9.26", "0.9.25"]);
119+
120+
const version = await resolveVersion("^0.9.0", undefined, "lowest");
121+
122+
expect(version).toBe("0.9.25");
123+
expect(mockGetAllVersions).toHaveBeenCalledTimes(1);
124+
expect(mockGetAllVersions).toHaveBeenCalledWith(undefined);
125+
});
126+
98127
it("uses manifest-file when provided", async () => {
99128
mockGetAllVersions.mockResolvedValue(["0.9.26", "0.9.25"]);
100129

__tests__/version/requirements-file.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from "@jest/globals";
2-
import { getUvVersionFromFile } from "../../src/version/resolve";
2+
import { getUvVersionFromFile } from "../../src/version/file-parser";
33

44
test("ignores dependencies starting with uv", async () => {
55
const parsedVersion = getUvVersionFromFile(

__tests__/version/requirements-hashes-file.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect, test } from "@jest/globals";
2-
import { getUvVersionFromFile } from "../../src/version/resolve";
2+
import { getUvVersionFromFile } from "../../src/version/file-parser";
33

44
test("ignores dependencies starting with uv", async () => {
55
const parsedVersion = getUvVersionFromFile(
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import fs from "node:fs";
2+
import os from "node:os";
3+
import path from "node:path";
4+
import { afterEach, describe, expect, it } from "@jest/globals";
5+
import { resolveVersionRequest } from "../../src/version/version-request-resolver";
6+
7+
const tempDirs: string[] = [];
8+
9+
function createTempProject(files: Record<string, string> = {}): string {
10+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "setup-uv-version-test-"));
11+
tempDirs.push(dir);
12+
13+
for (const [relativePath, content] of Object.entries(files)) {
14+
const filePath = path.join(dir, relativePath);
15+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
16+
fs.writeFileSync(filePath, content);
17+
}
18+
19+
return dir;
20+
}
21+
22+
afterEach(() => {
23+
for (const dir of tempDirs.splice(0)) {
24+
fs.rmSync(dir, { force: true, recursive: true });
25+
}
26+
});
27+
28+
describe("resolveVersionRequest", () => {
29+
it("prefers explicit input over version-file and workspace config", () => {
30+
const workingDirectory = createTempProject({
31+
".tool-versions": "uv 0.4.0\n",
32+
"pyproject.toml": `[tool.uv]\nrequired-version = "==0.5.14"\n`,
33+
"uv.toml": `required-version = "==0.5.15"\n`,
34+
});
35+
36+
const request = resolveVersionRequest({
37+
version: "==0.6.0",
38+
versionFile: path.join(workingDirectory, ".tool-versions"),
39+
workingDirectory,
40+
});
41+
42+
expect(request).toEqual({
43+
source: "input",
44+
specifier: "0.6.0",
45+
});
46+
});
47+
48+
it("uses .tool-versions when it is passed via version-file", () => {
49+
const workingDirectory = createTempProject({
50+
".tool-versions": "uv 0.5.15\n",
51+
});
52+
53+
const request = resolveVersionRequest({
54+
versionFile: path.join(workingDirectory, ".tool-versions"),
55+
workingDirectory,
56+
});
57+
58+
expect(request).toEqual({
59+
format: ".tool-versions",
60+
source: "version-file",
61+
sourcePath: path.join(workingDirectory, ".tool-versions"),
62+
specifier: "0.5.15",
63+
});
64+
});
65+
66+
it("uses requirements.txt when it is passed via version-file", () => {
67+
const workingDirectory = createTempProject({
68+
"requirements.txt": "uv==0.6.17\nuvicorn==0.35.0\n",
69+
});
70+
71+
const request = resolveVersionRequest({
72+
versionFile: path.join(workingDirectory, "requirements.txt"),
73+
workingDirectory,
74+
});
75+
76+
expect(request).toEqual({
77+
format: "requirements",
78+
source: "version-file",
79+
sourcePath: path.join(workingDirectory, "requirements.txt"),
80+
specifier: "0.6.17",
81+
});
82+
});
83+
84+
it("prefers uv.toml over pyproject.toml during workspace discovery", () => {
85+
const workingDirectory = createTempProject({
86+
"pyproject.toml": `[tool.uv]\nrequired-version = "==0.5.14"\n`,
87+
"uv.toml": `required-version = "==0.5.15"\n`,
88+
});
89+
90+
const request = resolveVersionRequest({ workingDirectory });
91+
92+
expect(request).toEqual({
93+
format: "uv.toml",
94+
source: "uv.toml",
95+
sourcePath: path.join(workingDirectory, "uv.toml"),
96+
specifier: "0.5.15",
97+
});
98+
});
99+
100+
it("falls back to latest when no version source is found", () => {
101+
const workingDirectory = createTempProject({});
102+
103+
const request = resolveVersionRequest({ workingDirectory });
104+
105+
expect(request).toEqual({
106+
source: "default",
107+
specifier: "latest",
108+
});
109+
});
110+
111+
it("throws when version-file does not resolve a version", () => {
112+
const workingDirectory = createTempProject({
113+
"requirements.txt": "uvicorn==0.35.0\n",
114+
});
115+
116+
expect(() =>
117+
resolveVersionRequest({
118+
versionFile: path.join(workingDirectory, "requirements.txt"),
119+
workingDirectory,
120+
}),
121+
).toThrow(
122+
`Could not determine uv version from file: ${path.join(workingDirectory, "requirements.txt")}`,
123+
);
124+
});
125+
});

dist/save-cache/index.cjs

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

0 commit comments

Comments
 (0)