mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-09-04 06:39:22 +00:00
Add resolved Python version output for activated environments
This commit is contained in:
@@ -347,9 +347,14 @@ jobs:
|
|||||||
if [ "$PYTHON_VERSION" != "3.13.1t" ]; then
|
if [ "$PYTHON_VERSION" != "3.13.1t" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
if [ -n "$PYTHON_VERSION_RESOLVED" ]; then
|
||||||
|
echo "python-version-resolved should be empty without environment activation"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: ${{ steps.setup-uv.outputs.python-version }}
|
PYTHON_VERSION: ${{ steps.setup-uv.outputs.python-version }}
|
||||||
|
PYTHON_VERSION_RESOLVED: ${{ steps.setup-uv.outputs.python-version-resolved }}
|
||||||
- run: uv sync
|
- run: uv sync
|
||||||
working-directory: __tests__/fixtures/uv-project
|
working-directory: __tests__/fixtures/uv-project
|
||||||
|
|
||||||
@@ -358,23 +363,46 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
|
python-version: ["3.13.1t"]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
python-version: "3.13"
|
||||||
|
- os: ubuntu-latest
|
||||||
|
python-version: "3.14.0rc2"
|
||||||
|
- os: ubuntu-latest
|
||||||
|
python-version: "pypy3.11"
|
||||||
steps:
|
steps:
|
||||||
- name: Install latest version
|
- name: Install latest version
|
||||||
id: setup-uv
|
id: setup-uv
|
||||||
uses: $/
|
uses: $/
|
||||||
with:
|
with:
|
||||||
python-version: 3.13.1t
|
python-version: ${{ matrix.python-version }}
|
||||||
activate-environment: true
|
activate-environment: true
|
||||||
|
enable-cache: true
|
||||||
- name: Verify packages can be installed
|
- name: Verify packages can be installed
|
||||||
run: uv pip install pip
|
run: uv pip install pip
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Verify python version is correct
|
- name: Verify Python version outputs and cache key
|
||||||
run: |
|
run: |
|
||||||
python --version
|
expected=$(python -I -c 'import platform; print(platform.python_version())')
|
||||||
if [ "$(python --version)" != "Python 3.13.1" ]; then
|
if [ "$PYTHON_VERSION_RESOLVED" != "$expected" ]; then
|
||||||
|
echo "Wrong resolved Python version: $PYTHON_VERSION_RESOLVED (expected $expected)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
if [ "$PYTHON_VERSION" != "$PYTHON_REQUEST" ]; then
|
||||||
|
echo "Wrong requested Python version: $PYTHON_VERSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
case "$CACHE_KEY" in
|
||||||
|
*-"$PYTHON_REQUEST"-*) ;;
|
||||||
|
*) echo "Cache key no longer contains requested Python version: $CACHE_KEY"; exit 1 ;;
|
||||||
|
esac
|
||||||
shell: bash
|
shell: bash
|
||||||
|
env:
|
||||||
|
CACHE_KEY: ${{ steps.setup-uv.outputs.cache-key }}
|
||||||
|
PYTHON_REQUEST: ${{ matrix.python-version }}
|
||||||
|
PYTHON_VERSION: ${{ steps.setup-uv.outputs.python-version }}
|
||||||
|
PYTHON_VERSION_RESOLVED: ${{ steps.setup-uv.outputs.python-version-resolved }}
|
||||||
- name: Verify output venv is set
|
- name: Verify output venv is set
|
||||||
run: |
|
run: |
|
||||||
if [ -z "$UV_VENV" ]; then
|
if [ -z "$UV_VENV" ]; then
|
||||||
@@ -439,6 +467,15 @@ jobs:
|
|||||||
raise SystemExit(f"Python is not running from custom venv: {sys.executable}")
|
raise SystemExit(f"Python is not running from custom venv: {sys.executable}")
|
||||||
PY
|
PY
|
||||||
shell: bash
|
shell: bash
|
||||||
|
- name: Verify resolved Python version from custom venv
|
||||||
|
run: |
|
||||||
|
if [ "$PYTHON_VERSION_RESOLVED" != "3.13.1" ]; then
|
||||||
|
echo "Wrong resolved Python version: $PYTHON_VERSION_RESOLVED"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
PYTHON_VERSION_RESOLVED: ${{ steps.setup-uv.outputs.python-version-resolved }}
|
||||||
|
|
||||||
test-activate-environment-no-project:
|
test-activate-environment-no-project:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
|||||||
- `cache-hit`: A boolean value to indicate a cache entry was found.
|
- `cache-hit`: A boolean value to indicate a cache entry was found.
|
||||||
- `venv`: Path to the activated venv if activate-environment is true.
|
- `venv`: Path to the activated venv if activate-environment is true.
|
||||||
- `python-version`: The Python version that was set.
|
- `python-version`: The Python version that was set.
|
||||||
|
- `python-version-resolved`: The full Python version of the activated venv, including prerelease suffixes.
|
||||||
|
Empty when `activate-environment` is false or the version 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
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import * as path from "node:path";
|
||||||
|
import type * as exec from "@actions/exec";
|
||||||
|
import {
|
||||||
|
afterEach,
|
||||||
|
beforeEach,
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
jest,
|
||||||
|
} from "@jest/globals";
|
||||||
|
import { createSetupInputs } from "../helpers/setup-inputs";
|
||||||
|
|
||||||
|
const mockGetExecOutput = jest.fn<typeof exec.getExecOutput>();
|
||||||
|
const mockDebug = jest.fn();
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
|
||||||
|
jest.unstable_mockModule("@actions/core", () => ({
|
||||||
|
debug: mockDebug,
|
||||||
|
isDebug: jest.fn(() => false),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.unstable_mockModule("@actions/exec", () => ({
|
||||||
|
getExecOutput: mockGetExecOutput,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { getResolvedPythonVersion } = await import(
|
||||||
|
"../../src/utils/python-version"
|
||||||
|
);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockGetExecOutput.mockReset();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
Object.defineProperty(process, "platform", { value: originalPlatform });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("getResolvedPythonVersion", () => {
|
||||||
|
it("does not query Python when environment activation is disabled", async () => {
|
||||||
|
const inputs = createSetupInputs({ pythonVersion: "3.15t" });
|
||||||
|
|
||||||
|
expect(await getResolvedPythonVersion(inputs)).toBe("");
|
||||||
|
expect(mockGetExecOutput).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
["3.13", "3.13.1"],
|
||||||
|
["3.13.1t", "3.13.1"],
|
||||||
|
["3.15t", "3.15.0rc1"],
|
||||||
|
["pypy3.11", "3.11.11"],
|
||||||
|
["", "3.12.9"],
|
||||||
|
])(
|
||||||
|
"resolves %j to the interpreter's version %s",
|
||||||
|
async (request, version) => {
|
||||||
|
mockGetExecOutput.mockResolvedValue({
|
||||||
|
exitCode: 0,
|
||||||
|
stderr: "",
|
||||||
|
stdout: `${version}\r\n`,
|
||||||
|
});
|
||||||
|
const inputs = createSetupInputs({
|
||||||
|
activateEnvironment: true,
|
||||||
|
pythonVersion: request,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(await getResolvedPythonVersion(inputs)).toBe(version);
|
||||||
|
expect(inputs.pythonVersion).toBe(request);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each(["linux", "darwin", "win32"])(
|
||||||
|
"queries the custom venv directly on %s, including paths with spaces",
|
||||||
|
async (platform) => {
|
||||||
|
Object.defineProperty(process, "platform", { value: platform });
|
||||||
|
mockGetExecOutput.mockResolvedValue({
|
||||||
|
exitCode: 0,
|
||||||
|
stderr: "",
|
||||||
|
stdout: "3.13.1\n",
|
||||||
|
});
|
||||||
|
const inputs = createSetupInputs({
|
||||||
|
activateEnvironment: true,
|
||||||
|
venvPath: "/runner temp/custom venv",
|
||||||
|
workingDirectory: "/different/project",
|
||||||
|
});
|
||||||
|
|
||||||
|
await getResolvedPythonVersion(inputs);
|
||||||
|
|
||||||
|
const pythonPath =
|
||||||
|
platform === "win32"
|
||||||
|
? path.join(inputs.venvPath, "Scripts", "python.exe")
|
||||||
|
: path.join(inputs.venvPath, "bin", "python");
|
||||||
|
expect(mockGetExecOutput).toHaveBeenCalledWith(
|
||||||
|
`"${pythonPath}"`,
|
||||||
|
["-I", "-c", "import platform; print(platform.python_version())"],
|
||||||
|
{ silent: true },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it("escapes quotes in the venv path for @actions/exec", async () => {
|
||||||
|
Object.defineProperty(process, "platform", { value: "linux" });
|
||||||
|
mockGetExecOutput.mockResolvedValue({
|
||||||
|
exitCode: 0,
|
||||||
|
stderr: "",
|
||||||
|
stdout: "3.13.1\n",
|
||||||
|
});
|
||||||
|
const inputs = createSetupInputs({
|
||||||
|
activateEnvironment: true,
|
||||||
|
venvPath: '/workspace/a "quoted" venv',
|
||||||
|
});
|
||||||
|
|
||||||
|
await getResolvedPythonVersion(inputs);
|
||||||
|
|
||||||
|
expect(mockGetExecOutput.mock.calls[0][0]).toContain('a \\"quoted\\" venv');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([new Error("interpreter missing"), "interpreter failed"])(
|
||||||
|
"returns an empty output if the interpreter cannot be queried: %s",
|
||||||
|
async (error) => {
|
||||||
|
mockGetExecOutput.mockRejectedValue(error);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await getResolvedPythonVersion(
|
||||||
|
createSetupInputs({ activateEnvironment: true }),
|
||||||
|
),
|
||||||
|
).toBe("");
|
||||||
|
expect(mockDebug).toHaveBeenCalledWith(
|
||||||
|
expect.stringContaining(error instanceof Error ? error.message : error),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -79,5 +79,7 @@ outputs:
|
|||||||
type: string
|
type: string
|
||||||
python-version:
|
python-version:
|
||||||
type: string
|
type: string
|
||||||
|
python-version-resolved:
|
||||||
|
type: string
|
||||||
python-cache-hit:
|
python-cache-hit:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ outputs:
|
|||||||
description: "Path to the activated venv if activate-environment is true"
|
description: "Path to the activated venv if activate-environment is true"
|
||||||
python-version:
|
python-version:
|
||||||
description: "The Python version that was set."
|
description: "The Python version that was set."
|
||||||
|
python-version-resolved:
|
||||||
|
description: "The full Python version of the activated venv, including prerelease suffixes. Empty when activate-environment is false or the version 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:
|
||||||
|
|||||||
+64
-3
@@ -14676,7 +14676,7 @@ var require_util4 = __commonJS({
|
|||||||
var { getEncoding } = require_encoding();
|
var { getEncoding } = require_encoding();
|
||||||
var { serializeAMimeType, parseMIMEType } = require_data_url();
|
var { serializeAMimeType, parseMIMEType } = require_data_url();
|
||||||
var { types: types2 } = require("node:util");
|
var { types: types2 } = require("node:util");
|
||||||
var { StringDecoder } = require("string_decoder");
|
var { StringDecoder: StringDecoder2 } = require("string_decoder");
|
||||||
var { btoa: btoa2 } = require("node:buffer");
|
var { btoa: btoa2 } = require("node:buffer");
|
||||||
var staticPropertyDescriptors = {
|
var staticPropertyDescriptors = {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
@@ -14767,7 +14767,7 @@ var require_util4 = __commonJS({
|
|||||||
dataURL += serializeAMimeType(parsed);
|
dataURL += serializeAMimeType(parsed);
|
||||||
}
|
}
|
||||||
dataURL += ";base64,";
|
dataURL += ";base64,";
|
||||||
const decoder = new StringDecoder("latin1");
|
const decoder = new StringDecoder2("latin1");
|
||||||
for (const chunk of bytes) {
|
for (const chunk of bytes) {
|
||||||
dataURL += btoa2(decoder.write(chunk));
|
dataURL += btoa2(decoder.write(chunk));
|
||||||
}
|
}
|
||||||
@@ -14796,7 +14796,7 @@ var require_util4 = __commonJS({
|
|||||||
}
|
}
|
||||||
case "BinaryString": {
|
case "BinaryString": {
|
||||||
let binaryString = "";
|
let binaryString = "";
|
||||||
const decoder = new StringDecoder("latin1");
|
const decoder = new StringDecoder2("latin1");
|
||||||
for (const chunk of bytes) {
|
for (const chunk of bytes) {
|
||||||
binaryString += decoder.write(chunk);
|
binaryString += decoder.write(chunk);
|
||||||
}
|
}
|
||||||
@@ -58186,6 +58186,9 @@ var _summary = new Summary();
|
|||||||
// node_modules/@actions/core/lib/platform.js
|
// node_modules/@actions/core/lib/platform.js
|
||||||
var import_os2 = __toESM(require("os"), 1);
|
var import_os2 = __toESM(require("os"), 1);
|
||||||
|
|
||||||
|
// node_modules/@actions/exec/lib/exec.js
|
||||||
|
var import_string_decoder = require("string_decoder");
|
||||||
|
|
||||||
// node_modules/@actions/exec/lib/toolrunner.js
|
// node_modules/@actions/exec/lib/toolrunner.js
|
||||||
var os3 = __toESM(require("os"), 1);
|
var os3 = __toESM(require("os"), 1);
|
||||||
var events = __toESM(require("events"), 1);
|
var events = __toESM(require("events"), 1);
|
||||||
@@ -59006,6 +59009,38 @@ function exec(commandLine, args, options) {
|
|||||||
return runner.exec();
|
return runner.exec();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function getExecOutput(commandLine, args, options) {
|
||||||
|
return __awaiter7(this, void 0, void 0, function* () {
|
||||||
|
var _a2, _b;
|
||||||
|
let stdout = "";
|
||||||
|
let stderr = "";
|
||||||
|
const stdoutDecoder = new import_string_decoder.StringDecoder("utf8");
|
||||||
|
const stderrDecoder = new import_string_decoder.StringDecoder("utf8");
|
||||||
|
const originalStdoutListener = (_a2 = options === null || options === void 0 ? void 0 : options.listeners) === null || _a2 === void 0 ? void 0 : _a2.stdout;
|
||||||
|
const originalStdErrListener = (_b = options === null || options === void 0 ? void 0 : options.listeners) === null || _b === void 0 ? void 0 : _b.stderr;
|
||||||
|
const stdErrListener = (data) => {
|
||||||
|
stderr += stderrDecoder.write(data);
|
||||||
|
if (originalStdErrListener) {
|
||||||
|
originalStdErrListener(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const stdOutListener = (data) => {
|
||||||
|
stdout += stdoutDecoder.write(data);
|
||||||
|
if (originalStdoutListener) {
|
||||||
|
originalStdoutListener(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const listeners = Object.assign(Object.assign({}, options === null || options === void 0 ? void 0 : options.listeners), { stdout: stdOutListener, stderr: stdErrListener });
|
||||||
|
const exitCode = yield exec(commandLine, args, Object.assign(Object.assign({}, options), { listeners }));
|
||||||
|
stdout += stdoutDecoder.end();
|
||||||
|
stderr += stderrDecoder.end();
|
||||||
|
return {
|
||||||
|
exitCode,
|
||||||
|
stdout,
|
||||||
|
stderr
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// node_modules/@actions/core/lib/platform.js
|
// node_modules/@actions/core/lib/platform.js
|
||||||
var platform = import_os2.default.platform();
|
var platform = import_os2.default.platform();
|
||||||
@@ -102066,6 +102101,28 @@ function getResolutionStrategy() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// src/utils/python-version.ts
|
||||||
|
var import_node_path2 = require("node:path");
|
||||||
|
async function getResolvedPythonVersion(inputs) {
|
||||||
|
if (!inputs.activateEnvironment) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const pythonPath = process.platform === "win32" ? (0, import_node_path2.join)(inputs.venvPath, "Scripts", "python.exe") : (0, import_node_path2.join)(inputs.venvPath, "bin", "python");
|
||||||
|
try {
|
||||||
|
const { stdout } = await getExecOutput(
|
||||||
|
`"${pythonPath.replace(/"/g, '\\"')}"`,
|
||||||
|
["-I", "-c", "import platform; print(platform.python_version())"],
|
||||||
|
{ silent: !isDebug() }
|
||||||
|
);
|
||||||
|
return stdout.trim();
|
||||||
|
} catch (error2) {
|
||||||
|
debug(
|
||||||
|
`Failed to get the activated environment's Python version. Error: ${error2 instanceof Error ? error2.message : String(error2)}`
|
||||||
|
);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// src/setup-uv.ts
|
// src/setup-uv.ts
|
||||||
var sourceDir = __dirname;
|
var sourceDir = __dirname;
|
||||||
function formatUnexpectedFailure(error2) {
|
function formatUnexpectedFailure(error2) {
|
||||||
@@ -102136,6 +102193,10 @@ async function run() {
|
|||||||
info2(`Successfully installed uv version ${setupResult.version}`);
|
info2(`Successfully installed uv version ${setupResult.version}`);
|
||||||
const detectedPythonVersion = await getPythonVersion2(inputs);
|
const detectedPythonVersion = await getPythonVersion2(inputs);
|
||||||
setOutput("python-version", detectedPythonVersion);
|
setOutput("python-version", detectedPythonVersion);
|
||||||
|
setOutput(
|
||||||
|
"python-version-resolved",
|
||||||
|
await getResolvedPythonVersion(inputs)
|
||||||
|
);
|
||||||
if (inputs.enableCache) {
|
if (inputs.enableCache) {
|
||||||
await restoreCache2(inputs, detectedPythonVersion);
|
await restoreCache2(inputs, detectedPythonVersion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,19 @@ This allows directly using it in later steps:
|
|||||||
|
|
||||||
By default, the venv is created at `.venv` inside the `working-directory`.
|
By default, the venv is created at `.venv` inside the `working-directory`.
|
||||||
|
|
||||||
|
With `activate-environment: true`, the `python-version-resolved` output contains the
|
||||||
|
venv's full Python version, as reported by `platform.python_version()`. For example,
|
||||||
|
a `python-version` input of `3.15t` can resolve to `3.15.0rc1`. Use
|
||||||
|
`${{ steps.setup-uv.outputs.python-version-resolved }}` in later steps to access
|
||||||
|
the resolved version (with `id: setup-uv` on the setup step).
|
||||||
|
|
||||||
|
This is the Python language version: it includes prerelease suffixes, but no
|
||||||
|
implementation name or free-threaded marker. For cache keys that distinguish PyPy
|
||||||
|
from CPython or free-threaded builds, include the requested version as well.
|
||||||
|
The output is empty when `activate-environment` is false or the version cannot be
|
||||||
|
determined. 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:
|
You can customize the venv location with `venv-path`, for example to place it in the runner temp directory:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
getPlatform,
|
getPlatform,
|
||||||
type Platform,
|
type Platform,
|
||||||
} from "./utils/platforms";
|
} from "./utils/platforms";
|
||||||
|
import { getResolvedPythonVersion } from "./utils/python-version";
|
||||||
import { resolveUvVersion } from "./version/resolve";
|
import { resolveUvVersion } from "./version/resolve";
|
||||||
|
|
||||||
const sourceDir = __dirname;
|
const sourceDir = __dirname;
|
||||||
@@ -101,6 +102,10 @@ async function run(): Promise<void> {
|
|||||||
|
|
||||||
const detectedPythonVersion = await getPythonVersion(inputs);
|
const detectedPythonVersion = await getPythonVersion(inputs);
|
||||||
core.setOutput("python-version", detectedPythonVersion);
|
core.setOutput("python-version", detectedPythonVersion);
|
||||||
|
core.setOutput(
|
||||||
|
"python-version-resolved",
|
||||||
|
await getResolvedPythonVersion(inputs),
|
||||||
|
);
|
||||||
|
|
||||||
if (inputs.enableCache) {
|
if (inputs.enableCache) {
|
||||||
await restoreCache(inputs, detectedPythonVersion);
|
await restoreCache(inputs, detectedPythonVersion);
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { join } from "node:path";
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
import * as exec from "@actions/exec";
|
||||||
|
import type { SetupInputs } from "./inputs";
|
||||||
|
|
||||||
|
export async function getResolvedPythonVersion(
|
||||||
|
inputs: SetupInputs,
|
||||||
|
): Promise<string> {
|
||||||
|
if (!inputs.activateEnvironment) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const pythonPath =
|
||||||
|
process.platform === "win32"
|
||||||
|
? join(inputs.venvPath, "Scripts", "python.exe")
|
||||||
|
: join(inputs.venvPath, "bin", "python");
|
||||||
|
|
||||||
|
try {
|
||||||
|
// @actions/exec parses the executable as a command line, so quote the path.
|
||||||
|
const { stdout } = await exec.getExecOutput(
|
||||||
|
`"${pythonPath.replace(/"/g, '\\"')}"`,
|
||||||
|
["-I", "-c", "import platform; print(platform.python_version())"],
|
||||||
|
{ silent: !core.isDebug() },
|
||||||
|
);
|
||||||
|
return stdout.trim();
|
||||||
|
} catch (error) {
|
||||||
|
core.debug(
|
||||||
|
`Failed to get the activated environment's Python version. Error: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
|
);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user