Detect required-version from config file (#233)

1. If defined use version input
2. If defined use uv-file input
3. If defined use pyproject-file input
4. Search for required-version in uv.toml in repo root
5. Search for required-version in pyproject.toml in repo root
6. Use latest

Closes: #215
This commit is contained in:
Kevin Stillhammer 2025-01-13 15:24:25 +01:00 committed by GitHub
parent d577e74f98
commit 5ce9ee0011
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 159 additions and 14 deletions

View File

@ -64,6 +64,39 @@ jobs:
fi fi
env: env:
UV_VERSION: ${{ steps.setup-uv.outputs.uv-version }} UV_VERSION: ${{ steps.setup-uv.outputs.uv-version }}
test-pyproject-file-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install version 0.5.14
id: setup-uv
uses: ./
with:
pyproject-file: "__tests__/fixtures/pyproject-toml-project/pyproject.toml"
- name: Correct version gets installed
run: |
if [ "$UV_VERSION" != "0.5.14" ]; then
exit 1
fi
env:
UV_VERSION: ${{ steps.setup-uv.outputs.uv-version }}
test-uv-file-version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install version 0.5.15
id: setup-uv
uses: ./
with:
pyproject-file: "__tests__/fixtures/uv-toml-project/pyproject.toml"
uv-file: "__tests__/fixtures/uv-toml-project/uv.toml"
- name: Correct version gets installed
run: |
if [ "$UV_VERSION" != "0.5.15" ]; then
exit 1
fi
env:
UV_VERSION: ${{ steps.setup-uv.outputs.uv-version }}
test-checksum: test-checksum:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:

View File

@ -0,0 +1 @@
3.11

View File

@ -0,0 +1,6 @@
def main():
print("Hello from pyproject-toml-project!")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,10 @@
[project]
name = "pyproject-toml-project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[tool.uv]
required-version = "==0.5.14"

View File

@ -0,0 +1 @@
3.11

View File

@ -0,0 +1,6 @@
def main():
print("Hello from uv-toml-project!")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,10 @@
[project]
name = "uv-toml-project"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = []
[tool.uv]
required-version = "==0.5.14"

View File

@ -0,0 +1 @@
required-version = "==0.5.15"

View File

@ -4,8 +4,14 @@ description:
author: "astral-sh" author: "astral-sh"
inputs: inputs:
version: version:
description: "The version of uv to install" description: "The version of uv to install e.g., `0.5.0` Defaults to the version in pyproject.toml or 'latest'."
default: "latest" 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
@ -18,7 +24,7 @@ inputs:
required: false required: false
default: ${{ github.token }} default: ${{ github.token }}
enable-cache: enable-cache:
description: "Enable caching of the uv cache" description: "Enable uploading of the uv cache"
default: "auto" default: "auto"
cache-dependency-glob: cache-dependency-glob:
description: description:

BIN
dist/save-cache/index.js generated vendored

Binary file not shown.

BIN
dist/setup/index.js generated vendored

Binary file not shown.

11
package-lock.json generated
View File

@ -16,6 +16,7 @@
"@actions/glob": "^0.5.0", "@actions/glob": "^0.5.0",
"@actions/io": "^1.1.3", "@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1", "@actions/tool-cache": "^2.0.1",
"@iarna/toml": "^2.2.5",
"@octokit/rest": "^21.0.2" "@octokit/rest": "^21.0.2"
}, },
"devDependencies": { "devDependencies": {
@ -1104,6 +1105,11 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
},
"node_modules/@istanbuljs/load-nyc-config": { "node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@ -5918,6 +5924,11 @@
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz",
"integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==" "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA=="
}, },
"@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
},
"@istanbuljs/load-nyc-config": { "@istanbuljs/load-nyc-config": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",

View File

@ -30,7 +30,8 @@
"@actions/glob": "^0.5.0", "@actions/glob": "^0.5.0",
"@actions/io": "^1.1.3", "@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1", "@actions/tool-cache": "^2.0.1",
"@octokit/rest": "^21.0.2" "@octokit/rest": "^21.0.2",
"@iarna/toml": "^2.2.5"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "1.9.4", "@biomejs/biome": "1.9.4",

View File

@ -18,12 +18,16 @@ import {
checkSum, checkSum,
enableCache, enableCache,
githubToken, githubToken,
pyProjectFile,
pythonVersion, pythonVersion,
toolBinDir, toolBinDir,
toolDir, toolDir,
version, uvFile,
version as versionInput,
} from "./utils/inputs"; } from "./utils/inputs";
import * as exec from "@actions/exec"; import * as exec from "@actions/exec";
import fs from "node:fs";
import { getUvVersionFromConfigFile } from "./utils/pyproject";
async function run(): Promise<void> { async function run(): Promise<void> {
const platform = getPlatform(); const platform = getPlatform();
@ -36,13 +40,7 @@ async function run(): Promise<void> {
if (arch === undefined) { if (arch === undefined) {
throw new Error(`Unsupported architecture: ${process.arch}`); throw new Error(`Unsupported architecture: ${process.arch}`);
} }
const setupResult = await setupUv( const setupResult = await setupUv(platform, arch, checkSum, githubToken);
platform,
arch,
version,
checkSum,
githubToken,
);
addUvToPath(setupResult.uvDir); addUvToPath(setupResult.uvDir);
addToolBinToPath(); addToolBinToPath();
@ -66,11 +64,10 @@ async function run(): Promise<void> {
async function setupUv( async function setupUv(
platform: Platform, platform: Platform,
arch: Architecture, arch: Architecture,
versionInput: string,
checkSum: string | undefined, checkSum: string | undefined,
githubToken: string, githubToken: string,
): Promise<{ uvDir: string; version: string }> { ): Promise<{ uvDir: string; version: string }> {
const resolvedVersion = await resolveVersion(versionInput, githubToken); const resolvedVersion = await determineVersion();
const toolCacheResult = tryGetFromToolCache(arch, resolvedVersion); const toolCacheResult = tryGetFromToolCache(arch, resolvedVersion);
if (toolCacheResult.installedPath) { if (toolCacheResult.installedPath) {
core.info(`Found uv in tool-cache for ${toolCacheResult.version}`); core.info(`Found uv in tool-cache for ${toolCacheResult.version}`);
@ -94,6 +91,28 @@ async function setupUv(
}; };
} }
async function determineVersion(): Promise<string> {
if (versionInput !== "") {
return await resolveVersion(versionInput, githubToken);
}
const configFile = uvFile !== "" ? uvFile : pyProjectFile;
if (configFile !== "") {
const versionFromConfigFile = getUvVersionFromConfigFile(configFile);
if (versionFromConfigFile === undefined) {
core.warning(
`Could not find required-version under [tool.uv] in ${configFile}. Falling back to latest`,
);
}
return await resolveVersion(versionFromConfigFile || "latest", githubToken);
}
if (!fs.existsSync("uv.toml") && !fs.existsSync("pyproject.toml")) {
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 addUvToPath(cachedPath: string): void { function addUvToPath(cachedPath: string): void {
core.addPath(cachedPath); core.addPath(cachedPath);
core.info(`Added ${cachedPath} to the path`); core.info(`Added ${cachedPath} to the path`);

View File

@ -2,6 +2,8 @@ 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 checkSum = core.getInput("checksum"); export const checkSum = core.getInput("checksum");
export const enableCache = getEnableCache(); export const enableCache = getEnableCache();

38
src/utils/pyproject.ts Normal file
View File

@ -0,0 +1,38 @@
import fs from "node:fs";
import * as core from "@actions/core";
import * as toml from "@iarna/toml";
export function getUvVersionFromConfigFile(
filePath: string,
): string | undefined {
if (!fs.existsSync(filePath)) {
core.warning(`Could not find file: ${filePath}`);
return undefined;
}
let requiredVersion = getRequiredVersion(filePath);
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: string): string | undefined {
const fileContent = fs.readFileSync(filePath, "utf-8");
if (filePath.endsWith("pyproject.toml")) {
const tomlContent = toml.parse(fileContent) as {
tool?: { uv?: { "required-version"?: string } };
};
return tomlContent?.tool?.uv?.["required-version"];
}
const tomlContent = toml.parse(fileContent) as {
"required-version"?: string;
};
return tomlContent["required-version"];
}