mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-09-03 22:29:21 +00:00
Fail setup when activated Python runtime detection fails
This commit is contained in:
@@ -140,7 +140,7 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
||||
- `python-version`: The Python version that was set.
|
||||
- `python-runtime-id`: An opaque identifier for the activated venv's Python runtime, including
|
||||
implementation, full version, and free-threaded build information. Useful as a cache-key component.
|
||||
Empty when `activate-environment` is false or the runtime cannot be determined.
|
||||
Empty when `activate-environment` is false. The action fails if the activated runtime cannot be determined.
|
||||
- `python-cache-hit`: A boolean value to indicate the Python cache entry was found.
|
||||
|
||||
### Python version
|
||||
|
||||
@@ -7,14 +7,12 @@ const mockExecFile =
|
||||
jest.fn<
|
||||
(...args: unknown[]) => Promise<{ stdout: string; stderr: string }>
|
||||
>();
|
||||
const mockDebug = jest.fn();
|
||||
const originalPlatform = process.platform;
|
||||
const inputs = createSetupInputs({
|
||||
activateEnvironment: true,
|
||||
pythonVersion: "3.15t",
|
||||
});
|
||||
|
||||
jest.unstable_mockModule("@actions/core", () => ({ debug: mockDebug }));
|
||||
jest.unstable_mockModule("node:child_process", () => ({
|
||||
// execFile's custom promisifier returns both stdout and stderr.
|
||||
execFile: Object.assign(mockExecFile, { [promisify.custom]: mockExecFile }),
|
||||
@@ -70,16 +68,13 @@ it.each([
|
||||
["pypy", [7, 3, 24, "beta", 2], "pypy-7.3.24b2"],
|
||||
["pypy", [7, 3, 24, "candidate", 3], "pypy-7.3.24rc3"],
|
||||
["graalpy", [25, 0, 0, "final", 0], "graalpy-25.0.0"],
|
||||
["pypy", [7, 3, 24, "unknown", 0], ""],
|
||||
])("formats %s implementation version %j", async (name, version, expected) => {
|
||||
mockRuntime({
|
||||
implementation: name,
|
||||
implementationVersion: version,
|
||||
pythonVersion: "3.11.15",
|
||||
});
|
||||
expect(await getPythonRuntimeId(inputs)).toBe(
|
||||
expected ? `${expected}-python-3.11.15` : "",
|
||||
);
|
||||
expect(await getPythonRuntimeId(inputs)).toBe(`${expected}-python-3.11.15`);
|
||||
});
|
||||
|
||||
it.each([
|
||||
@@ -97,15 +92,25 @@ it.each([
|
||||
);
|
||||
});
|
||||
|
||||
it.each([new Error("interpreter missing"), "", "not JSON", "null", "{}"])(
|
||||
"returns an empty ID for interpreter failure: %s",
|
||||
async (result) => {
|
||||
if (result instanceof Error) {
|
||||
mockExecFile.mockRejectedValue(result);
|
||||
} else {
|
||||
mockExecFile.mockResolvedValue({ stderr: "", stdout: result });
|
||||
}
|
||||
expect(await getPythonRuntimeId(inputs)).toBe("");
|
||||
expect(mockDebug).toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
it.each([
|
||||
new Error("interpreter missing"),
|
||||
"",
|
||||
"not JSON",
|
||||
"null",
|
||||
"{}",
|
||||
JSON.stringify({
|
||||
freethreaded: false,
|
||||
implementation: "pypy",
|
||||
implementationVersion: [7, 3, 24, "unknown", 0],
|
||||
pythonVersion: "3.11.15",
|
||||
}),
|
||||
])("rejects interpreter failure or invalid metadata: %s", async (result) => {
|
||||
if (result instanceof Error) {
|
||||
mockExecFile.mockRejectedValue(result);
|
||||
} else {
|
||||
mockExecFile.mockResolvedValue({ stderr: "", stdout: result });
|
||||
}
|
||||
await expect(getPythonRuntimeId(inputs)).rejects.toThrow(
|
||||
"Failed to identify the activated environment's Python runtime:",
|
||||
);
|
||||
});
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ outputs:
|
||||
python-version:
|
||||
description: "The Python version that was set."
|
||||
python-runtime-id:
|
||||
description: "An opaque identifier for the activated venv's Python runtime, including implementation, full version, and free-threaded build information. Empty when activate-environment is false or the runtime cannot be determined."
|
||||
description: "An opaque identifier for the activated venv's Python runtime, including implementation, full version, and free-threaded build information. Empty when activate-environment is false. The action fails if the activated runtime cannot be determined."
|
||||
python-cache-hit:
|
||||
description: "A boolean value to indicate the Python cache entry was found"
|
||||
runs:
|
||||
|
||||
+3
-3
@@ -102116,10 +102116,10 @@ async function getPythonRuntimeId(inputs) {
|
||||
);
|
||||
return formatRuntimeId(JSON.parse(stdout));
|
||||
} catch (error2) {
|
||||
debug(
|
||||
`Failed to identify the activated environment's Python runtime. Error: ${error2 instanceof Error ? error2.message : String(error2)}`
|
||||
throw new Error(
|
||||
`Failed to identify the activated environment's Python runtime: ${error2 instanceof Error ? error2.message : String(error2)}`,
|
||||
{ cause: error2 }
|
||||
);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ key: build-${{ runner.os }}-${{ runner.arch }}-${{ steps.setup-uv.outputs.python
|
||||
```
|
||||
|
||||
The free-threaded marker describes the interpreter's build even when the GIL is
|
||||
enabled at runtime. The output is empty when `activate-environment` is false or the
|
||||
runtime cannot be determined. The existing `python-version` output and setup-uv's
|
||||
cache keys are unaffected.
|
||||
enabled at runtime. The output is empty when `activate-environment` is false. If
|
||||
the activated runtime cannot be determined, the action fails. The existing
|
||||
`python-version` output and setup-uv's cache keys are unaffected.
|
||||
|
||||
You can customize the venv location with `venv-path`, for example to place it in the runner temp directory:
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { execFile } from "node:child_process";
|
||||
import { join } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import * as core from "@actions/core";
|
||||
import type { SetupInputs } from "./inputs";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
@@ -79,9 +78,9 @@ export async function getPythonRuntimeId(inputs: SetupInputs): Promise<string> {
|
||||
);
|
||||
return formatRuntimeId(JSON.parse(stdout));
|
||||
} catch (error) {
|
||||
core.debug(
|
||||
`Failed to identify the activated environment's Python runtime. Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||
throw new Error(
|
||||
`Failed to identify the activated environment's Python runtime: ${error instanceof Error ? error.message : String(error)}`,
|
||||
{ cause: error },
|
||||
);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user