mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-09-04 06:39:22 +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-version`: The Python version that was set.
|
||||||
- `python-runtime-id`: An opaque identifier for the activated venv's Python runtime, including
|
- `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.
|
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-cache-hit`: A boolean value to indicate the Python cache entry was found.
|
||||||
|
|
||||||
### Python version
|
### Python version
|
||||||
|
|||||||
@@ -7,14 +7,12 @@ const mockExecFile =
|
|||||||
jest.fn<
|
jest.fn<
|
||||||
(...args: unknown[]) => Promise<{ stdout: string; stderr: string }>
|
(...args: unknown[]) => Promise<{ stdout: string; stderr: string }>
|
||||||
>();
|
>();
|
||||||
const mockDebug = jest.fn();
|
|
||||||
const originalPlatform = process.platform;
|
const originalPlatform = process.platform;
|
||||||
const inputs = createSetupInputs({
|
const inputs = createSetupInputs({
|
||||||
activateEnvironment: true,
|
activateEnvironment: true,
|
||||||
pythonVersion: "3.15t",
|
pythonVersion: "3.15t",
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.unstable_mockModule("@actions/core", () => ({ debug: mockDebug }));
|
|
||||||
jest.unstable_mockModule("node:child_process", () => ({
|
jest.unstable_mockModule("node:child_process", () => ({
|
||||||
// execFile's custom promisifier returns both stdout and stderr.
|
// execFile's custom promisifier returns both stdout and stderr.
|
||||||
execFile: Object.assign(mockExecFile, { [promisify.custom]: mockExecFile }),
|
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, "beta", 2], "pypy-7.3.24b2"],
|
||||||
["pypy", [7, 3, 24, "candidate", 3], "pypy-7.3.24rc3"],
|
["pypy", [7, 3, 24, "candidate", 3], "pypy-7.3.24rc3"],
|
||||||
["graalpy", [25, 0, 0, "final", 0], "graalpy-25.0.0"],
|
["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) => {
|
])("formats %s implementation version %j", async (name, version, expected) => {
|
||||||
mockRuntime({
|
mockRuntime({
|
||||||
implementation: name,
|
implementation: name,
|
||||||
implementationVersion: version,
|
implementationVersion: version,
|
||||||
pythonVersion: "3.11.15",
|
pythonVersion: "3.11.15",
|
||||||
});
|
});
|
||||||
expect(await getPythonRuntimeId(inputs)).toBe(
|
expect(await getPythonRuntimeId(inputs)).toBe(`${expected}-python-3.11.15`);
|
||||||
expected ? `${expected}-python-3.11.15` : "",
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
@@ -97,15 +92,25 @@ it.each([
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([new Error("interpreter missing"), "", "not JSON", "null", "{}"])(
|
it.each([
|
||||||
"returns an empty ID for interpreter failure: %s",
|
new Error("interpreter missing"),
|
||||||
async (result) => {
|
"",
|
||||||
if (result instanceof Error) {
|
"not JSON",
|
||||||
mockExecFile.mockRejectedValue(result);
|
"null",
|
||||||
} else {
|
"{}",
|
||||||
mockExecFile.mockResolvedValue({ stderr: "", stdout: result });
|
JSON.stringify({
|
||||||
}
|
freethreaded: false,
|
||||||
expect(await getPythonRuntimeId(inputs)).toBe("");
|
implementation: "pypy",
|
||||||
expect(mockDebug).toHaveBeenCalled();
|
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:
|
python-version:
|
||||||
description: "The Python version that was set."
|
description: "The Python version that was set."
|
||||||
python-runtime-id:
|
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:
|
python-cache-hit:
|
||||||
description: "A boolean value to indicate the Python cache entry was found"
|
description: "A boolean value to indicate the Python cache entry was found"
|
||||||
runs:
|
runs:
|
||||||
|
|||||||
+3
-3
@@ -102116,10 +102116,10 @@ async function getPythonRuntimeId(inputs) {
|
|||||||
);
|
);
|
||||||
return formatRuntimeId(JSON.parse(stdout));
|
return formatRuntimeId(JSON.parse(stdout));
|
||||||
} catch (error2) {
|
} catch (error2) {
|
||||||
debug(
|
throw new Error(
|
||||||
`Failed to identify the activated environment's Python runtime. Error: ${error2 instanceof Error ? error2.message : String(error2)}`
|
`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
|
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
|
enabled at runtime. The output is empty when `activate-environment` is false. If
|
||||||
runtime cannot be determined. The existing `python-version` output and setup-uv's
|
the activated runtime cannot be determined, the action fails. The existing
|
||||||
cache keys are unaffected.
|
`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:
|
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 { execFile } from "node:child_process";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import * as core from "@actions/core";
|
|
||||||
import type { SetupInputs } from "./inputs";
|
import type { SetupInputs } from "./inputs";
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
@@ -79,9 +78,9 @@ export async function getPythonRuntimeId(inputs: SetupInputs): Promise<string> {
|
|||||||
);
|
);
|
||||||
return formatRuntimeId(JSON.parse(stdout));
|
return formatRuntimeId(JSON.parse(stdout));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.debug(
|
throw new Error(
|
||||||
`Failed to identify the activated environment's Python runtime. Error: ${error instanceof Error ? error.message : String(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