From 87f752e4009c574fb179d04fff023fa4adfd8c02 Mon Sep 17 00:00:00 2001 From: Raj-StepSecurity Date: Mon, 19 Oct 2026 10:37:59 +0530 Subject: [PATCH 1/3] chore: sync with upstream v10.3.0 --- .github/workflows/test.yml | 2 - README.md | 23 ++++ __tests__/cache/restore-cache.test.ts | 47 ++++++- __tests__/helpers/setup-inputs.ts | 2 + __tests__/utils/inputs.test.ts | 31 +++++ __tests__/utils/python-arch.test.ts | 152 +++++++++++++++++++++ action-types.yml | 2 + action.yml | 3 + config.json | 17 +++ dist/save-cache/index.cjs | 5 + dist/setup/index.cjs | 89 ++++++++++-- docs/caching.md | 1 + docs/environment-and-tools.md | 2 + package-lock.json | 7 +- package.json | 10 +- src/cache/restore-cache.ts | 5 +- src/download/checksum/known-checksums.json | 144 +++++++++++++++++++ src/setup-uv.ts | 6 + src/utils/inputs.ts | 7 + src/utils/python-arch.ts | 75 ++++++++++ 20 files changed, 606 insertions(+), 24 deletions(-) create mode 100644 __tests__/utils/python-arch.test.ts create mode 100644 config.json create mode 100644 src/utils/python-arch.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 43b0152..b1d8881 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -647,8 +647,6 @@ jobs: expected-os: "ubuntu-22.04" - os: ubuntu-24.04 expected-os: "ubuntu-24.04" - - os: macos-14 - expected-os: "macos-14" - os: macos-15 expected-os: "macos-15" - os: windows-2022 diff --git a/README.md b/README.md index c5920ea..f652283 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Set up your GitHub Actions workflow with a specific version of [uv](https://docs - [Inputs](#inputs) - [Outputs](#outputs) - [Python version](#python-version) + - [Python architecture](#python-architecture) - [Working directory](#working-directory) - [Advanced Configuration](#advanced-configuration) - [How it works](#how-it-works) @@ -58,6 +59,9 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed # The version of Python to set UV_PYTHON to (overrides the Python version from .tool-versions) python-version: "" + # The Python architecture to set UV_PYTHON_ARCH to, e.g., x86_64 or aarch64 + python-arch: "" + # Use uv venv to activate a venv ready to be used by later steps activate-environment: "false" @@ -195,6 +199,25 @@ jobs: run: uv run --frozen pytest ``` +### Python architecture + +Use `python-arch` to set `UV_PYTHON_ARCH` for the rest of the job. This selects the Python +architecture independently of the version, including versions requested by `.python-version`. +An explicit architecture or interpreter path in a Python request takes precedence. + +```yaml +- uses: step-security/setup-uv@v10 + with: + python-version: "3.14" + python-arch: x86_64 +- run: uv run --frozen pytest +``` + +The input overrides an existing `UV_PYTHON_ARCH` value. When it is omitted, the action respects +`UV_PYTHON_ARCH` from the environment. Both forms require a uv version that supports the variable; +the action reports an error if the installed version does not support it. The selected architecture +is included in the [cache key](docs/caching.md#cache-key). + ### Working directory You can set the working directory with the `working-directory` input. diff --git a/__tests__/cache/restore-cache.test.ts b/__tests__/cache/restore-cache.test.ts index bb97348..fdc80d5 100644 --- a/__tests__/cache/restore-cache.test.ts +++ b/__tests__/cache/restore-cache.test.ts @@ -4,6 +4,9 @@ import { createSetupInputs } from "../helpers/setup-inputs"; const mockRestoreCache = jest.fn(); const mockSaveState = jest.fn(); 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"); jest.unstable_mockModule("@actions/cache", () => ({ restoreCache: mockRestoreCache, @@ -24,9 +27,9 @@ jest.unstable_mockModule("../../src/utils/logging", () => ({ })); jest.unstable_mockModule("../../src/utils/platforms", () => ({ - getArch: jest.fn(() => "x86_64"), - getOSNameVersion: jest.fn(() => "ubuntu-24.04"), - getPlatform: jest.fn(async () => "unknown-linux-gnu"), + getArch: mockGetArch, + getOSNameVersion: mockGetOSNameVersion, + getPlatform: mockGetPlatform, })); const { restoreCache } = await import("../../src/cache/restore-cache"); @@ -39,6 +42,9 @@ function cacheKeyOutput(): string { beforeEach(() => { jest.clearAllMocks(); + mockGetArch.mockReturnValue("x86_64"); + mockGetOSNameVersion.mockReturnValue("ubuntu-24.04"); + mockGetPlatform.mockResolvedValue("unknown-linux-gnu"); }); describe("restoreCache", () => { @@ -71,4 +77,39 @@ describe("restoreCache", () => { "setup-uv-2-x86_64-unknown-linux-gnu-ubuntu-24.04-3.11-dependencyhash-tests-3.11", ); }); + + it("includes the resolved Python architecture in the cache key", async () => { + const inputs = createSetupInputs({ pythonArch: "aarch64" }); + + await restoreCache(inputs, "3.14"); + + expect(cacheKeyOutput()).toContain("-3.14-python-aarch64-"); + }); + + it.each(["aarch64", "x86_64"])( + "separates %s Python caches on a Windows ARM64 runner", + async (pythonArch) => { + mockGetArch.mockReturnValue("aarch64"); + mockGetOSNameVersion.mockReturnValue("windows-11"); + mockGetPlatform.mockResolvedValue("pc-windows-msvc"); + const inputs = createSetupInputs({ + cachePython: true, + pythonArch, + restoreCache: true, + }); + + await restoreCache(inputs, "3.14"); + + const cacheKey = `setup-uv-2-aarch64-pc-windows-msvc-windows-11-3.14-python-${pythonArch}-py-dependencyhash`; + expect(cacheKeyOutput()).toBe(cacheKey); + expect(mockRestoreCache).toHaveBeenCalledWith( + [inputs.cacheLocalPath?.path], + cacheKey, + ); + expect(mockRestoreCache).toHaveBeenCalledWith( + [inputs.pythonDir], + `${cacheKey}-python`, + ); + }, + ); }); diff --git a/__tests__/helpers/setup-inputs.ts b/__tests__/helpers/setup-inputs.ts index 0a6a625..f20e57d 100644 --- a/__tests__/helpers/setup-inputs.ts +++ b/__tests__/helpers/setup-inputs.ts @@ -16,11 +16,13 @@ export function createSetupInputs( checksum: "", downloadFromAstralMirror: false, enableCache: true, + exportPythonArch: false, githubToken: "", ignoreEmptyWorkdir: false, ignoreNothingToCache: false, noProject: false, pruneCache: false, + pythonArch: "", pythonDir: "/tmp/uv-python-dir", pythonVersion: "", quiet: false, diff --git a/__tests__/utils/inputs.test.ts b/__tests__/utils/inputs.test.ts index f93a41b..126ca8f 100644 --- a/__tests__/utils/inputs.test.ts +++ b/__tests__/utils/inputs.test.ts @@ -19,6 +19,7 @@ const ORIGINAL_RUNNER_ENVIRONMENT = process.env.RUNNER_ENVIRONMENT; const ORIGINAL_RUNNER_TEMP = process.env.RUNNER_TEMP; const ORIGINAL_UV_CACHE_DIR = process.env.UV_CACHE_DIR; const ORIGINAL_UV_PYTHON = process.env.UV_PYTHON; +const ORIGINAL_UV_PYTHON_ARCH = process.env.UV_PYTHON_ARCH; const ORIGINAL_UV_PYTHON_INSTALL_DIR = process.env.UV_PYTHON_INSTALL_DIR; const mockDebug = jest.fn(); @@ -62,6 +63,7 @@ function resetEnvironment(): void { delete process.env.RUNNER_TEMP; delete process.env.UV_CACHE_DIR; delete process.env.UV_PYTHON; + delete process.env.UV_PYTHON_ARCH; delete process.env.UV_PYTHON_INSTALL_DIR; } @@ -77,6 +79,11 @@ function restoreEnvironment(): void { process.env.RUNNER_TEMP = ORIGINAL_RUNNER_TEMP; process.env.UV_CACHE_DIR = ORIGINAL_UV_CACHE_DIR; process.env.UV_PYTHON = ORIGINAL_UV_PYTHON; + if (ORIGINAL_UV_PYTHON_ARCH === undefined) { + delete process.env.UV_PYTHON_ARCH; + } else { + process.env.UV_PYTHON_ARCH = ORIGINAL_UV_PYTHON_ARCH; + } process.env.UV_PYTHON_INSTALL_DIR = ORIGINAL_UV_PYTHON_INSTALL_DIR; } @@ -98,6 +105,8 @@ describe("loadInputs", () => { source: CacheLocalSource.Default, }); 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"); @@ -149,6 +158,28 @@ describe("loadInputs", () => { expect(inputs.pythonVersion).toBe(""); }); + it("prefers the python-arch input over UV_PYTHON_ARCH", () => { + mockInputs["working-directory"] = "/workspace"; + mockInputs["python-arch"] = "x86_64"; + process.env.UV_PYTHON_ARCH = "aarch64"; + + const inputs = loadInputs(); + expect(inputs.pythonArch).toBe("x86_64"); + expect(inputs.exportPythonArch).toBe(true); + }); + + it.each(["aarch64", "x86_64_v3", ""])( + "uses UV_PYTHON_ARCH when python-arch is omitted: %s", + (pythonArch) => { + mockInputs["working-directory"] = "/workspace"; + process.env.UV_PYTHON_ARCH = pythonArch; + + const inputs = loadInputs(); + expect(inputs.pythonArch).toBe(pythonArch); + expect(inputs.exportPythonArch).toBe(false); + }, + ); + it.each(["pull_request_target", "workflow_run", "release"])( "disables automatic caching for the %s event", (eventName) => { diff --git a/__tests__/utils/python-arch.test.ts b/__tests__/utils/python-arch.test.ts new file mode 100644 index 0000000..f846c7b --- /dev/null +++ b/__tests__/utils/python-arch.test.ts @@ -0,0 +1,152 @@ +import { promisify } from "node:util"; +import { + afterEach, + beforeEach, + describe, + expect, + it, + jest, +} from "@jest/globals"; + +const ORIGINAL_UV_PYTHON_ARCH = process.env.UV_PYTHON_ARCH; + +const mockExecFile = + jest.fn< + (...args: unknown[]) => Promise<{ + stdout: string; + stderr: string; + }> + >(); +const mockExportVariable = jest.fn(); + +jest.unstable_mockModule("node:child_process", () => ({ + execFile: Object.assign(mockExecFile, { [promisify.custom]: mockExecFile }), +})); +jest.unstable_mockModule("@actions/core", () => ({ + exportVariable: mockExportVariable, +})); +jest.unstable_mockModule("../../src/utils/logging", () => ({ + info: jest.fn(), +})); + +const { setupPythonArch } = await import("../../src/utils/python-arch"); + +const supportedProbe = Object.assign(new Error("uv exited with code 2"), { + code: 2, + stderr: + "error: Failed to parse environment variable `UV_PYTHON_ARCH` with invalid value `setup-uv-probe`: Unknown architecture: setup-uv-probe\n", +}); +const success = { stderr: "", stdout: "/cache\n" }; + +beforeEach(() => { + delete process.env.UV_PYTHON_ARCH; + jest.clearAllMocks(); + mockExecFile + .mockReset() + .mockRejectedValueOnce(supportedProbe) + .mockResolvedValueOnce(success); +}); + +afterEach(() => { + if (ORIGINAL_UV_PYTHON_ARCH === undefined) { + delete process.env.UV_PYTHON_ARCH; + } else { + process.env.UV_PYTHON_ARCH = ORIGINAL_UV_PYTHON_ARCH; + } +}); + +describe("setupPythonArch", () => { + it("leaves Python selection alone without an architecture", async () => { + await setupPythonArch("/tools/uv", "", false); + + expect(mockExecFile).not.toHaveBeenCalled(); + expect(mockExportVariable).not.toHaveBeenCalled(); + }); + + it("validates a resolved environment architecture without exporting it", async () => { + process.env.UV_PYTHON_ARCH = "aarch64"; + + await setupPythonArch("/tools/uv", "aarch64", false); + + expect(mockExecFile).toHaveBeenNthCalledWith( + 2, + "/tools/uv", + ["--no-config", "cache", "dir"], + expect.objectContaining({ + env: expect.objectContaining({ UV_PYTHON_ARCH: "aarch64" }), + }), + ); + expect(mockExportVariable).not.toHaveBeenCalled(); + expect(process.env.UV_PYTHON_ARCH).toBe("aarch64"); + }); + + 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", true); + + expect(mockExecFile).toHaveBeenNthCalledWith( + 1, + uvPath, + ["--no-config", "cache", "dir"], + expect.objectContaining({ + encoding: "utf8", + env: expect.objectContaining({ UV_PYTHON_ARCH: "setup-uv-probe" }), + }), + ); + expect(mockExecFile).toHaveBeenNthCalledWith( + 2, + uvPath, + ["--no-config", "cache", "dir"], + expect.objectContaining({ + env: expect.objectContaining({ UV_PYTHON_ARCH: "x86_64" }), + }), + ); + expect(mockExportVariable).toHaveBeenCalledWith( + "UV_PYTHON_ARCH", + "x86_64", + ); + }, + ); + + it("rejects uv versions that ignore UV_PYTHON_ARCH", async () => { + mockExecFile.mockReset().mockResolvedValue(success); + + 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); + expect(mockExportVariable).not.toHaveBeenCalled(); + }); + + it("reports unexpected probe failures", async () => { + mockExecFile.mockReset().mockRejectedValue( + Object.assign(new Error("uv exited with code 2"), { + code: 2, + stderr: "error: unrelated configuration error\n", + }), + ); + + 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(); + }); + + it("reports invalid architectures before exporting them", async () => { + mockExecFile + .mockReset() + .mockRejectedValueOnce(supportedProbe) + .mockRejectedValueOnce( + Object.assign(new Error("uv exited with code 2"), { + code: 2, + stderr: "error: Unknown architecture: invalid\n", + }), + ); + + await expect(setupPythonArch("/tools/uv", "invalid", true)).rejects.toThrow( + "Failed to set Python architecture to invalid: error: Unknown architecture: invalid", + ); + expect(mockExportVariable).not.toHaveBeenCalled(); + }); +}); diff --git a/action-types.yml b/action-types.yml index a2b4ac3..3746c94 100644 --- a/action-types.yml +++ b/action-types.yml @@ -7,6 +7,8 @@ inputs: type: string python-version: type: string + python-arch: + type: string activate-environment: type: boolean venv-path: diff --git a/action.yml b/action.yml index e00ee60..55df62c 100644 --- a/action.yml +++ b/action.yml @@ -12,6 +12,9 @@ inputs: python-version: description: "The version of Python to set UV_PYTHON to. Overrides the Python version from .tool-versions." required: false + python-arch: + description: "The Python architecture to set UV_PYTHON_ARCH to, e.g., x86_64 or aarch64. Overrides UV_PYTHON_ARCH." + required: false activate-environment: description: "Use uv venv to activate a venv ready to be used by later steps. " default: "false" diff --git a/config.json b/config.json new file mode 100644 index 0000000..7d10eef --- /dev/null +++ b/config.json @@ -0,0 +1,17 @@ +{ + "$comment": "Managed automatically when syncing with upstream. Do not edit by hand.", + "schema_version": 1, + "onboarding_type": "copied", + "action_type": "node", + "upstream": { + "repository": "astral-sh/setup-uv", + "synced_tag": "v10.3.0", + "synced_commit": "1c37ad07a6a961277cf70c0d37d6f313000f5884", + "archived": false + }, + "build": { + "package_manager": "npm@11.12.1", + "node_version": "24", + "script": "all" + } +} diff --git a/dist/save-cache/index.cjs b/dist/save-cache/index.cjs index a72053e..983ed8c 100644 --- a/dist/save-cache/index.cjs +++ b/dist/save-cache/index.cjs @@ -78439,6 +78439,9 @@ function loadInputs() { const version3 = getInput("version"); const versionFile = getVersionFile(workingDirectory); const pythonVersion = getPythonVersion(versionFile); + const pythonArchInput = getInput("python-arch"); + const pythonArch = pythonArchInput || process.env.UV_PYTHON_ARCH || ""; + const exportPythonArch = pythonArchInput !== ""; const activateEnvironment = getBooleanInput("activate-environment"); const noProject = getBooleanInput("no-project"); const venvPath = getVenvPath(workingDirectory, activateEnvironment); @@ -78476,12 +78479,14 @@ function loadInputs() { checksum, downloadFromAstralMirror, enableCache, + exportPythonArch, githubToken, ignoreEmptyWorkdir, ignoreNothingToCache, manifestFile, noProject, pruneCache: pruneCache2, + pythonArch, pythonDir, pythonVersion, quiet: quiet2, diff --git a/dist/setup/index.cjs b/dist/setup/index.cjs index 640e9e3..c5ad1b2 100644 --- a/dist/setup/index.cjs +++ b/dist/setup/index.cjs @@ -11102,7 +11102,7 @@ var require_mock_interceptor = __commonJS({ var require_mock_client = __commonJS({ "node_modules/@actions/http-client/node_modules/undici/lib/mock/mock-client.js"(exports2, module2) { "use strict"; - var { promisify: promisify6 } = require("node:util"); + var { promisify: promisify7 } = require("node:util"); var Client = require_client(); var { buildMockDispatch } = require_mock_utils(); var { @@ -11142,7 +11142,7 @@ var require_mock_client = __commonJS({ return new MockInterceptor(opts, this[kDispatches]); } async [kClose]() { - await promisify6(this[kOriginalClose])(); + await promisify7(this[kOriginalClose])(); this[kConnected] = 0; this[kMockAgent][Symbols.kClients].delete(this[kOrigin]); } @@ -11155,7 +11155,7 @@ var require_mock_client = __commonJS({ var require_mock_pool = __commonJS({ "node_modules/@actions/http-client/node_modules/undici/lib/mock/mock-pool.js"(exports2, module2) { "use strict"; - var { promisify: promisify6 } = require("node:util"); + var { promisify: promisify7 } = require("node:util"); var Pool = require_pool(); var { buildMockDispatch } = require_mock_utils(); var { @@ -11195,7 +11195,7 @@ var require_mock_pool = __commonJS({ return new MockInterceptor(opts, this[kDispatches]); } async [kClose]() { - await promisify6(this[kOriginalClose])(); + await promisify7(this[kOriginalClose])(); this[kConnected] = 0; this[kMockAgent][Symbols.kClients].delete(this[kOrigin]); } @@ -44167,7 +44167,7 @@ var require_mock_interceptor2 = __commonJS({ var require_mock_client2 = __commonJS({ "node_modules/undici/lib/mock/mock-client.js"(exports2, module2) { "use strict"; - var { promisify: promisify6 } = require("node:util"); + var { promisify: promisify7 } = require("node:util"); var Client = require_client2(); var { buildMockDispatch } = require_mock_utils2(); var { @@ -44215,7 +44215,7 @@ var require_mock_client2 = __commonJS({ this[kDispatches] = []; } async [kClose]() { - await promisify6(this[kOriginalClose])(); + await promisify7(this[kOriginalClose])(); this[kConnected] = 0; this[kMockAgent][Symbols.kClients].delete(this[kOrigin]); } @@ -44428,7 +44428,7 @@ var require_mock_call_history = __commonJS({ var require_mock_pool2 = __commonJS({ "node_modules/undici/lib/mock/mock-pool.js"(exports2, module2) { "use strict"; - var { promisify: promisify6 } = require("node:util"); + var { promisify: promisify7 } = require("node:util"); var Pool = require_pool2(); var { buildMockDispatch } = require_mock_utils2(); var { @@ -44476,7 +44476,7 @@ var require_mock_pool2 = __commonJS({ this[kDispatches] = []; } async [kClose]() { - await promisify6(this[kOriginalClose])(); + await promisify7(this[kOriginalClose])(); this[kConnected] = 0; this[kMockAgent][Symbols.kClients].delete(this[kOrigin]); } @@ -68793,7 +68793,7 @@ var require_promisify = __commonJS({ "node_modules/axios/node_modules/agent-base/dist/src/promisify.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - function promisify6(fn) { + function promisify7(fn) { return function(req, opts) { return new Promise((resolve3, reject) => { fn.call(this, req, opts, (err, rtn) => { @@ -68806,7 +68806,7 @@ var require_promisify = __commonJS({ }); }; } - exports2.default = promisify6; + exports2.default = promisify7; } }); @@ -108714,11 +108714,12 @@ async function computeKeys(inputs, pythonVersion) { } const suffix = inputs.cacheSuffix ? `-${encodeURIComponent(inputs.cacheSuffix)}` : ""; const version3 = encodeURIComponent(pythonVersion ?? "unknown"); + const pythonArchKey = inputs.pythonArch ? `-python-${encodeURIComponent(inputs.pythonArch)}` : ""; const platform2 = await getPlatform(); const osNameVersion = getOSNameVersion(); const pruned = inputs.pruneCache ? "-pruned" : ""; const python = inputs.cachePython ? "-py" : ""; - return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform2}-${osNameVersion}-${version3}${pruned}${python}${cacheDependencyPathHash}${suffix}`; + return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform2}-${osNameVersion}-${version3}${pythonArchKey}${pruned}${python}${cacheDependencyPathHash}${suffix}`; } function handleMatchResult(matchedKey, primaryKey, stateKey, outputKey) { if (!matchedKey) { @@ -116451,6 +116452,9 @@ function loadInputs() { const version3 = getInput("version"); const versionFile = getVersionFile(workingDirectory); const pythonVersion = getPythonVersion(versionFile); + const pythonArchInput = getInput("python-arch"); + const pythonArch = pythonArchInput || process.env.UV_PYTHON_ARCH || ""; + const exportPythonArch = pythonArchInput !== ""; const activateEnvironment2 = getBooleanInput("activate-environment"); const noProject = getBooleanInput("no-project"); const venvPath = getVenvPath(workingDirectory, activateEnvironment2); @@ -116488,12 +116492,14 @@ function loadInputs() { checksum, downloadFromAstralMirror, enableCache, + exportPythonArch, githubToken, ignoreEmptyWorkdir, ignoreNothingToCache, manifestFile, noProject, pruneCache, + pythonArch, pythonDir, pythonVersion, quiet: quiet2, @@ -116742,16 +116748,68 @@ function getResolutionStrategy() { ); } -// src/utils/python-runtime.ts +// src/utils/python-arch.ts var import_node_child_process = require("node:child_process"); var import_node_util4 = require("node:util"); var execFileAsync = (0, import_node_util4.promisify)(import_node_child_process.execFile); +var PROBE_ARCH = "setup-uv-probe"; +async function setupPythonArch(uvPath, pythonArch, exportPythonArch) { + if (pythonArch === "") { + return; + } + const probe = await queryPythonArch(uvPath, PROBE_ARCH); + if (probe.exitCode === 0) { + throw new Error( + "The installed version of uv does not support UV_PYTHON_ARCH. Select a newer uv version or use an architecture-qualified python-version." + ); + } + if (!probe.stderr.includes( + `environment variable \`UV_PYTHON_ARCH\` with invalid value \`${PROBE_ARCH}\`` + )) { + throw new Error( + `Failed to check uv's support for UV_PYTHON_ARCH: ${probe.stderr.trim() || `uv exited with code ${probe.exitCode}`}` + ); + } + const selected = await queryPythonArch(uvPath, pythonArch); + if (selected.exitCode !== 0) { + throw new Error( + `Failed to set Python architecture to ${pythonArch}: ${selected.stderr.trim() || `uv exited with code ${selected.exitCode}`}` + ); + } + if (exportPythonArch) { + exportVariable("UV_PYTHON_ARCH", pythonArch); + info2(`Set UV_PYTHON_ARCH to ${pythonArch}`); + } +} +async function queryPythonArch(uvPath, pythonArch) { + try { + const { stderr } = await execFileAsync( + uvPath, + ["--no-config", "cache", "dir"], + { + encoding: "utf8", + env: { ...process.env, NO_COLOR: "1", UV_PYTHON_ARCH: pythonArch } + } + ); + return { exitCode: 0, stderr }; + } catch (error2) { + if (error2 instanceof Error && "code" in error2 && typeof error2.code === "number" && "stderr" in error2 && typeof error2.stderr === "string") { + return { exitCode: error2.code, stderr: error2.stderr }; + } + throw error2; + } +} + +// src/utils/python-runtime.ts +var import_node_child_process2 = require("node:child_process"); +var import_node_util5 = require("node:util"); +var execFileAsync2 = (0, import_node_util5.promisify)(import_node_child_process2.execFile); async function getPythonRuntimeId(inputs) { if (!inputs.activateEnvironment) { return ""; } try { - const { stdout } = await execFileAsync( + const { stdout } = await execFileAsync2( "uv", [ "python", @@ -122501,6 +122559,11 @@ async function run() { throw new Error(`Unsupported architecture: ${process.arch}`); } const setupResult = await setupUv(inputs, platform2, arch3); + const uvPath = path17.join( + setupResult.uvDir, + process.platform === "win32" ? "uv.exe" : "uv" + ); + await setupPythonArch(uvPath, inputs.pythonArch, inputs.exportPythonArch); addToolBinToPath(inputs); addUvToPathAndOutput(setupResult.uvDir); setToolDir(inputs); diff --git a/docs/caching.md b/docs/caching.md index 8d7011e..24d2635 100644 --- a/docs/caching.md +++ b/docs/caching.md @@ -11,6 +11,7 @@ The cache key is automatically generated based on: `pc-windows-msvc`) - **OS version**: OS name and version (e.g., `ubuntu-22.04`, `macos-14`, `windows-2022`) - **Python version**: The Python version in use +- **Python architecture**: The architecture selected by `python-arch` or `UV_PYTHON_ARCH`, when set - **Cache options**: Whether pruning and Python caching are enabled - **Dependency hash**: Hash of files matching `cache-dependency-glob` - **Suffix**: Optional `cache-suffix` if provided diff --git a/docs/environment-and-tools.md b/docs/environment-and-tools.md index 3565083..973a7de 100644 --- a/docs/environment-and-tools.md +++ b/docs/environment-and-tools.md @@ -144,6 +144,7 @@ If you want to ignore this, set the `ignore-empty-workdir` input to `true`. This action sets several environment variables that influence uv's behavior and can be used by subsequent steps: - `UV_PYTHON`: Set when `python-version` is specified or the selected `.tool-versions` file contains a supported `python` entry. Controls which Python version uv uses. +- `UV_PYTHON_ARCH`: Set when `python-arch` is specified. Controls the architecture of Python requests that do not specify one. - `UV_CACHE_DIR`: Set when caching is enabled (unless already configured in uv config files). Controls where uv stores its cache. - `UV_TOOL_DIR`: Set when `tool-dir` input is specified. Controls where uv installs tool environments. - `UV_TOOL_BIN_DIR`: Set when `tool-bin-dir` input is specified. Controls where uv installs tool binaries. @@ -155,6 +156,7 @@ This action sets several environment variables that influence uv's behavior and - `UV_NO_MODIFY_PATH`: If set, prevents the action from modifying PATH. Cannot be used with `activate-environment`. - `UV_CACHE_DIR`: If already set, the action will respect it instead of setting its own cache directory. - `UV_PYTHON`: If already set and `python-version` is not specified, the action will respect it instead of using the `python` entry from `.tool-versions`. +- `UV_PYTHON_ARCH`: If already set and `python-arch` is not specified, the action will use it and include it in the cache key. Requires a uv version that supports `UV_PYTHON_ARCH`. ```yaml - name: Example using environment variables diff --git a/package-lock.json b/package-lock.json index 89efaee..35f5ae6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "setup-uv", + "name": "@step-security/setup-uv", "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "setup-uv", + "name": "@step-security/setup-uv", "version": "1.0.0", "license": "MIT", "dependencies": { @@ -33,7 +33,8 @@ "typescript": "^6.0.3" }, "engines": { - "npm": ">=11.10.0" + "node": ">=24", + "npm": ">=11" } }, "node_modules/@actions/cache": { diff --git a/package.json b/package.json index 8933425..3c1eaea 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { - "name": "setup-uv", + "name": "@step-security/setup-uv", "version": "1.0.0", "private": true, "type": "module", "description": "Set up your GitHub Actions workflow with a specific version of uv", "main": "dist/setup/index.cjs", "engines": { - "npm": ">=11.10.0" + "npm": ">=11", + "node": ">=24" }, "devEngines": { "packageManager": { @@ -36,6 +37,7 @@ "uv" ], "author": "step-security", + "publisher": "step-security", "license": "MIT", "dependencies": { "@actions/cache": "^6.2.0", @@ -60,5 +62,9 @@ "js-yaml": "^5.3.0", "ts-jest": "^29.4.11", "typescript": "^6.0.3" + }, + "homepage": "https://github.com/step-security/setup-uv#readme", + "bugs": { + "url": "https://github.com/step-security/setup-uv/issues" } } diff --git a/src/cache/restore-cache.ts b/src/cache/restore-cache.ts index b5fec8f..e803e10 100644 --- a/src/cache/restore-cache.ts +++ b/src/cache/restore-cache.ts @@ -98,11 +98,14 @@ async function computeKeys( ? `-${encodeURIComponent(inputs.cacheSuffix)}` : ""; const version = encodeURIComponent(pythonVersion ?? "unknown"); + const pythonArchKey = inputs.pythonArch + ? `-python-${encodeURIComponent(inputs.pythonArch)}` + : ""; const platform = await getPlatform(); const osNameVersion = getOSNameVersion(); const pruned = inputs.pruneCache ? "-pruned" : ""; const python = inputs.cachePython ? "-py" : ""; - return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${osNameVersion}-${version}${pruned}${python}${cacheDependencyPathHash}${suffix}`; + return `setup-uv-${CACHE_VERSION}-${getArch()}-${platform}-${osNameVersion}-${version}${pythonArchKey}${pruned}${python}${cacheDependencyPathHash}${suffix}`; } function handleMatchResult( diff --git a/src/download/checksum/known-checksums.json b/src/download/checksum/known-checksums.json index b0b9dfe..d589df9 100644 --- a/src/download/checksum/known-checksums.json +++ b/src/download/checksum/known-checksums.json @@ -1,4 +1,148 @@ { + "aarch64-apple-darwin-0.13.0": "a9c1b29002cf3c83f07fa9cd8a887a3be0107d90e23189721221e7257db8e3d6", + "aarch64-pc-windows-msvc-0.13.0": "cb54028b59aa87f11cf6dec293ce000420043a49a8aea522e822a671321f8932", + "aarch64-unknown-linux-gnu-0.13.0": "3ccfb6af6e242433eb552f7d9676abd5412c6595c497e990d9c8cb7b5bd4d2c3", + "aarch64-unknown-linux-musl-0.13.0": "281ca6cf43f4e26e35474839ad4861be86de42af2682f74134460f5b2071b96d", + "arm-unknown-linux-musleabihf-0.13.0": "3f981753e12b6fcf705e05fe00bfe41366c5b5c260ebcea76965821dfc8f6c94", + "armv7-unknown-linux-gnueabihf-0.13.0": "e38957791fdd56d356421d81a509b66680d47478870082519340361e5abdbb8b", + "armv7-unknown-linux-musleabihf-0.13.0": "8c4e1f37dfcafa8244f0e8f1cd38f1ee597e5091c6e21a60fdd674987f69f8a2", + "i686-pc-windows-msvc-0.13.0": "5fca2da976672231e3dcc1d81bb1059781dea3915715fe8f000a916886d183cb", + "i686-unknown-linux-gnu-0.13.0": "4ee76d4f81003f04a1aeb6c743330d41a45054f2c69ceee4afdd129dd2786f88", + "i686-unknown-linux-musl-0.13.0": "fd9fe1435115fc62fda26cac28b024998d2af39f093f107ef51692d8e24ac7b4", + "powerpc64le-unknown-linux-gnu-0.13.0": "2fac854f1249968b91cd3bd6a089faf4cf7f896e407b9e1b3bc03ea0f0373989", + "riscv64gc-unknown-linux-gnu-0.13.0": "90f660b61ffb8cefae7a60e1b5915ab3eb828266f6d4593279440f735dcded63", + "riscv64gc-unknown-linux-musl-0.13.0": "6bfb5a8f9dce279e12f3ce1b57bef1a51b62ceb1de2c6233b61617883f23d56d", + "s390x-unknown-linux-gnu-0.13.0": "7b7b733e9b44eb0d1f5f6275672653c08f5abe2dd930acdc64123d5c69593132", + "x86_64-apple-darwin-0.13.0": "5f44dcbde809b632f47c36fadb241cb4d6f9af71d0c8f172b5d2026d3dde742c", + "x86_64-pc-windows-msvc-0.13.0": "088962f9e7b7bd9ea740c04c650b2a21c8928c345bd99ac24350dc924dba656c", + "x86_64-unknown-linux-gnu-0.13.0": "1468ebd5a5541121837c5a2817b9972ba6090fa6caa3d142620850a47fb75154", + "x86_64-unknown-linux-musl-0.13.0": "b0828fc4cdc47d65951e94b5f0a15a5364420e8dcd88723f3b21e7a2eb30bbc3", + "aarch64-apple-darwin-0.12.24": "0c4346de7abdb49495b393b9ec809fe387aa43e586be20fecb972216c1e71732", + "aarch64-pc-windows-msvc-0.12.24": "4b783bda5cc44bbae0651a837223873a7acee31152381aef5fc86ef6bef25997", + "aarch64-unknown-linux-gnu-0.12.24": "5231be65f496304623895dacdbf1de8504fec90303684bdf05805aa34414dd21", + "aarch64-unknown-linux-musl-0.12.24": "7f9ab4726d743b6a92e310477a7840c8a8a7b3938cb3c4657d541342fca75011", + "arm-unknown-linux-musleabihf-0.12.24": "c134b64ba9d6e760625ff9239708dffaeb67b612ebb47a774470bd88fac32084", + "armv7-unknown-linux-gnueabihf-0.12.24": "7ae5772338fb28f33052c06f82d1acb245df7bc1cb7628184a9baf91e9a101cd", + "armv7-unknown-linux-musleabihf-0.12.24": "fe46d0ad949c2901be0ead471109cfed57a082d4ff037cf64d7c7c65e910cdf2", + "i686-pc-windows-msvc-0.12.24": "752eda106495f96849951831a419f63796a01dc73ce5ab3cae6d48239527a06e", + "i686-unknown-linux-gnu-0.12.24": "89dde6d09ef1ae1e548b78c035ee75d0e2127b6c3991e0754651021c57110296", + "i686-unknown-linux-musl-0.12.24": "1d86de046c8be1ed1d7ea383f52469056145ee86a57fb11db5a51b4446d3d365", + "powerpc64le-unknown-linux-gnu-0.12.24": "897c61e780aded8062c9011f009b5d2971891b7e97df013c2ae10fca6fd41425", + "riscv64gc-unknown-linux-gnu-0.12.24": "c7789e1b3575c4c5a95a73ce280cd7335e4e1d8bf2aa90c606e33c5e3625d2e5", + "riscv64gc-unknown-linux-musl-0.12.24": "1adf83ae63acc09d7bd4926f6a1a0d26f819df6972635c0e57aa29d21e1d9797", + "s390x-unknown-linux-gnu-0.12.24": "9d2863b384a60f1c44c3e642226d1ffa97c0e6275cbb41f83aa2cdd764f8397c", + "x86_64-apple-darwin-0.12.24": "4fa82e37cb94767661f532b001e470b67a186c7260e305bd84ddb78fd545c0b6", + "x86_64-pc-windows-msvc-0.12.24": "7c38608c8a18ee137d748a1773053b07ec8f3a30fab49aebaa6f4e4efeceb019", + "x86_64-unknown-linux-gnu-0.12.24": "b4dfaef47d491a7296981f8374a4595f55dbf84e8937c8ecd2983574d8bb3da6", + "x86_64-unknown-linux-musl-0.12.24": "48170bd200a5430298c18f3b264485a1f3a8605f01088277daf6e37633edf0f5", + "aarch64-apple-darwin-0.12.23": "50487ae565ccd96e499056b4674d438f4c53170202617b4c759defe0c6a1b544", + "aarch64-pc-windows-msvc-0.12.23": "13294e232ececbe709c06b74e6ced06f2a225ea5591476685362f22be56a50d5", + "aarch64-unknown-linux-gnu-0.12.23": "6524bd338177ed50d035d39354e12545e993bbeba2ecbddf0480c5b3a81d313f", + "aarch64-unknown-linux-musl-0.12.23": "b536543cc4d50661986b165c76ee8aa9056e4fa332edcd153ff2e98760f9359b", + "arm-unknown-linux-musleabihf-0.12.23": "7184501c712c58abc9554e1f4fcc9bacc042ad28e1ad0f42e762a1ed27a151c5", + "armv7-unknown-linux-gnueabihf-0.12.23": "4d568920e1f60c4b881cbe2827dfa20592a9a9721f69b57d47650d035c4fe8f6", + "armv7-unknown-linux-musleabihf-0.12.23": "f5c941f2a7fa078ffcbc58654ec1b37de98e2a93a24cd3deb19c1acdd66ff533", + "i686-pc-windows-msvc-0.12.23": "22a92f4374e4716c2848acaa0392f2f8e4a13b0ff65d080e2a5ade167bce96a8", + "i686-unknown-linux-gnu-0.12.23": "52c93c40f6056c4d0e1e259acd60c11f7328416a4f28c85e5f1b04430538aeaa", + "i686-unknown-linux-musl-0.12.23": "b3838649e6896734be828e96c6b14f3064882508a7211398c0e3a35f974f501b", + "powerpc64le-unknown-linux-gnu-0.12.23": "e8e13421bdecb3f31c0794edfcb8b2e04406f34d645fd9c040f7bd9ace5c3f72", + "riscv64gc-unknown-linux-gnu-0.12.23": "661c1a11afc8db4adb20b2d30f789b50e682529b0f1f49e3dd138d86581065b3", + "riscv64gc-unknown-linux-musl-0.12.23": "d6dcc450fe1c159540115c8934c76515ee03192c9e61cb983228ad3809e1cc71", + "s390x-unknown-linux-gnu-0.12.23": "50c726711cb5f4cdbf45e31c141c9033fdd43146f90ac630c252857c60daf84b", + "x86_64-apple-darwin-0.12.23": "960da44cb4b73685206ddd250b19e0a117fa41095710c1038f081f5cb613efb4", + "x86_64-pc-windows-msvc-0.12.23": "75d05de6762778c31ee183398de7dd15093fad0ed90b1f236d8205ea5ec00c90", + "x86_64-unknown-linux-gnu-0.12.23": "9167d72b3319674b6303c4cbe071854bba13ebdf3d76b1a7cbdc175471fb66d6", + "x86_64-unknown-linux-musl-0.12.23": "1cff8783850e794470aadb73f54b749542a511fc57b0ce6468b64bd3852e0ade", + "aarch64-apple-darwin-0.12.22": "5d714de09501a59393ceca78f4bc232a50478729640d251907160299b2a93ddd", + "aarch64-pc-windows-msvc-0.12.22": "6a42b919c2bb7135f07b4d1bb8e489f0eaab0bae039020573cc522d831e2d32e", + "aarch64-unknown-linux-gnu-0.12.22": "6f66a14e8239871fb477f9746c941fedfa77e8fe28a8bc7c07e1dc7f53a66712", + "aarch64-unknown-linux-musl-0.12.22": "228bd32c180421a94eef91378a92b2dd63c768bd278430e833250524c4a13382", + "arm-unknown-linux-musleabihf-0.12.22": "e7df01f0b9cfec6a82232e0de063cb961e38e4e1a9767295bdee87e148f6dde0", + "armv7-unknown-linux-gnueabihf-0.12.22": "ec4d636bce8cc4d2ff0a927f2805671e2d7377e3f3f7b42109d5d4633839fa41", + "armv7-unknown-linux-musleabihf-0.12.22": "5f5ea3f80f8ffa47aa47fb8f59b5589eb3619c05ffe7730d8554ead42720f742", + "i686-pc-windows-msvc-0.12.22": "a18a913fe4435e5591113ff035077d9461177ad03ab2747eaeb88aee95833a16", + "i686-unknown-linux-gnu-0.12.22": "221bbc2362b7cbf651e3fbb0a228c034820bb07f9efe2785c9339828fcdf079b", + "i686-unknown-linux-musl-0.12.22": "50dadb6a043359f4762e338691306109ca1df3d3312460a926642dbf8c9f527c", + "powerpc64le-unknown-linux-gnu-0.12.22": "17b959094cffb2fd3c3fb9c64d98a1ea8eabfd0bc83507ab08e4ca2187302d1c", + "riscv64gc-unknown-linux-gnu-0.12.22": "f25202c8647b4a783b0f04e2c341c617d8d11a8bc72d4ccdcbcc6f0c9d7782f2", + "riscv64gc-unknown-linux-musl-0.12.22": "30b29481b4dd28a8cc9d903b66dbe9532781bd25de817fcd9ea5fd37598ef171", + "s390x-unknown-linux-gnu-0.12.22": "3672ce2d278239cbc52ba0c962f21556cd49f889a87577ea0801ad7eadc0be73", + "x86_64-apple-darwin-0.12.22": "1b8a5b316883df2daf20fb9a446e5b230e01d947d57aba2694977c5ac5a7e98c", + "x86_64-pc-windows-msvc-0.12.22": "ea1397797a0ca15f63516dd0f49c2dde9776db9be5861cab152ebe8ad199894d", + "x86_64-unknown-linux-gnu-0.12.22": "b9980552309f09c15172b8be828555e375097f16deb459795ce7bfd200380f0b", + "x86_64-unknown-linux-musl-0.12.22": "a50fd68c653b0cfb1c85e0a7db62cb78cf5c22b6f3dcf3ae173e5f222d084470", + "aarch64-apple-darwin-0.12.21": "b88bda573e566ef9bced66b155fe0408626fbbc053aee1c30ba686f0728c9447", + "aarch64-pc-windows-msvc-0.12.21": "93ed53b94e9cec000cacdfd18ca67bc4cb2b6a5f5ec041edd7f2a3dae365ce79", + "aarch64-unknown-linux-gnu-0.12.21": "030b69227b40af8c1981b7301793dc66e71ed3c796ea8688209dd268bd91ec51", + "aarch64-unknown-linux-musl-0.12.21": "67389a674e62adffa5a395d9a3b80688731c4aa7b33a6def3e62d00f7fec821f", + "arm-unknown-linux-musleabihf-0.12.21": "047c43febfaabcf06f6e20361bf99a4fd57b9c391a99e0bff2d410dd647829a6", + "armv7-unknown-linux-gnueabihf-0.12.21": "ddb4826a23a9a994da3d868c57b74b1fcb22e29691fc89f8b1702c6a1a9e0df7", + "armv7-unknown-linux-musleabihf-0.12.21": "eeb8edc4e5b74ec4521da4d3911153ba8ce24ed8557e2dbbe55d04a6d7a7f45e", + "i686-pc-windows-msvc-0.12.21": "66b7ffe136362b8522748c4d43b7e82b846e37e4e9272fcfadffaad8bf7b5a75", + "i686-unknown-linux-gnu-0.12.21": "b9ff98d9e6303f8d403af3f002ff1a429867cfcf915f1fa296689b43d9defd52", + "i686-unknown-linux-musl-0.12.21": "1492353034d106f2067eeec8f8b6aad1354e13fbb3f91c25a40eb5d44215fd6f", + "powerpc64le-unknown-linux-gnu-0.12.21": "c76a8589ed7f447d1e14dc20f060861fecd457a44a287047ef6a49bc6f22ae25", + "riscv64gc-unknown-linux-gnu-0.12.21": "202b30dff0f35cd8094e97949c8694b31951f404dd99802e1c997d65d752cf58", + "riscv64gc-unknown-linux-musl-0.12.21": "ca1dcb18c0e81c31d006d1ab808fcb4e3a95dde780b1e58805039f84a8ae0b2d", + "s390x-unknown-linux-gnu-0.12.21": "556bd11fca37f43a5ec051b5ed82e64b54fe536d6dea2fa84f8b34d2eb3a77d0", + "x86_64-apple-darwin-0.12.21": "2b336763b396ec6afa20c5a8b083538ca7402445b868311979d740a4344c17d8", + "x86_64-pc-windows-msvc-0.12.21": "5d223efa0bf00208c3853246af09420419dfbd352536aa6bb8163d6170e23890", + "x86_64-unknown-linux-gnu-0.12.21": "23f02075b652bb1df64178cfae41b5caf160822e720e2663568f3f5d63bc52c0", + "x86_64-unknown-linux-musl-0.12.21": "d69d543a55ec9cdf9d3d9f2648b0a161847e3dbddc477e3be6b5813a6d46f639", + "aarch64-apple-darwin-0.12.20": "848fdeb602ff1a1baacd4f6c8b7bdc6cf1ad026a6d9cf59475fda17c179743ca", + "aarch64-pc-windows-msvc-0.12.20": "b6bd9218855591742ffd3b00fcf2044b4d2fb6446b6a3545e0dfee447e950388", + "aarch64-unknown-linux-gnu-0.12.20": "8a7aad7bc76a2fae5151566ff3e43eacce0b2a113d5e4de3e4afe3e58fa2441e", + "aarch64-unknown-linux-musl-0.12.20": "94bb13feeebc6b59a4124016c957cdc9ee406d1476ce2b2ce2991e95b8e820b7", + "arm-unknown-linux-musleabihf-0.12.20": "6aeef64cf07b43135d6b1c20bd57809f2d965d0f8a2d5602230d5d55b8245477", + "armv7-unknown-linux-gnueabihf-0.12.20": "e1c53318608448ad3b8e7f2e9b069936730a6e7b47831ba5446e4b4f436ee715", + "armv7-unknown-linux-musleabihf-0.12.20": "a4c3a0e12e5489f092c93b232ddc4a811a6ea9a03f447f91f88e96867c0bac8d", + "i686-pc-windows-msvc-0.12.20": "1a372c273370ae9a7e9aa84020ce91fc1d9ebecbd287c3447e7e99cada0b14f3", + "i686-unknown-linux-gnu-0.12.20": "f1e83cc88970ed799b507a8392152d19916dfa0b6c9ae9c8145742035a40d5cb", + "i686-unknown-linux-musl-0.12.20": "11d541dd32dd779adbdfef69fe30d7d325036f50d394d3f260a0042998e05499", + "powerpc64le-unknown-linux-gnu-0.12.20": "39224a5bfc21a8041afc0315e5d47c86acecf4e669944564950996b516fb5987", + "riscv64gc-unknown-linux-gnu-0.12.20": "5cb9df36ca64fb72673c59a77b955b50f3bb907689a98d1d8d640aa3e71f2660", + "riscv64gc-unknown-linux-musl-0.12.20": "360e91a317a27bd33978577c57b6f3ed778bdfe8c30c9b613e46fdc33bf8aee8", + "s390x-unknown-linux-gnu-0.12.20": "25485439b52cb029afa724c442418ca08a53122100f8cce68ccceb88323ccde2", + "x86_64-apple-darwin-0.12.20": "ac54283d211fd77cdc152b67606dbaf6406ff4ab03f3af4ae99468fa8e887141", + "x86_64-pc-windows-msvc-0.12.20": "95f9bc30fbb3574d276e28ac4a6de932d25153645853d13da8c21eec3bc88d06", + "x86_64-unknown-linux-gnu-0.12.20": "6590717592ace991ff83a63fef799e3ad9d33ecc8f96c5d6bdd732496e79337f", + "x86_64-unknown-linux-musl-0.12.20": "14114d66a094f1907af0fcbc863f34226bbb7f5e430e13dce6676ba40dcc6891", + "aarch64-apple-darwin-0.12.19": "a9a8df1eedeb192f2e47e40e2faabfb387db4b850209118786d42f89dde3e0ba", + "aarch64-pc-windows-msvc-0.12.19": "115b54cb823bc48260670f5782001add6067ac8d98d18c8263a833704e287de9", + "aarch64-unknown-linux-gnu-0.12.19": "0804e9b164c64b6914182d5920c08551958a095986f10a3731056df701126436", + "aarch64-unknown-linux-musl-0.12.19": "ad8d8448a2ff642ba62c2f684d7dd22a03f8eb3fc9918c2c3e8ec975f4ed6710", + "arm-unknown-linux-musleabihf-0.12.19": "173b6b118e444dc3b3a0b6337dd87d66fa79835aa5e059d79e942ae33a850e20", + "armv7-unknown-linux-gnueabihf-0.12.19": "f47fe74244c4adcff20637c1aee2550dbc31c81ccf0b2a9537bf98b24bc4028a", + "armv7-unknown-linux-musleabihf-0.12.19": "0df353aac087509c47fe660837ca5d284858ef4a5eec4042cbcdeb0118ba0f1b", + "i686-pc-windows-msvc-0.12.19": "e1c2d19d1173a0e9f81ba3f95881ad741808133e372610889ff6870629218c7f", + "i686-unknown-linux-gnu-0.12.19": "952b0bae707e19b2b5d012b46519a2159be929273d466a1437759f0961be0b93", + "i686-unknown-linux-musl-0.12.19": "f923ac32e0e5139950fe1b63abab74d48cabb94b15c90637bc380dadcaf4da40", + "powerpc64le-unknown-linux-gnu-0.12.19": "e30649ad846a14bd96440efd45fdb60dcdf8db088fb143064aa78632048ad957", + "riscv64gc-unknown-linux-gnu-0.12.19": "50a83ea999ea861a6a853ae1ad0982baad96cc6451e46a5d7e366c4d9475f1bb", + "riscv64gc-unknown-linux-musl-0.12.19": "051de9eda7e09dab4c8a304ab2e119317649fee0e24efd0358f410d0c5b3407f", + "s390x-unknown-linux-gnu-0.12.19": "e6a9149ea122c1b3b9719ca3577c321376e3c400e004c3cc18231fdb1d35107b", + "x86_64-apple-darwin-0.12.19": "cb5fa57bafe68fc0fb94b17f06bee0b0b9a7feb94ccbd110445afa0696e39273", + "x86_64-pc-windows-msvc-0.12.19": "6dbb02d79e419522f1c500f0adb1cddcff0cda7d59b0d66ea7f5e3b4a1b2f5f0", + "x86_64-unknown-linux-gnu-0.12.19": "23bf5552d220e0842b65c862097b2ebaeba0064b74eda5e565e77fd25969d8c8", + "x86_64-unknown-linux-musl-0.12.19": "db7278c9f57981338fddff1fb250e11964bc0a4fafcb9eed8303fdb117dc067b", + "aarch64-apple-darwin-0.12.18": "cf40e0c6a202190ccd9e0406dcfdd5b2d6668a9a5c779b17948963df32aafe5b", + "aarch64-pc-windows-msvc-0.12.18": "17f27b1c64eacc757ae603579f116a014881e486c5e79ae81877980d4699e943", + "aarch64-unknown-linux-gnu-0.12.18": "afb6291f3f0a6b4521fc67b947822506c41dde5b60d2189dd8f3695b2ac8c9e7", + "aarch64-unknown-linux-musl-0.12.18": "0796973fb3eea8095078c3d0659bd17a5f6789a71b8dd85caff2483178f78ac3", + "arm-unknown-linux-musleabihf-0.12.18": "a37127fb331d5e6228efc1f8549d2447b50c907eee4629347f150a649083619c", + "armv7-unknown-linux-gnueabihf-0.12.18": "a38e82350e1e95d5526d1ab81d9b4eb676815c51646243b3b3fbc55b218732d1", + "armv7-unknown-linux-musleabihf-0.12.18": "41f0808328f65910bacdb487638475715f949900c7a23b393b3754e2156ff15a", + "i686-pc-windows-msvc-0.12.18": "e04c0f1fd9a8703761f9edd64d797ddb2c9a3e6eec0e2fed234a7bd2c2e868b9", + "i686-unknown-linux-gnu-0.12.18": "278dbc5dfc6bdde33a553fdba53174cc49daf512a857db1b3c1b5d663290196f", + "i686-unknown-linux-musl-0.12.18": "ebfdaaafc447fb2a7329cde879a7748b2ab40ecdcd3d5f04fc0a5d1ab79bb0bd", + "powerpc64le-unknown-linux-gnu-0.12.18": "332d174248230ed599a9df0e4e77d6921dbb42ca0fdfbe26eb2a6c999da936b3", + "riscv64gc-unknown-linux-gnu-0.12.18": "be88652a03225acbd6bf7204d006b244b0743c8c756a35137c209fa4ff731c41", + "riscv64gc-unknown-linux-musl-0.12.18": "29d34dcc833b99b09f78fa11c66fa3c490c3e37c4f0d754e7b84f7147850190e", + "s390x-unknown-linux-gnu-0.12.18": "ac412f7ab2a096a7302e0ae8828c7ef84db8a1f7ff97acba8ff8987d46d39cec", + "x86_64-apple-darwin-0.12.18": "2e4108f5395397c8bc5d43bf83d3bdbb2d0e92b90d0efa607756be704905fa33", + "x86_64-pc-windows-msvc-0.12.18": "cae6a3bc25239f83dffb467a4b180508d9da23986c04639ebfa44e43e6a84bff", + "x86_64-unknown-linux-gnu-0.12.18": "89eadd7c76fc063887959510d5ba0ab1264dfd5f1143b925ddb73021a40acf16", + "x86_64-unknown-linux-musl-0.12.18": "e38d97460b98ebfd31b197de0fe9fa578add4bc8ba0179b203dd3f87b99f98e6", "aarch64-apple-darwin-0.12.17": "85f00cbdc6dd3e97eba4c31b4d014375a9fdfe8f570023b84e5102fc3456896b", "aarch64-pc-windows-msvc-0.12.17": "3e1aa6849d77f0e00dc865e4afab5c5b32de053e21fe35bf5ad5cec3734ec976", "aarch64-unknown-linux-gnu-0.12.17": "d636d1b678e9e7f367ecb22b46bd1cabbed234d6bc3b4d96365d2b507f72f86c", diff --git a/src/setup-uv.ts b/src/setup-uv.ts index ec17846..330af82 100644 --- a/src/setup-uv.ts +++ b/src/setup-uv.ts @@ -16,6 +16,7 @@ import { getPlatform, type Platform, } from "./utils/platforms"; +import { setupPythonArch } from "./utils/python-arch"; import { getPythonRuntimeId } from "./utils/python-runtime"; import { validateSubscription } from "./utils/subscription"; import { resolveUvVersion } from "./version/resolve"; @@ -88,6 +89,11 @@ async function run(): Promise { throw new Error(`Unsupported architecture: ${process.arch}`); } const setupResult = await setupUv(inputs, platform, arch); + const uvPath = path.join( + setupResult.uvDir, + process.platform === "win32" ? "uv.exe" : "uv", + ); + await setupPythonArch(uvPath, inputs.pythonArch, inputs.exportPythonArch); addToolBinToPath(inputs); addUvToPathAndOutput(setupResult.uvDir); diff --git a/src/utils/inputs.ts b/src/utils/inputs.ts index 62ddfc2..c342a2b 100644 --- a/src/utils/inputs.ts +++ b/src/utils/inputs.ts @@ -24,6 +24,8 @@ export interface SetupInputs { version: string; versionFile: string; pythonVersion: string; + pythonArch: string; + exportPythonArch: boolean; activateEnvironment: boolean; noProject: boolean; venvPath: string; @@ -54,6 +56,9 @@ export function loadInputs(): SetupInputs { const version = core.getInput("version"); const versionFile = getVersionFile(workingDirectory); const pythonVersion = getPythonVersion(versionFile); + const pythonArchInput = core.getInput("python-arch"); + const pythonArch = pythonArchInput || process.env.UV_PYTHON_ARCH || ""; + const exportPythonArch = pythonArchInput !== ""; const activateEnvironment = core.getBooleanInput("activate-environment"); const noProject = core.getBooleanInput("no-project"); const venvPath = getVenvPath(workingDirectory, activateEnvironment); @@ -94,12 +99,14 @@ export function loadInputs(): SetupInputs { checksum, downloadFromAstralMirror, enableCache, + exportPythonArch, githubToken, ignoreEmptyWorkdir, ignoreNothingToCache, manifestFile, noProject, pruneCache, + pythonArch, pythonDir, pythonVersion, quiet, diff --git a/src/utils/python-arch.ts b/src/utils/python-arch.ts new file mode 100644 index 0000000..da8dd85 --- /dev/null +++ b/src/utils/python-arch.ts @@ -0,0 +1,75 @@ +import { execFile } from "node:child_process"; +import { promisify } from "node:util"; +import * as core from "@actions/core"; +import * as log from "./logging"; + +const execFileAsync = promisify(execFile); +const PROBE_ARCH = "setup-uv-probe"; + +export async function setupPythonArch( + uvPath: string, + pythonArch: string, + exportPythonArch: boolean, +): Promise { + if (pythonArch === "") { + return; + } + + // Older uv releases ignore unknown environment variables. An invalid architecture + // confirms that uv recognizes UV_PYTHON_ARCH without finding or downloading Python. + const probe = await queryPythonArch(uvPath, PROBE_ARCH); + if (probe.exitCode === 0) { + throw new Error( + "The installed version of uv does not support UV_PYTHON_ARCH. Select a newer uv version or use an architecture-qualified python-version.", + ); + } + if ( + !probe.stderr.includes( + `environment variable \`UV_PYTHON_ARCH\` with invalid value \`${PROBE_ARCH}\``, + ) + ) { + throw new Error( + `Failed to check uv's support for UV_PYTHON_ARCH: ${probe.stderr.trim() || `uv exited with code ${probe.exitCode}`}`, + ); + } + + const selected = await queryPythonArch(uvPath, pythonArch); + if (selected.exitCode !== 0) { + throw new Error( + `Failed to set Python architecture to ${pythonArch}: ${selected.stderr.trim() || `uv exited with code ${selected.exitCode}`}`, + ); + } + + if (exportPythonArch) { + core.exportVariable("UV_PYTHON_ARCH", pythonArch); + log.info(`Set UV_PYTHON_ARCH to ${pythonArch}`); + } +} + +async function queryPythonArch( + uvPath: string, + pythonArch: string, +): Promise<{ exitCode: number; stderr: string }> { + try { + const { stderr } = await execFileAsync( + uvPath, + ["--no-config", "cache", "dir"], + { + encoding: "utf8", + env: { ...process.env, NO_COLOR: "1", UV_PYTHON_ARCH: pythonArch }, + }, + ); + return { exitCode: 0, stderr }; + } catch (error) { + if ( + error instanceof Error && + "code" in error && + typeof error.code === "number" && + "stderr" in error && + typeof error.stderr === "string" + ) { + return { exitCode: error.code, stderr: error.stderr }; + } + throw error; + } +} From e509b5ba1dc680f3b72ac7d393ac7d73b6e4da05 Mon Sep 17 00:00:00 2001 From: Raj-StepSecurity Date: Mon, 19 Oct 2026 10:43:17 +0530 Subject: [PATCH 2/3] code linted --- config.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/config.json b/config.json index 7d10eef..d0d3c5f 100644 --- a/config.json +++ b/config.json @@ -1,17 +1,17 @@ { "$comment": "Managed automatically when syncing with upstream. Do not edit by hand.", - "schema_version": 1, - "onboarding_type": "copied", "action_type": "node", - "upstream": { - "repository": "astral-sh/setup-uv", - "synced_tag": "v10.3.0", - "synced_commit": "1c37ad07a6a961277cf70c0d37d6f313000f5884", - "archived": false - }, "build": { - "package_manager": "npm@11.12.1", "node_version": "24", + "package_manager": "npm@11.12.1", "script": "all" + }, + "onboarding_type": "copied", + "schema_version": 1, + "upstream": { + "archived": false, + "repository": "astral-sh/setup-uv", + "synced_commit": "1c37ad07a6a961277cf70c0d37d6f313000f5884", + "synced_tag": "v10.3.0" } } From 4d52150b2b07df3d354bff974ed1399e33fd395b Mon Sep 17 00:00:00 2001 From: Raj-StepSecurity Date: Mon, 19 Oct 2026 15:24:30 +0530 Subject: [PATCH 3/3] ci updated --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b1d8881..45ae95d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -48,7 +48,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: ${{ github.actor == 'dependabot[bot]' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "macos-14", "windows-latest"]') }} + os: ${{ github.actor == 'dependabot[bot]' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "macos-15", "windows-latest"]') }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0 @@ -377,7 +377,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: ${{ github.actor == 'dependabot[bot]' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "macos-14", "windows-latest"]') }} + os: ${{ github.actor == 'dependabot[bot]' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "macos-15", "windows-latest"]') }} steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0