Resolve Python architecture during input loading

This commit is contained in:
Zanie Blue
2026-10-02 13:19:07 -05:00
parent 7cc9e96834
commit db42fc9bc6
10 changed files with 1132 additions and 1152 deletions

View File

@@ -1,11 +1,4 @@
import {
afterEach,
beforeEach,
describe,
expect,
it,
jest,
} from "@jest/globals";
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
import { createSetupInputs } from "../helpers/setup-inputs";
const mockRestoreCache = jest.fn();
@@ -14,7 +7,6 @@ const mockSetOutput = jest.fn();
const mockGetArch = jest.fn(() => "x86_64");
const mockGetOSNameVersion = jest.fn(() => "ubuntu-24.04");
const mockGetPlatform = jest.fn(async () => "unknown-linux-gnu");
const ORIGINAL_UV_PYTHON_ARCH = process.env.UV_PYTHON_ARCH;
jest.unstable_mockModule("@actions/cache", () => ({
restoreCache: mockRestoreCache,
@@ -49,21 +41,12 @@ function cacheKeyOutput(): string {
}
beforeEach(() => {
delete process.env.UV_PYTHON_ARCH;
jest.clearAllMocks();
mockGetArch.mockReturnValue("x86_64");
mockGetOSNameVersion.mockReturnValue("ubuntu-24.04");
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", () => {
it("encodes Python version ranges before adding them to the cache key", async () => {
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 () => {
process.env.UV_PYTHON_ARCH = "aarch64";
it("includes the resolved Python architecture in the cache key", async () => {
const inputs = createSetupInputs({ pythonArch: "aarch64" });
await restoreCache(createSetupInputs(), "3.14");
await restoreCache(inputs, "3.14");
expect(cacheKeyOutput()).toContain("-3.14-python-aarch64-");
});

View File

@@ -16,6 +16,7 @@ export function createSetupInputs(
checksum: "",
downloadFromAstralMirror: false,
enableCache: true,
exportPythonArch: false,
githubToken: "",
ignoreEmptyWorkdir: false,
ignoreNothingToCache: false,

View File

@@ -38,9 +38,7 @@ jest.unstable_mockModule("@actions/core", () => ({
warning: mockWarning,
}));
const { CacheLocalSource, loadInputs, resolvePythonArch } = await import(
"../../src/utils/inputs"
);
const { CacheLocalSource, loadInputs } = await import("../../src/utils/inputs");
function createTempProject(files: Record<string, string> = {}): string {
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.pythonArch).toBe("");
expect(inputs.exportPythonArch).toBe(false);
expect(inputs.venvPath).toBe("/workspace/.venv");
expect(inputs.manifestFile).toBeUndefined();
expect(inputs.resolutionStrategy).toBe("highest");
@@ -166,7 +165,7 @@ describe("loadInputs", () => {
const inputs = loadInputs();
expect(inputs.pythonArch).toBe("x86_64");
expect(resolvePythonArch(inputs.pythonArch)).toBe("x86_64");
expect(inputs.exportPythonArch).toBe(true);
});
it.each(["aarch64", "x86_64_v3", ""])(
@@ -176,8 +175,8 @@ describe("loadInputs", () => {
process.env.UV_PYTHON_ARCH = pythonArch;
const inputs = loadInputs();
expect(inputs.pythonArch).toBe("");
expect(resolvePythonArch(inputs.pythonArch)).toBe(pythonArch);
expect(inputs.pythonArch).toBe(pythonArch);
expect(inputs.exportPythonArch).toBe(false);
},
);

View File

@@ -57,16 +57,16 @@ afterEach(() => {
describe("setupPythonArch", () => {
it("leaves Python selection alone without an architecture", async () => {
await setupPythonArch("/tools/uv", "");
await setupPythonArch("/tools/uv", "", false);
expect(mockExecFile).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";
await setupPythonArch("/tools/uv", "");
await setupPythonArch("/tools/uv", "aarch64", false);
expect(mockExecFile).toHaveBeenNthCalledWith(
2,
@@ -83,7 +83,7 @@ describe("setupPythonArch", () => {
it.each(["/runner temp/uv", "C:\\runner temp\\uv.exe"])(
"validates and exports the architecture using the installed uv: %s",
async (uvPath) => {
await setupPythonArch(uvPath, "x86_64");
await setupPythonArch(uvPath, "x86_64", true);
expect(mockExecFile).toHaveBeenNthCalledWith(
1,
@@ -112,7 +112,7 @@ describe("setupPythonArch", () => {
it("rejects uv versions that ignore UV_PYTHON_ARCH", async () => {
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",
);
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",
);
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",
);
expect(mockExportVariable).not.toHaveBeenCalled();