new inputs activate-environment and working-directory (#381)

venv activation was implicit when python-version was supplied. This now
only happens when activate-environment is true. working-directory
controls where we work and thus also where the .venv will be created

Closes: #351
Closes: #271
Closes: #251
Closes: #211
This commit is contained in:
Kevin Stillhammer 2025-04-24 15:17:35 +02:00 committed by GitHub
parent aa1290542e
commit ec4c691628
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 203 additions and 179 deletions

View file

@ -115,7 +115,7 @@ jobs:
id: setup-uv id: setup-uv
uses: ./ uses: ./
with: with:
pyproject-file: "__tests__/fixtures/pyproject-toml-project/pyproject.toml" working-directory: "__tests__/fixtures/pyproject-toml-project"
- name: Correct version gets installed - name: Correct version gets installed
run: | run: |
if [ "$(uv --version)" != "uv 0.5.14" ]; then if [ "$(uv --version)" != "uv 0.5.14" ]; then
@ -131,9 +131,8 @@ jobs:
id: setup-uv id: setup-uv
uses: ./ uses: ./
with: with:
pyproject-file: "__tests__/fixtures/malformed-pyproject-toml-project/pyproject.toml" working-directory: "__tests__/fixtures/malformed-pyproject-toml-project"
- run: uv sync - run: uv --help
working-directory: __tests__/fixtures/uv-project
test-uv-file-version: test-uv-file-version:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -143,8 +142,7 @@ jobs:
id: setup-uv id: setup-uv
uses: ./ uses: ./
with: with:
pyproject-file: "__tests__/fixtures/uv-toml-project/pyproject.toml" working-directory: "__tests__/fixtures/uv-toml-project"
uv-file: "__tests__/fixtures/uv-toml-project/uv.toml"
- name: Correct version gets installed - name: Correct version gets installed
run: | run: |
if [ "$(uv --version)" != "uv 0.5.15" ]; then if [ "$(uv --version)" != "uv 0.5.15" ]; then
@ -229,7 +227,7 @@ jobs:
fi fi
test-python-version: test-python-version:
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
@ -246,8 +244,21 @@ jobs:
exit 1 exit 1
fi fi
shell: bash shell: bash
test-activate-environment:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
steps:
- uses: actions/checkout@v4
- name: Install latest version
uses: ./
with:
python-version: 3.13.1t
activate-environment: true
- name: Verify packages can be installed - name: Verify packages can be installed
run: uv pip install --python=3.13.1t pip run: uv pip install pip
shell: bash shell: bash
- name: Verify python version is correct - name: Verify python version is correct
run: | run: |
@ -508,6 +519,7 @@ jobs:
- test-tool-install - test-tool-install
- test-tilde-expansion-tool-dirs - test-tilde-expansion-tool-dirs
- test-python-version - test-python-version
- test-activate-environment
- test-musl - test-musl
- test-restore-cache - test-restore-cache
- test-restore-cache-requirements-txt - test-restore-cache-requirements-txt

View file

@ -15,8 +15,9 @@ Set up your GitHub Actions workflow with a specific version of [uv](https://docs
- [Install the latest version](#install-the-latest-version) - [Install the latest version](#install-the-latest-version)
- [Install a specific version](#install-a-specific-version) - [Install a specific version](#install-a-specific-version)
- [Install a version by supplying a semver range or pep440 specifier](#install-a-version-by-supplying-a-semver-range-or-pep440-specifier) - [Install a version by supplying a semver range or pep440 specifier](#install-a-version-by-supplying-a-semver-range-or-pep440-specifier)
- [Install a required-version](#install-a-required-version)
- [Python version](#python-version) - [Python version](#python-version)
- [Activate environment](#activate-environment)
- [Working directory](#working-directory)
- [Validate checksum](#validate-checksum) - [Validate checksum](#validate-checksum)
- [Enable Caching](#enable-caching) - [Enable Caching](#enable-caching)
- [Cache dependency glob](#cache-dependency-glob) - [Cache dependency glob](#cache-dependency-glob)
@ -90,32 +91,9 @@ to install the latest version that satisfies the range.
version: ">=0.4.25,<0.5" version: ">=0.4.25,<0.5"
``` ```
### Install a required-version
You can specify a [required-version](https://docs.astral.sh/uv/reference/settings/#required-version)
in either a `uv.toml` or `pyproject.toml` file:
```yaml
- name: Install required-version defined in uv.toml
uses: astral-sh/setup-uv@v5
with:
uv-file: "path/to/uv.toml"
```
```yaml
- name: Install required-version defined in pyproject.toml
uses: astral-sh/setup-uv@v5
with:
pyproject-file: "path/to/pyproject.toml"
```
### Python version ### Python version
You can use the input `python-version` to You can use the input `python-version` to set the environment variable `UV_PYTHON` for the rest of your workflow
- set the environment variable `UV_PYTHON` for the rest of your workflow
- create a new virtual environment with the specified python version
- activate the virtual environment for the rest of your workflow
This will override any python version specifications in `pyproject.toml` and `.python-version` This will override any python version specifications in `pyproject.toml` and `.python-version`
@ -146,6 +124,34 @@ jobs:
run: uv run --frozen pytest run: uv run --frozen pytest
``` ```
### Activate environment
You can set `activate-environment` to `true` to automatically activate a venv.
This allows directly using it in later steps:
```yaml
- name: Install the latest version of uv and activate the environment
uses: astral-sh/setup-uv@v5
with:
activate-environment: true
- run: uv pip install pip
```
### Working directory
You can set the working directory with the `working-directory` input.
This controls where we look for `pyproject.toml`, `uv.toml` and `.python-version` files
which are used to determine the version of uv and python to install.
It also controls where [the venv gets created](#activate-environment).
```yaml
- name: Install uv based on the config files in the working-directory
uses: astral-sh/setup-uv@v5
with:
working-directory: my/subproject/dir
```
### Validate checksum ### Validate checksum
You can specify a checksum to validate the downloaded executable. Checksums up to the default version You can specify a checksum to validate the downloaded executable. Checksums up to the default version
@ -383,7 +389,7 @@ This action downloads uv from the uv repo's official
[GitHub Actions Toolkit](https://github.com/actions/toolkit) to cache it as a tool to speed up [GitHub Actions Toolkit](https://github.com/actions/toolkit) to cache it as a tool to speed up
consecutive runs on self-hosted runners. consecutive runs on self-hosted runners.
The installed version of uv is then added to the runner PATH, enabling subsequent steps to invoke it The installed version of uv is then added to the runner PATH, enabling later steps to invoke it
by name (`uv`). by name (`uv`).
## FAQ ## FAQ

View file

@ -6,15 +6,15 @@ inputs:
version: version:
description: "The version of uv to install e.g., `0.5.0` Defaults to the version in pyproject.toml or 'latest'." description: "The version of uv to install e.g., `0.5.0` Defaults to the version in pyproject.toml or 'latest'."
default: "" default: ""
pyproject-file:
description: "Path to a pyproject.toml"
default: ""
uv-file:
description: "Path to a uv.toml"
default: ""
python-version: python-version:
description: "The version of Python to set UV_PYTHON to" description: "The version of Python to set UV_PYTHON to"
required: false required: false
activate-environment:
description: "Use uv venv to activate a venv ready to be used by later steps. "
default: "false"
working-directory:
description: "The directory to execute all commands in and look for files such as pyproject.toml"
default: ${{ github.workspace }}
checksum: checksum:
description: "The checksum of the uv version to install" description: "The checksum of the uv version to install"
required: false required: false

8
dist/save-cache/index.js generated vendored
View file

@ -88731,7 +88731,7 @@ async function getPythonVersion() {
}, },
}; };
try { try {
const execArgs = ["python", "find"]; const execArgs = ["python", "find", "--directory", inputs_1.workingDirectory];
await exec.exec("uv", execArgs, options); await exec.exec("uv", execArgs, options);
const pythonPath = output.trim(); const pythonPath = output.trim();
output = ""; output = "";
@ -88997,13 +88997,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.pythonVersion = exports.uvFile = exports.pyProjectFile = exports.version = void 0; exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.workingDirectory = exports.activateEnvironment = exports.pythonVersion = exports.version = void 0;
const core = __importStar(__nccwpck_require__(7484)); const core = __importStar(__nccwpck_require__(7484));
const node_path_1 = __importDefault(__nccwpck_require__(6760)); const node_path_1 = __importDefault(__nccwpck_require__(6760));
exports.version = core.getInput("version"); exports.version = core.getInput("version");
exports.pyProjectFile = core.getInput("pyproject-file");
exports.uvFile = core.getInput("uv-file");
exports.pythonVersion = core.getInput("python-version"); exports.pythonVersion = core.getInput("python-version");
exports.activateEnvironment = core.getBooleanInput("activate-environment");
exports.workingDirectory = core.getInput("working-directory");
exports.checkSum = core.getInput("checksum"); exports.checkSum = core.getInput("checksum");
exports.enableCache = getEnableCache(); exports.enableCache = getEnableCache();
exports.cacheSuffix = core.getInput("cache-suffix") || ""; exports.cacheSuffix = core.getInput("cache-suffix") || "";

209
dist/setup/index.js generated vendored
View file

@ -121062,7 +121062,7 @@ async function getPythonVersion() {
}, },
}; };
try { try {
const execArgs = ["python", "find"]; const execArgs = ["python", "find", "--directory", inputs_1.workingDirectory];
await exec.exec("uv", execArgs, options); await exec.exec("uv", execArgs, options);
const pythonPath = output.trim(); const pythonPath = output.trim();
output = ""; output = "";
@ -124315,7 +124315,7 @@ const platforms_1 = __nccwpck_require__(98361);
const inputs_1 = __nccwpck_require__(9612); const inputs_1 = __nccwpck_require__(9612);
const exec = __importStar(__nccwpck_require__(95236)); const exec = __importStar(__nccwpck_require__(95236));
const node_fs_1 = __importDefault(__nccwpck_require__(73024)); const node_fs_1 = __importDefault(__nccwpck_require__(73024));
const pyproject_1 = __nccwpck_require__(53929); const config_file_1 = __nccwpck_require__(27846);
async function run() { async function run() {
detectEmptyWorkdir(); detectEmptyWorkdir();
const platform = await (0, platforms_1.getPlatform)(); const platform = await (0, platforms_1.getPlatform)();
@ -124331,7 +124331,8 @@ async function run() {
addToolBinToPath(); addToolBinToPath();
addUvToPathAndOutput(setupResult.uvDir); addUvToPathAndOutput(setupResult.uvDir);
setToolDir(); setToolDir();
await setupPython(); setupPython();
await activateEnvironment();
addMatchers(); addMatchers();
setCacheDir(inputs_1.cacheLocalPath); setCacheDir(inputs_1.cacheLocalPath);
core.setOutput("uv-version", setupResult.version); core.setOutput("uv-version", setupResult.version);
@ -124375,20 +124376,12 @@ async function determineVersion() {
if (inputs_1.version !== "") { if (inputs_1.version !== "") {
return await (0, download_version_1.resolveVersion)(inputs_1.version, inputs_1.githubToken); return await (0, download_version_1.resolveVersion)(inputs_1.version, inputs_1.githubToken);
} }
const configFile = inputs_1.uvFile !== "" ? inputs_1.uvFile : inputs_1.pyProjectFile; const versionFromUvToml = (0, config_file_1.getUvVersionFromConfigFile)(`${inputs_1.workingDirectory}${path.sep}uv.toml`);
if (configFile !== "") { const versionFromPyproject = (0, config_file_1.getUvVersionFromConfigFile)(`${inputs_1.workingDirectory}${path.sep}pyproject.toml`);
const versionFromConfigFile = (0, pyproject_1.getUvVersionFromConfigFile)(configFile); if (versionFromUvToml === undefined && versionFromPyproject === undefined) {
if (versionFromConfigFile === undefined) { core.info("Could not determine uv version from uv.toml or pyproject.toml. Falling back to latest.");
core.warning(`Could not find required-version under [tool.uv] in ${configFile}. Falling back to latest`);
} }
return await (0, download_version_1.resolveVersion)(versionFromConfigFile || "latest", inputs_1.githubToken); return await (0, download_version_1.resolveVersion)(versionFromUvToml || versionFromPyproject || "latest", inputs_1.githubToken);
}
if (!node_fs_1.default.existsSync("uv.toml") && !node_fs_1.default.existsSync("pyproject.toml")) {
return await (0, download_version_1.resolveVersion)("latest", inputs_1.githubToken);
}
const versionFile = node_fs_1.default.existsSync("uv.toml") ? "uv.toml" : "pyproject.toml";
const versionFromConfigFile = (0, pyproject_1.getUvVersionFromConfigFile)(versionFile);
return await (0, download_version_1.resolveVersion)(versionFromConfigFile || "latest", inputs_1.githubToken);
} }
function addUvToPathAndOutput(cachedPath) { function addUvToPathAndOutput(cachedPath) {
core.setOutput("uv-path", `${cachedPath}${path.sep}uv`); core.setOutput("uv-path", `${cachedPath}${path.sep}uv`);
@ -124424,19 +124417,23 @@ function setToolDir() {
core.info(`Set UV_TOOL_DIR to ${inputs_1.toolDir}`); core.info(`Set UV_TOOL_DIR to ${inputs_1.toolDir}`);
} }
} }
async function setupPython() { function setupPython() {
if (inputs_1.pythonVersion !== "") { if (inputs_1.pythonVersion !== "") {
core.exportVariable("UV_PYTHON", inputs_1.pythonVersion); core.exportVariable("UV_PYTHON", inputs_1.pythonVersion);
core.info(`Set UV_PYTHON to ${inputs_1.pythonVersion}`); core.info(`Set UV_PYTHON to ${inputs_1.pythonVersion}`);
const execArgs = ["venv", "--python", inputs_1.pythonVersion]; }
}
async function activateEnvironment() {
if (inputs_1.activateEnvironment) {
const execArgs = ["venv", ".venv", "--directory", inputs_1.workingDirectory];
core.info("Activating python venv..."); core.info("Activating python venv...");
await exec.exec("uv", execArgs); await exec.exec("uv", execArgs);
let venvBinPath = ".venv/bin"; let venvBinPath = `${inputs_1.workingDirectory}${path.sep}.venv${path.sep}bin`;
if (process.platform === "win32") { if (process.platform === "win32") {
venvBinPath = ".venv/Scripts"; venvBinPath = `${inputs_1.workingDirectory}${path.sep}.venv${path.sep}Scripts`;
} }
core.addPath(path.resolve(venvBinPath)); core.addPath(path.resolve(venvBinPath));
core.exportVariable("VIRTUAL_ENV", path.resolve(".venv")); core.exportVariable("VIRTUAL_ENV", path.resolve(`${inputs_1.workingDirectory}${path.sep}.venv`));
} }
} }
function setCacheDir(cacheLocalPath) { function setCacheDir(cacheLocalPath) {
@ -124450,6 +124447,88 @@ function addMatchers() {
run(); run();
/***/ }),
/***/ 27846:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getUvVersionFromConfigFile = getUvVersionFromConfigFile;
const node_fs_1 = __importDefault(__nccwpck_require__(73024));
const core = __importStar(__nccwpck_require__(37484));
const toml = __importStar(__nccwpck_require__(27106));
function getUvVersionFromConfigFile(filePath) {
core.info(`Trying to find required-version for uv in: ${filePath}`);
if (!node_fs_1.default.existsSync(filePath)) {
core.info(`Could not find file: ${filePath}`);
return undefined;
}
let requiredVersion;
try {
requiredVersion = getRequiredVersion(filePath);
}
catch (err) {
const message = err.message;
core.warning(`Error while parsing ${filePath}: ${message}`);
return undefined;
}
if (requiredVersion?.startsWith("==")) {
requiredVersion = requiredVersion.slice(2);
}
if (requiredVersion !== undefined) {
core.info(`Found required-version for uv in ${filePath}: ${requiredVersion}`);
}
return requiredVersion;
}
function getRequiredVersion(filePath) {
const fileContent = node_fs_1.default.readFileSync(filePath, "utf-8");
if (filePath.endsWith("pyproject.toml")) {
const tomlContent = toml.parse(fileContent);
return tomlContent?.tool?.uv?.["required-version"];
}
const tomlContent = toml.parse(fileContent);
return tomlContent["required-version"];
}
/***/ }), /***/ }),
/***/ 56156: /***/ 56156:
@ -124508,13 +124587,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", ({ value: true })); Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.pythonVersion = exports.uvFile = exports.pyProjectFile = exports.version = void 0; exports.githubToken = exports.toolDir = exports.toolBinDir = exports.ignoreEmptyWorkdir = exports.ignoreNothingToCache = exports.pruneCache = exports.cacheDependencyGlob = exports.cacheLocalPath = exports.cacheSuffix = exports.enableCache = exports.checkSum = exports.workingDirectory = exports.activateEnvironment = exports.pythonVersion = exports.version = void 0;
const core = __importStar(__nccwpck_require__(37484)); const core = __importStar(__nccwpck_require__(37484));
const node_path_1 = __importDefault(__nccwpck_require__(76760)); const node_path_1 = __importDefault(__nccwpck_require__(76760));
exports.version = core.getInput("version"); exports.version = core.getInput("version");
exports.pyProjectFile = core.getInput("pyproject-file");
exports.uvFile = core.getInput("uv-file");
exports.pythonVersion = core.getInput("python-version"); exports.pythonVersion = core.getInput("python-version");
exports.activateEnvironment = core.getBooleanInput("activate-environment");
exports.workingDirectory = core.getInput("working-directory");
exports.checkSum = core.getInput("checksum"); exports.checkSum = core.getInput("checksum");
exports.enableCache = getEnableCache(); exports.enableCache = getEnableCache();
exports.cacheSuffix = core.getInput("cache-suffix") || ""; exports.cacheSuffix = core.getInput("cache-suffix") || "";
@ -124725,88 +124804,6 @@ async function isMuslOs() {
} }
/***/ }),
/***/ 53929:
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.getUvVersionFromConfigFile = getUvVersionFromConfigFile;
const node_fs_1 = __importDefault(__nccwpck_require__(73024));
const core = __importStar(__nccwpck_require__(37484));
const toml = __importStar(__nccwpck_require__(27106));
function getUvVersionFromConfigFile(filePath) {
core.debug(`Trying to find required-version for uv in: ${filePath}`);
if (!node_fs_1.default.existsSync(filePath)) {
core.warning(`Could not find file: ${filePath}`);
return undefined;
}
let requiredVersion;
try {
requiredVersion = getRequiredVersion(filePath);
}
catch (err) {
const message = err.message;
core.warning(`Error while parsing ${filePath}: ${message}`);
return undefined;
}
if (requiredVersion?.startsWith("==")) {
requiredVersion = requiredVersion.slice(2);
}
if (requiredVersion !== undefined) {
core.info(`Found required-version for uv in ${filePath}: ${requiredVersion}`);
}
return requiredVersion;
}
function getRequiredVersion(filePath) {
const fileContent = node_fs_1.default.readFileSync(filePath, "utf-8");
if (filePath.endsWith("pyproject.toml")) {
const tomlContent = toml.parse(fileContent);
return tomlContent?.tool?.uv?.["required-version"];
}
const tomlContent = toml.parse(fileContent);
return tomlContent["required-version"];
}
/***/ }), /***/ }),
/***/ 42078: /***/ 42078:

View file

@ -5,6 +5,7 @@ import {
cacheLocalPath, cacheLocalPath,
cacheSuffix, cacheSuffix,
pythonVersion as pythonVersionInput, pythonVersion as pythonVersionInput,
workingDirectory,
} from "../utils/inputs"; } from "../utils/inputs";
import { getArch, getPlatform } from "../utils/platforms"; import { getArch, getPlatform } from "../utils/platforms";
import { hashFiles } from "../hash/hash-files"; import { hashFiles } from "../hash/hash-files";
@ -73,7 +74,7 @@ async function getPythonVersion(): Promise<string> {
}; };
try { try {
const execArgs = ["python", "find"]; const execArgs = ["python", "find", "--directory", workingDirectory];
await exec.exec("uv", execArgs, options); await exec.exec("uv", execArgs, options);
const pythonPath = output.trim(); const pythonPath = output.trim();

View file

@ -14,21 +14,21 @@ import {
type Platform, type Platform,
} from "./utils/platforms"; } from "./utils/platforms";
import { import {
activateEnvironment as activateEnvironmentInput,
cacheLocalPath, cacheLocalPath,
checkSum, checkSum,
ignoreEmptyWorkdir, ignoreEmptyWorkdir,
enableCache, enableCache,
githubToken, githubToken,
pyProjectFile,
pythonVersion, pythonVersion,
toolBinDir, toolBinDir,
toolDir, toolDir,
uvFile,
version as versionInput, version as versionInput,
workingDirectory,
} from "./utils/inputs"; } from "./utils/inputs";
import * as exec from "@actions/exec"; import * as exec from "@actions/exec";
import fs from "node:fs"; import fs from "node:fs";
import { getUvVersionFromConfigFile } from "./utils/pyproject"; import { getUvVersionFromConfigFile } from "./utils/config-file";
async function run(): Promise<void> { async function run(): Promise<void> {
detectEmptyWorkdir(); detectEmptyWorkdir();
@ -47,7 +47,8 @@ async function run(): Promise<void> {
addToolBinToPath(); addToolBinToPath();
addUvToPathAndOutput(setupResult.uvDir); addUvToPathAndOutput(setupResult.uvDir);
setToolDir(); setToolDir();
await setupPython(); setupPython();
await activateEnvironment();
addMatchers(); addMatchers();
setCacheDir(cacheLocalPath); setCacheDir(cacheLocalPath);
@ -111,22 +112,21 @@ async function determineVersion(): Promise<string> {
if (versionInput !== "") { if (versionInput !== "") {
return await resolveVersion(versionInput, githubToken); return await resolveVersion(versionInput, githubToken);
} }
const configFile = uvFile !== "" ? uvFile : pyProjectFile; const versionFromUvToml = getUvVersionFromConfigFile(
if (configFile !== "") { `${workingDirectory}${path.sep}uv.toml`,
const versionFromConfigFile = getUvVersionFromConfigFile(configFile); );
if (versionFromConfigFile === undefined) { const versionFromPyproject = getUvVersionFromConfigFile(
core.warning( `${workingDirectory}${path.sep}pyproject.toml`,
`Could not find required-version under [tool.uv] in ${configFile}. Falling back to latest`, );
if (versionFromUvToml === undefined && versionFromPyproject === undefined) {
core.info(
"Could not determine uv version from uv.toml or pyproject.toml. Falling back to latest.",
); );
} }
return await resolveVersion(versionFromConfigFile || "latest", githubToken); return await resolveVersion(
} versionFromUvToml || versionFromPyproject || "latest",
if (!fs.existsSync("uv.toml") && !fs.existsSync("pyproject.toml")) { githubToken,
return await resolveVersion("latest", githubToken); );
}
const versionFile = fs.existsSync("uv.toml") ? "uv.toml" : "pyproject.toml";
const versionFromConfigFile = getUvVersionFromConfigFile(versionFile);
return await resolveVersion(versionFromConfigFile || "latest", githubToken);
} }
function addUvToPathAndOutput(cachedPath: string): void { function addUvToPathAndOutput(cachedPath: string): void {
@ -163,21 +163,29 @@ function setToolDir(): void {
} }
} }
async function setupPython(): Promise<void> { function setupPython(): void {
if (pythonVersion !== "") { if (pythonVersion !== "") {
core.exportVariable("UV_PYTHON", pythonVersion); core.exportVariable("UV_PYTHON", pythonVersion);
core.info(`Set UV_PYTHON to ${pythonVersion}`); core.info(`Set UV_PYTHON to ${pythonVersion}`);
const execArgs = ["venv", "--python", pythonVersion]; }
}
async function activateEnvironment(): Promise<void> {
if (activateEnvironmentInput) {
const execArgs = ["venv", ".venv", "--directory", workingDirectory];
core.info("Activating python venv..."); core.info("Activating python venv...");
await exec.exec("uv", execArgs); await exec.exec("uv", execArgs);
let venvBinPath = ".venv/bin"; let venvBinPath = `${workingDirectory}${path.sep}.venv${path.sep}bin`;
if (process.platform === "win32") { if (process.platform === "win32") {
venvBinPath = ".venv/Scripts"; venvBinPath = `${workingDirectory}${path.sep}.venv${path.sep}Scripts`;
} }
core.addPath(path.resolve(venvBinPath)); core.addPath(path.resolve(venvBinPath));
core.exportVariable("VIRTUAL_ENV", path.resolve(".venv")); core.exportVariable(
"VIRTUAL_ENV",
path.resolve(`${workingDirectory}${path.sep}.venv`),
);
} }
} }

View file

@ -5,9 +5,9 @@ import * as toml from "smol-toml";
export function getUvVersionFromConfigFile( export function getUvVersionFromConfigFile(
filePath: string, filePath: string,
): string | undefined { ): string | undefined {
core.debug(`Trying to find required-version for uv in: ${filePath}`); core.info(`Trying to find required-version for uv in: ${filePath}`);
if (!fs.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
core.warning(`Could not find file: ${filePath}`); core.info(`Could not find file: ${filePath}`);
return undefined; return undefined;
} }
let requiredVersion: string | undefined; let requiredVersion: string | undefined;

View file

@ -2,9 +2,9 @@ import * as core from "@actions/core";
import path from "node:path"; import path from "node:path";
export const version = core.getInput("version"); export const version = core.getInput("version");
export const pyProjectFile = core.getInput("pyproject-file");
export const uvFile = core.getInput("uv-file");
export const pythonVersion = core.getInput("python-version"); export const pythonVersion = core.getInput("python-version");
export const activateEnvironment = core.getBooleanInput("activate-environment");
export const workingDirectory = core.getInput("working-directory");
export const checkSum = core.getInput("checksum"); export const checkSum = core.getInput("checksum");
export const enableCache = getEnableCache(); export const enableCache = getEnableCache();
export const cacheSuffix = core.getInput("cache-suffix") || ""; export const cacheSuffix = core.getInput("cache-suffix") || "";