mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-10-03 00:45:44 +00:00
Resolve Python architecture during input loading
This commit is contained in:
25
__tests__/cache/restore-cache.test.ts
vendored
25
__tests__/cache/restore-cache.test.ts
vendored
@@ -1,11 +1,4 @@
|
|||||||
import {
|
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
|
||||||
afterEach,
|
|
||||||
beforeEach,
|
|
||||||
describe,
|
|
||||||
expect,
|
|
||||||
it,
|
|
||||||
jest,
|
|
||||||
} from "@jest/globals";
|
|
||||||
import { createSetupInputs } from "../helpers/setup-inputs";
|
import { createSetupInputs } from "../helpers/setup-inputs";
|
||||||
|
|
||||||
const mockRestoreCache = jest.fn();
|
const mockRestoreCache = jest.fn();
|
||||||
@@ -14,7 +7,6 @@ const mockSetOutput = jest.fn();
|
|||||||
const mockGetArch = jest.fn(() => "x86_64");
|
const mockGetArch = jest.fn(() => "x86_64");
|
||||||
const mockGetOSNameVersion = jest.fn(() => "ubuntu-24.04");
|
const mockGetOSNameVersion = jest.fn(() => "ubuntu-24.04");
|
||||||
const mockGetPlatform = jest.fn(async () => "unknown-linux-gnu");
|
const mockGetPlatform = jest.fn(async () => "unknown-linux-gnu");
|
||||||
const ORIGINAL_UV_PYTHON_ARCH = process.env.UV_PYTHON_ARCH;
|
|
||||||
|
|
||||||
jest.unstable_mockModule("@actions/cache", () => ({
|
jest.unstable_mockModule("@actions/cache", () => ({
|
||||||
restoreCache: mockRestoreCache,
|
restoreCache: mockRestoreCache,
|
||||||
@@ -49,21 +41,12 @@ function cacheKeyOutput(): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
delete process.env.UV_PYTHON_ARCH;
|
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
mockGetArch.mockReturnValue("x86_64");
|
mockGetArch.mockReturnValue("x86_64");
|
||||||
mockGetOSNameVersion.mockReturnValue("ubuntu-24.04");
|
mockGetOSNameVersion.mockReturnValue("ubuntu-24.04");
|
||||||
mockGetPlatform.mockResolvedValue("unknown-linux-gnu");
|
mockGetPlatform.mockResolvedValue("unknown-linux-gnu");
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
if (ORIGINAL_UV_PYTHON_ARCH === undefined) {
|
|
||||||
delete process.env.UV_PYTHON_ARCH;
|
|
||||||
} else {
|
|
||||||
process.env.UV_PYTHON_ARCH = ORIGINAL_UV_PYTHON_ARCH;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("restoreCache", () => {
|
describe("restoreCache", () => {
|
||||||
it("encodes Python version ranges before adding them to the cache key", async () => {
|
it("encodes Python version ranges before adding them to the cache key", async () => {
|
||||||
await restoreCache(createSetupInputs(), ">3.10.11,<3.11");
|
await restoreCache(createSetupInputs(), ">3.10.11,<3.11");
|
||||||
@@ -95,10 +78,10 @@ describe("restoreCache", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("includes an inherited Python architecture in the cache key", async () => {
|
it("includes the resolved Python architecture in the cache key", async () => {
|
||||||
process.env.UV_PYTHON_ARCH = "aarch64";
|
const inputs = createSetupInputs({ pythonArch: "aarch64" });
|
||||||
|
|
||||||
await restoreCache(createSetupInputs(), "3.14");
|
await restoreCache(inputs, "3.14");
|
||||||
|
|
||||||
expect(cacheKeyOutput()).toContain("-3.14-python-aarch64-");
|
expect(cacheKeyOutput()).toContain("-3.14-python-aarch64-");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export function createSetupInputs(
|
|||||||
checksum: "",
|
checksum: "",
|
||||||
downloadFromAstralMirror: false,
|
downloadFromAstralMirror: false,
|
||||||
enableCache: true,
|
enableCache: true,
|
||||||
|
exportPythonArch: false,
|
||||||
githubToken: "",
|
githubToken: "",
|
||||||
ignoreEmptyWorkdir: false,
|
ignoreEmptyWorkdir: false,
|
||||||
ignoreNothingToCache: false,
|
ignoreNothingToCache: false,
|
||||||
|
|||||||
@@ -38,9 +38,7 @@ jest.unstable_mockModule("@actions/core", () => ({
|
|||||||
warning: mockWarning,
|
warning: mockWarning,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { CacheLocalSource, loadInputs, resolvePythonArch } = await import(
|
const { CacheLocalSource, loadInputs } = await import("../../src/utils/inputs");
|
||||||
"../../src/utils/inputs"
|
|
||||||
);
|
|
||||||
|
|
||||||
function createTempProject(files: Record<string, string> = {}): string {
|
function createTempProject(files: Record<string, string> = {}): string {
|
||||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "setup-uv-inputs-test-"));
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "setup-uv-inputs-test-"));
|
||||||
@@ -108,6 +106,7 @@ describe("loadInputs", () => {
|
|||||||
});
|
});
|
||||||
expect(inputs.pythonDir).toBe("/runner-temp/uv-python-dir");
|
expect(inputs.pythonDir).toBe("/runner-temp/uv-python-dir");
|
||||||
expect(inputs.pythonArch).toBe("");
|
expect(inputs.pythonArch).toBe("");
|
||||||
|
expect(inputs.exportPythonArch).toBe(false);
|
||||||
expect(inputs.venvPath).toBe("/workspace/.venv");
|
expect(inputs.venvPath).toBe("/workspace/.venv");
|
||||||
expect(inputs.manifestFile).toBeUndefined();
|
expect(inputs.manifestFile).toBeUndefined();
|
||||||
expect(inputs.resolutionStrategy).toBe("highest");
|
expect(inputs.resolutionStrategy).toBe("highest");
|
||||||
@@ -166,7 +165,7 @@ describe("loadInputs", () => {
|
|||||||
|
|
||||||
const inputs = loadInputs();
|
const inputs = loadInputs();
|
||||||
expect(inputs.pythonArch).toBe("x86_64");
|
expect(inputs.pythonArch).toBe("x86_64");
|
||||||
expect(resolvePythonArch(inputs.pythonArch)).toBe("x86_64");
|
expect(inputs.exportPythonArch).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each(["aarch64", "x86_64_v3", ""])(
|
it.each(["aarch64", "x86_64_v3", ""])(
|
||||||
@@ -176,8 +175,8 @@ describe("loadInputs", () => {
|
|||||||
process.env.UV_PYTHON_ARCH = pythonArch;
|
process.env.UV_PYTHON_ARCH = pythonArch;
|
||||||
|
|
||||||
const inputs = loadInputs();
|
const inputs = loadInputs();
|
||||||
expect(inputs.pythonArch).toBe("");
|
expect(inputs.pythonArch).toBe(pythonArch);
|
||||||
expect(resolvePythonArch(inputs.pythonArch)).toBe(pythonArch);
|
expect(inputs.exportPythonArch).toBe(false);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -57,16 +57,16 @@ afterEach(() => {
|
|||||||
|
|
||||||
describe("setupPythonArch", () => {
|
describe("setupPythonArch", () => {
|
||||||
it("leaves Python selection alone without an architecture", async () => {
|
it("leaves Python selection alone without an architecture", async () => {
|
||||||
await setupPythonArch("/tools/uv", "");
|
await setupPythonArch("/tools/uv", "", false);
|
||||||
|
|
||||||
expect(mockExecFile).not.toHaveBeenCalled();
|
expect(mockExecFile).not.toHaveBeenCalled();
|
||||||
expect(mockExportVariable).not.toHaveBeenCalled();
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("validates an inherited architecture without exporting it", async () => {
|
it("validates a resolved environment architecture without exporting it", async () => {
|
||||||
process.env.UV_PYTHON_ARCH = "aarch64";
|
process.env.UV_PYTHON_ARCH = "aarch64";
|
||||||
|
|
||||||
await setupPythonArch("/tools/uv", "");
|
await setupPythonArch("/tools/uv", "aarch64", false);
|
||||||
|
|
||||||
expect(mockExecFile).toHaveBeenNthCalledWith(
|
expect(mockExecFile).toHaveBeenNthCalledWith(
|
||||||
2,
|
2,
|
||||||
@@ -83,7 +83,7 @@ describe("setupPythonArch", () => {
|
|||||||
it.each(["/runner temp/uv", "C:\\runner temp\\uv.exe"])(
|
it.each(["/runner temp/uv", "C:\\runner temp\\uv.exe"])(
|
||||||
"validates and exports the architecture using the installed uv: %s",
|
"validates and exports the architecture using the installed uv: %s",
|
||||||
async (uvPath) => {
|
async (uvPath) => {
|
||||||
await setupPythonArch(uvPath, "x86_64");
|
await setupPythonArch(uvPath, "x86_64", true);
|
||||||
|
|
||||||
expect(mockExecFile).toHaveBeenNthCalledWith(
|
expect(mockExecFile).toHaveBeenNthCalledWith(
|
||||||
1,
|
1,
|
||||||
@@ -112,7 +112,7 @@ describe("setupPythonArch", () => {
|
|||||||
it("rejects uv versions that ignore UV_PYTHON_ARCH", async () => {
|
it("rejects uv versions that ignore UV_PYTHON_ARCH", async () => {
|
||||||
mockExecFile.mockReset().mockResolvedValue(success);
|
mockExecFile.mockReset().mockResolvedValue(success);
|
||||||
|
|
||||||
await expect(setupPythonArch("/tools/uv", "x86_64")).rejects.toThrow(
|
await expect(setupPythonArch("/tools/uv", "x86_64", true)).rejects.toThrow(
|
||||||
"The installed version of uv does not support UV_PYTHON_ARCH",
|
"The installed version of uv does not support UV_PYTHON_ARCH",
|
||||||
);
|
);
|
||||||
expect(mockExecFile).toHaveBeenCalledTimes(1);
|
expect(mockExecFile).toHaveBeenCalledTimes(1);
|
||||||
@@ -127,7 +127,7 @@ describe("setupPythonArch", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(setupPythonArch("/tools/uv", "x86_64")).rejects.toThrow(
|
await expect(setupPythonArch("/tools/uv", "x86_64", true)).rejects.toThrow(
|
||||||
"Failed to check uv's support for UV_PYTHON_ARCH: error: unrelated configuration error",
|
"Failed to check uv's support for UV_PYTHON_ARCH: error: unrelated configuration error",
|
||||||
);
|
);
|
||||||
expect(mockExportVariable).not.toHaveBeenCalled();
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
||||||
@@ -144,7 +144,7 @@ describe("setupPythonArch", () => {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(setupPythonArch("/tools/uv", "invalid")).rejects.toThrow(
|
await expect(setupPythonArch("/tools/uv", "invalid", true)).rejects.toThrow(
|
||||||
"Failed to set Python architecture to invalid: error: Unknown architecture: invalid",
|
"Failed to set Python architecture to invalid: error: Unknown architecture: invalid",
|
||||||
);
|
);
|
||||||
expect(mockExportVariable).not.toHaveBeenCalled();
|
expect(mockExportVariable).not.toHaveBeenCalled();
|
||||||
|
|||||||
23
dist/save-cache/index.cjs
generated
vendored
23
dist/save-cache/index.cjs
generated
vendored
@@ -63714,6 +63714,15 @@ function info2(msg) {
|
|||||||
}
|
}
|
||||||
var warning2 = warning;
|
var warning2 = warning;
|
||||||
|
|
||||||
|
// src/cache/restore-cache.ts
|
||||||
|
var STATE_CACHE_KEY = "cache-key";
|
||||||
|
var STATE_CACHE_MATCHED_KEY = "cache-matched-key";
|
||||||
|
var STATE_PYTHON_CACHE_MATCHED_KEY = "python-cache-matched-key";
|
||||||
|
|
||||||
|
// src/utils/constants.ts
|
||||||
|
var STATE_UV_PATH = "uv-path";
|
||||||
|
var STATE_UV_VERSION = "uv-version";
|
||||||
|
|
||||||
// src/utils/inputs.ts
|
// src/utils/inputs.ts
|
||||||
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
||||||
var import_node_path = __toESM(require("node:path"), 1);
|
var import_node_path = __toESM(require("node:path"), 1);
|
||||||
@@ -64438,7 +64447,9 @@ function loadInputs() {
|
|||||||
const version3 = getInput("version");
|
const version3 = getInput("version");
|
||||||
const versionFile = getVersionFile(workingDirectory);
|
const versionFile = getVersionFile(workingDirectory);
|
||||||
const pythonVersion = getPythonVersion(versionFile);
|
const pythonVersion = getPythonVersion(versionFile);
|
||||||
const pythonArch = getInput("python-arch");
|
const pythonArchInput = getInput("python-arch");
|
||||||
|
const pythonArch = pythonArchInput || process.env.UV_PYTHON_ARCH || "";
|
||||||
|
const exportPythonArch = pythonArchInput !== "";
|
||||||
const activateEnvironment = getBooleanInput("activate-environment");
|
const activateEnvironment = getBooleanInput("activate-environment");
|
||||||
const noProject = getBooleanInput("no-project");
|
const noProject = getBooleanInput("no-project");
|
||||||
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
||||||
@@ -64476,6 +64487,7 @@ function loadInputs() {
|
|||||||
checksum,
|
checksum,
|
||||||
downloadFromAstralMirror,
|
downloadFromAstralMirror,
|
||||||
enableCache,
|
enableCache,
|
||||||
|
exportPythonArch,
|
||||||
githubToken,
|
githubToken,
|
||||||
ignoreEmptyWorkdir,
|
ignoreEmptyWorkdir,
|
||||||
ignoreNothingToCache,
|
ignoreNothingToCache,
|
||||||
@@ -64731,15 +64743,6 @@ function getResolutionStrategy() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/cache/restore-cache.ts
|
|
||||||
var STATE_CACHE_KEY = "cache-key";
|
|
||||||
var STATE_CACHE_MATCHED_KEY = "cache-matched-key";
|
|
||||||
var STATE_PYTHON_CACHE_MATCHED_KEY = "python-cache-matched-key";
|
|
||||||
|
|
||||||
// src/utils/constants.ts
|
|
||||||
var STATE_UV_PATH = "uv-path";
|
|
||||||
var STATE_UV_VERSION = "uv-version";
|
|
||||||
|
|
||||||
// src/save-cache.ts
|
// src/save-cache.ts
|
||||||
function formatUnexpectedFailure(error2) {
|
function formatUnexpectedFailure(error2) {
|
||||||
if (error2 instanceof Error) {
|
if (error2 instanceof Error) {
|
||||||
|
|||||||
2184
dist/setup/index.cjs
generated
vendored
2184
dist/setup/index.cjs
generated
vendored
File diff suppressed because it is too large
Load Diff
7
src/cache/restore-cache.ts
vendored
7
src/cache/restore-cache.ts
vendored
@@ -1,7 +1,7 @@
|
|||||||
import * as cache from "@actions/cache";
|
import * as cache from "@actions/cache";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import { hashFiles } from "../hash/hash-files";
|
import { hashFiles } from "../hash/hash-files";
|
||||||
import { resolvePythonArch, type SetupInputs } from "../utils/inputs";
|
import type { SetupInputs } from "../utils/inputs";
|
||||||
import * as log from "../utils/logging";
|
import * as log from "../utils/logging";
|
||||||
import { getArch, getOSNameVersion, getPlatform } from "../utils/platforms";
|
import { getArch, getOSNameVersion, getPlatform } from "../utils/platforms";
|
||||||
|
|
||||||
@@ -98,9 +98,8 @@ async function computeKeys(
|
|||||||
? `-${encodeURIComponent(inputs.cacheSuffix)}`
|
? `-${encodeURIComponent(inputs.cacheSuffix)}`
|
||||||
: "";
|
: "";
|
||||||
const version = encodeURIComponent(pythonVersion ?? "unknown");
|
const version = encodeURIComponent(pythonVersion ?? "unknown");
|
||||||
const pythonArch = resolvePythonArch(inputs.pythonArch);
|
const pythonArchKey = inputs.pythonArch
|
||||||
const pythonArchKey = pythonArch
|
? `-python-${encodeURIComponent(inputs.pythonArch)}`
|
||||||
? `-python-${encodeURIComponent(pythonArch)}`
|
|
||||||
: "";
|
: "";
|
||||||
const platform = await getPlatform();
|
const platform = await getPlatform();
|
||||||
const osNameVersion = getOSNameVersion();
|
const osNameVersion = getOSNameVersion();
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ async function run(): Promise<void> {
|
|||||||
setupResult.uvDir,
|
setupResult.uvDir,
|
||||||
process.platform === "win32" ? "uv.exe" : "uv",
|
process.platform === "win32" ? "uv.exe" : "uv",
|
||||||
);
|
);
|
||||||
await setupPythonArch(uvPath, inputs.pythonArch);
|
await setupPythonArch(uvPath, inputs.pythonArch, inputs.exportPythonArch);
|
||||||
|
|
||||||
addToolBinToPath(inputs);
|
addToolBinToPath(inputs);
|
||||||
addUvToPathAndOutput(setupResult.uvDir);
|
addUvToPathAndOutput(setupResult.uvDir);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface SetupInputs {
|
|||||||
versionFile: string;
|
versionFile: string;
|
||||||
pythonVersion: string;
|
pythonVersion: string;
|
||||||
pythonArch: string;
|
pythonArch: string;
|
||||||
|
exportPythonArch: boolean;
|
||||||
activateEnvironment: boolean;
|
activateEnvironment: boolean;
|
||||||
noProject: boolean;
|
noProject: boolean;
|
||||||
venvPath: string;
|
venvPath: string;
|
||||||
@@ -55,7 +56,9 @@ export function loadInputs(): SetupInputs {
|
|||||||
const version = core.getInput("version");
|
const version = core.getInput("version");
|
||||||
const versionFile = getVersionFile(workingDirectory);
|
const versionFile = getVersionFile(workingDirectory);
|
||||||
const pythonVersion = getPythonVersion(versionFile);
|
const pythonVersion = getPythonVersion(versionFile);
|
||||||
const pythonArch = core.getInput("python-arch");
|
const pythonArchInput = core.getInput("python-arch");
|
||||||
|
const pythonArch = pythonArchInput || process.env.UV_PYTHON_ARCH || "";
|
||||||
|
const exportPythonArch = pythonArchInput !== "";
|
||||||
const activateEnvironment = core.getBooleanInput("activate-environment");
|
const activateEnvironment = core.getBooleanInput("activate-environment");
|
||||||
const noProject = core.getBooleanInput("no-project");
|
const noProject = core.getBooleanInput("no-project");
|
||||||
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
||||||
@@ -96,6 +99,7 @@ export function loadInputs(): SetupInputs {
|
|||||||
checksum,
|
checksum,
|
||||||
downloadFromAstralMirror,
|
downloadFromAstralMirror,
|
||||||
enableCache,
|
enableCache,
|
||||||
|
exportPythonArch,
|
||||||
githubToken,
|
githubToken,
|
||||||
ignoreEmptyWorkdir,
|
ignoreEmptyWorkdir,
|
||||||
ignoreNothingToCache,
|
ignoreNothingToCache,
|
||||||
@@ -149,10 +153,6 @@ function getPythonVersion(versionFile: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePythonArch(pythonArch: string): string {
|
|
||||||
return pythonArch || process.env.UV_PYTHON_ARCH || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getVenvPath(
|
function getVenvPath(
|
||||||
workingDirectory: string,
|
workingDirectory: string,
|
||||||
activateEnvironment: boolean,
|
activateEnvironment: boolean,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { execFile } from "node:child_process";
|
import { execFile } from "node:child_process";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
import { resolvePythonArch } from "./inputs";
|
|
||||||
import * as log from "./logging";
|
import * as log from "./logging";
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
@@ -9,9 +8,9 @@ const PROBE_ARCH = "setup-uv-probe";
|
|||||||
|
|
||||||
export async function setupPythonArch(
|
export async function setupPythonArch(
|
||||||
uvPath: string,
|
uvPath: string,
|
||||||
pythonArchInput: string,
|
pythonArch: string,
|
||||||
|
exportPythonArch: boolean,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const pythonArch = resolvePythonArch(pythonArchInput);
|
|
||||||
if (pythonArch === "") {
|
if (pythonArch === "") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -41,7 +40,7 @@ export async function setupPythonArch(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pythonArchInput !== "") {
|
if (exportPythonArch) {
|
||||||
core.exportVariable("UV_PYTHON_ARCH", pythonArch);
|
core.exportVariable("UV_PYTHON_ARCH", pythonArch);
|
||||||
log.info(`Set UV_PYTHON_ARCH to ${pythonArch}`);
|
log.info(`Set UV_PYTHON_ARCH to ${pythonArch}`);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user