mirror of
https://github.com/astral-sh/setup-uv.git
synced 2026-08-25 11:33:53 +00:00
Read Python version from .tool-versions (#996)
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3.x]) (push) Failing after 5m27s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3]) (push) Failing after 5m28s
test / test-specific-version (map[expected-version:0.4.30 version-input:>=0.4.25,<0.5]) (push) Failing after 5m28s
test / test-specific-version (map[expected-version:0.1.0 resolution-strategy:lowest version-input:>=0.1.0,<0.2]) (push) Failing after 5m29s
test / test-uv-no-modify-path (push) Failing after 5m29s
test / test-specific-version (map[expected-version:0.3.2 version-input:0.3.2]) (push) Failing after 5m30s
test / test-specific-version (map[expected-version:0.3.0 version-input:0.3.0]) (push) Failing after 5m33s
test / test-specific-version (map[expected-version:0.1.45 resolution-strategy:highest version-input:>=0.1,<0.2]) (push) Failing after 5m35s
test / test-latest-version (>=0.8) (push) Failing after 5m38s
test / test-default-version (ubuntu-latest) (push) Failing after 5m43s
test / test-latest-version (latest) (push) Failing after 5m42s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25]) (push) Failing after 5m44s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25,<0.5]) (push) Failing after 5m45s
test / test-from-working-directory-version (map[expected-version:0.5.14 working-directory:__tests__/fixtures/pyproject-toml-project]) (push) Failing after 5m45s
test / test-from-working-directory-version (map[expected-version:0.5.15 working-directory:__tests__/fixtures/uv-toml-project]) (push) Failing after 9m29s
test / test-activate-environment-no-project (push) Failing after 9m12s
test / test-activate-environment (ubuntu-latest) (push) Failing after 9m14s
test / test-version-file-version (map[expected-version:0.6.17 version-file:__tests__/fixtures/uv-in-requirements-txt-project/requirements.txt]) (push) Failing after 9m31s
test / test-python-version (ubuntu-latest) (push) Failing after 9m15s
test / test-activate-environment-custom-path (ubuntu-latest) (push) Failing after 9m15s
test / test-tool-install (ubuntu-latest) (push) Failing after 9m21s
test / test-malformed-pyproject-file-fallback (push) Failing after 9m34s
test / test-with-explicit-token (push) Failing after 9m35s
test / test-tool-versions-python-version (push) Failing after 9m44s
test / test-version-file-version (map[expected-version:0.5.15 version-file:__tests__/fixtures/.tool-versions]) (push) Failing after 9m45s
test / test-checksum (map[checksum:4d9279ad5ca596b1e2d703901d508430eb07564dc4d8837de9e2fca9c90f8ecd os:ubuntu-latest]) (push) Failing after 9m40s
test / test-setup-cache-dependency-glob (push) Failing after 52s
test / test-cache-local-cache-disabled (push) Failing after 43s
test / test-restore-cache-dependency-glob (push) Skipped
test / test-relative-path (push) Failing after 48s
test / test-cache-python-missing-managed-install-dir (push) Failing after 39s
test / test-python-install-dir (map[expected-python-dir:/home/runner/work/_temp/uv-python-dir os:ubuntu-latest]) (push) Failing after 38s
test / test-workflow-run (push) Failing after 36s
test / test-cache-dir-from-file (push) Failing after 45s
test / test-uvx (push) Failing after 9m35s
test / test-version-file-version (map[expected-version:0.8.3 version-file:__tests__/fixtures/uv-in-requirements-hash-txt-project/requirements.txt]) (push) Failing after 9m47s
test / test-cache-key-os-version (ubuntu-22.04, ubuntu-22.04) (push) Failing after 29s
test / test-musl (push) Failing after 47s
test / test-debian-unstable (push) Failing after 54s
test / test-setup-cache-requirements-txt (push) Failing after 52s
test / test-restore-cache-requirements-txt (push) Skipped
test / test-cache-local (map[expected-cache-dir:/home/runner/work/_temp/setup-uv-cache os:ubuntu-latest]) (push) Failing after 46s
test / test-setup-cache-restore-cache-false (push) Failing after 47s
test / test-restore-cache-restore-cache-false (push) Skipped
test / test-setup-cache-save-cache-false (push) Failing after 51s
test / test-restore-cache-save-cache-false (push) Skipped
test / test-custom-manifest-file (push) Failing after 38s
test / test-cache-prune-force (push) Failing after 41s
test / test-act (push) Failing after 37s
test / test-restore-python-installs (push) Skipped
test / test-setup-cache (auto, ubuntu-latest) (push) Failing after 39s
test / test-setup-cache (false, ubuntu-latest) (push) Failing after 47s
test / test-setup-cache (true, ubuntu-latest) (push) Failing after 52s
test / test-cache-local-cache-disabled-but-explicit-path (push) Failing after 49s
test / test-no-python-version (push) Failing after 54s
test / test-download-from-astral-mirror-false (push) Failing after 39s
test / test-absolute-path (push) Failing after 38s
test / validate-typings (push) Successful in 38s
test / test-cache-python-installs (push) Failing after 43s
CodeQL / Analyze (TypeScript) (push) Failing after 1h6m30s
test / lint (push) Failing after 2h14m39s
test / test-default-version (macos-14) (push) Canceled after 0s
test / test-default-version (macos-latest) (push) Canceled after 0s
test / test-default-version (windows-latest) (push) Canceled after 0s
test / test-checksum (map[checksum:a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218 os:macos-latest]) (push) Canceled after 0s
test / test-tool-install (macos-14) (push) Canceled after 0s
test / test-tool-install (macos-latest) (push) Canceled after 0s
test / test-tool-install (windows-latest) (push) Canceled after 0s
test / test-python-version (macos-latest) (push) Canceled after 0s
test / test-python-version (windows-latest) (push) Canceled after 0s
test / test-activate-environment (macos-latest) (push) Canceled after 0s
test / test-activate-environment (windows-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (macos-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (windows-latest) (push) Canceled after 0s
test / test-cache-key-os-version (macos-14, macos-14) (push) Canceled after 0s
test / test-cache-key-os-version (macos-15, macos-15) (push) Canceled after 0s
test / test-cache-key-os-version (ubuntu-24.04, ubuntu-24.04) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2022, windows-2022) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2025, windows-2025) (push) Canceled after 0s
test / test-setup-cache (auto, windows-latest) (push) Canceled after 0s
test / test-setup-cache (false, windows-latest) (push) Canceled after 0s
test / test-setup-cache (true, windows-latest) (push) Canceled after 0s
test / test-restore-cache (auto, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (auto, windows-latest) (push) Canceled after 0s
test / test-restore-cache (false, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (false, windows-latest) (push) Canceled after 0s
test / test-restore-cache (true, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (true, windows-latest) (push) Canceled after 0s
test / test-cache-local (map[expected-cache-dir:D:\a\_temp\setup-uv-cache os:windows-latest]) (push) Canceled after 0s
test / test-python-install-dir (map[expected-python-dir:D:\a\_temp\uv-python-dir os:windows-latest]) (push) Canceled after 0s
test / all-tests-passed (push) Canceled after 0s
Release Drafter / ✏️ Draft release (push) Canceled after 0s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3.x]) (push) Failing after 5m27s
test / test-specific-version (map[expected-version:0.3.5 version-input:0.3]) (push) Failing after 5m28s
test / test-specific-version (map[expected-version:0.4.30 version-input:>=0.4.25,<0.5]) (push) Failing after 5m28s
test / test-specific-version (map[expected-version:0.1.0 resolution-strategy:lowest version-input:>=0.1.0,<0.2]) (push) Failing after 5m29s
test / test-uv-no-modify-path (push) Failing after 5m29s
test / test-specific-version (map[expected-version:0.3.2 version-input:0.3.2]) (push) Failing after 5m30s
test / test-specific-version (map[expected-version:0.3.0 version-input:0.3.0]) (push) Failing after 5m33s
test / test-specific-version (map[expected-version:0.1.45 resolution-strategy:highest version-input:>=0.1,<0.2]) (push) Failing after 5m35s
test / test-latest-version (>=0.8) (push) Failing after 5m38s
test / test-default-version (ubuntu-latest) (push) Failing after 5m43s
test / test-latest-version (latest) (push) Failing after 5m42s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25]) (push) Failing after 5m44s
test / test-specific-version (map[expected-version:0.4.25 resolution-strategy:lowest version-input:>=0.4.25,<0.5]) (push) Failing after 5m45s
test / test-from-working-directory-version (map[expected-version:0.5.14 working-directory:__tests__/fixtures/pyproject-toml-project]) (push) Failing after 5m45s
test / test-from-working-directory-version (map[expected-version:0.5.15 working-directory:__tests__/fixtures/uv-toml-project]) (push) Failing after 9m29s
test / test-activate-environment-no-project (push) Failing after 9m12s
test / test-activate-environment (ubuntu-latest) (push) Failing after 9m14s
test / test-version-file-version (map[expected-version:0.6.17 version-file:__tests__/fixtures/uv-in-requirements-txt-project/requirements.txt]) (push) Failing after 9m31s
test / test-python-version (ubuntu-latest) (push) Failing after 9m15s
test / test-activate-environment-custom-path (ubuntu-latest) (push) Failing after 9m15s
test / test-tool-install (ubuntu-latest) (push) Failing after 9m21s
test / test-malformed-pyproject-file-fallback (push) Failing after 9m34s
test / test-with-explicit-token (push) Failing after 9m35s
test / test-tool-versions-python-version (push) Failing after 9m44s
test / test-version-file-version (map[expected-version:0.5.15 version-file:__tests__/fixtures/.tool-versions]) (push) Failing after 9m45s
test / test-checksum (map[checksum:4d9279ad5ca596b1e2d703901d508430eb07564dc4d8837de9e2fca9c90f8ecd os:ubuntu-latest]) (push) Failing after 9m40s
test / test-setup-cache-dependency-glob (push) Failing after 52s
test / test-cache-local-cache-disabled (push) Failing after 43s
test / test-restore-cache-dependency-glob (push) Skipped
test / test-relative-path (push) Failing after 48s
test / test-cache-python-missing-managed-install-dir (push) Failing after 39s
test / test-python-install-dir (map[expected-python-dir:/home/runner/work/_temp/uv-python-dir os:ubuntu-latest]) (push) Failing after 38s
test / test-workflow-run (push) Failing after 36s
test / test-cache-dir-from-file (push) Failing after 45s
test / test-uvx (push) Failing after 9m35s
test / test-version-file-version (map[expected-version:0.8.3 version-file:__tests__/fixtures/uv-in-requirements-hash-txt-project/requirements.txt]) (push) Failing after 9m47s
test / test-cache-key-os-version (ubuntu-22.04, ubuntu-22.04) (push) Failing after 29s
test / test-musl (push) Failing after 47s
test / test-debian-unstable (push) Failing after 54s
test / test-setup-cache-requirements-txt (push) Failing after 52s
test / test-restore-cache-requirements-txt (push) Skipped
test / test-cache-local (map[expected-cache-dir:/home/runner/work/_temp/setup-uv-cache os:ubuntu-latest]) (push) Failing after 46s
test / test-setup-cache-restore-cache-false (push) Failing after 47s
test / test-restore-cache-restore-cache-false (push) Skipped
test / test-setup-cache-save-cache-false (push) Failing after 51s
test / test-restore-cache-save-cache-false (push) Skipped
test / test-custom-manifest-file (push) Failing after 38s
test / test-cache-prune-force (push) Failing after 41s
test / test-act (push) Failing after 37s
test / test-restore-python-installs (push) Skipped
test / test-setup-cache (auto, ubuntu-latest) (push) Failing after 39s
test / test-setup-cache (false, ubuntu-latest) (push) Failing after 47s
test / test-setup-cache (true, ubuntu-latest) (push) Failing after 52s
test / test-cache-local-cache-disabled-but-explicit-path (push) Failing after 49s
test / test-no-python-version (push) Failing after 54s
test / test-download-from-astral-mirror-false (push) Failing after 39s
test / test-absolute-path (push) Failing after 38s
test / validate-typings (push) Successful in 38s
test / test-cache-python-installs (push) Failing after 43s
CodeQL / Analyze (TypeScript) (push) Failing after 1h6m30s
test / lint (push) Failing after 2h14m39s
test / test-default-version (macos-14) (push) Canceled after 0s
test / test-default-version (macos-latest) (push) Canceled after 0s
test / test-default-version (windows-latest) (push) Canceled after 0s
test / test-checksum (map[checksum:a70cbfbf3bb5c08b2f84963b4f12c94e08fbb2468ba418a3bfe1066fbe9e7218 os:macos-latest]) (push) Canceled after 0s
test / test-tool-install (macos-14) (push) Canceled after 0s
test / test-tool-install (macos-latest) (push) Canceled after 0s
test / test-tool-install (windows-latest) (push) Canceled after 0s
test / test-python-version (macos-latest) (push) Canceled after 0s
test / test-python-version (windows-latest) (push) Canceled after 0s
test / test-activate-environment (macos-latest) (push) Canceled after 0s
test / test-activate-environment (windows-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (macos-latest) (push) Canceled after 0s
test / test-activate-environment-custom-path (windows-latest) (push) Canceled after 0s
test / test-cache-key-os-version (macos-14, macos-14) (push) Canceled after 0s
test / test-cache-key-os-version (macos-15, macos-15) (push) Canceled after 0s
test / test-cache-key-os-version (ubuntu-24.04, ubuntu-24.04) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2022, windows-2022) (push) Canceled after 0s
test / test-cache-key-os-version (windows-2025, windows-2025) (push) Canceled after 0s
test / test-setup-cache (auto, windows-latest) (push) Canceled after 0s
test / test-setup-cache (false, windows-latest) (push) Canceled after 0s
test / test-setup-cache (true, windows-latest) (push) Canceled after 0s
test / test-restore-cache (auto, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (auto, windows-latest) (push) Canceled after 0s
test / test-restore-cache (false, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (false, windows-latest) (push) Canceled after 0s
test / test-restore-cache (true, ubuntu-latest) (push) Canceled after 0s
test / test-restore-cache (true, windows-latest) (push) Canceled after 0s
test / test-cache-local (map[expected-cache-dir:D:\a\_temp\setup-uv-cache os:windows-latest]) (push) Canceled after 0s
test / test-python-install-dir (map[expected-python-dir:D:\a\_temp\uv-python-dir os:windows-latest]) (push) Canceled after 0s
test / all-tests-passed (push) Canceled after 0s
Release Drafter / ✏️ Draft release (push) Canceled after 0s
## Summary - read the Python version from an explicitly selected `.tool-versions` file - preserve `python-version` and existing `UV_PYTHON` precedence - add parser, input, and workflow coverage and update documentation and bundled action artifacts ## Validation - `npm run all` - `actionlint .github/workflows/test.yml` - `uvx zizmor .github/workflows/test.yml` Closes #983 Refs: pi-session 019ff01a-544c-79f3-8f73-a00132af39f5
This commit is contained in:
@@ -234,6 +234,31 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
test-tool-versions-python-version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Install versions from .tool-versions
|
||||||
|
id: setup-uv
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
version-file: "__tests__/fixtures/.tool-versions"
|
||||||
|
- name: Verify Python version from .tool-versions
|
||||||
|
run: |
|
||||||
|
if [ "$UV_PYTHON" != "3.13.1t" ]; then
|
||||||
|
echo "Wrong UV_PYTHON: $UV_PYTHON"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$PYTHON_VERSION" != "3.13.1t" ]; then
|
||||||
|
echo "Wrong python-version output: $PYTHON_VERSION"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
PYTHON_VERSION: ${{ steps.setup-uv.outputs.python-version }}
|
||||||
|
|
||||||
test-malformed-pyproject-file-fallback:
|
test-malformed-pyproject-file-fallback:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -1126,6 +1151,7 @@ jobs:
|
|||||||
- test-from-working-directory-version
|
- test-from-working-directory-version
|
||||||
- test-malformed-pyproject-file-fallback
|
- test-malformed-pyproject-file-fallback
|
||||||
- test-version-file-version
|
- test-version-file-version
|
||||||
|
- test-tool-versions-python-version
|
||||||
- test-checksum
|
- test-checksum
|
||||||
- test-with-explicit-token
|
- test-with-explicit-token
|
||||||
- test-uvx
|
- test-uvx
|
||||||
|
|||||||
@@ -47,13 +47,13 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
|||||||
# The version of uv to install, e.g., "0.5.0", "latest", or "latest-known" (default: searches for version in config files, then latest)
|
# The version of uv to install, e.g., "0.5.0", "latest", or "latest-known" (default: searches for version in config files, then latest)
|
||||||
version: ""
|
version: ""
|
||||||
|
|
||||||
# Path to a file containing the version of uv to install, e.g., uv.toml, pyproject.toml, .tool-versions, requirements.txt or uv.lock (default: searches uv.toml then pyproject.toml)
|
# Path to a file containing the version of uv to install, e.g., uv.toml, pyproject.toml, .tool-versions, requirements.txt or uv.lock. A selected .tool-versions file can also provide the Python version (default: searches uv.toml then pyproject.toml)
|
||||||
version-file: ""
|
version-file: ""
|
||||||
|
|
||||||
# Resolution strategy when resolving version ranges: 'highest' or 'lowest'
|
# Resolution strategy when resolving version ranges: 'highest' or 'lowest'
|
||||||
resolution-strategy: "highest"
|
resolution-strategy: "highest"
|
||||||
|
|
||||||
# The version of Python to set UV_PYTHON to
|
# The version of Python to set UV_PYTHON to (overrides the Python version from .tool-versions)
|
||||||
python-version: ""
|
python-version: ""
|
||||||
|
|
||||||
# Use uv venv to activate a venv ready to be used by later steps
|
# Use uv venv to activate a venv ready to be used by later steps
|
||||||
@@ -144,7 +144,25 @@ Have a look under [Advanced Configuration](#advanced-configuration) for detailed
|
|||||||
|
|
||||||
You can use the input `python-version` to set the environment variable `UV_PYTHON` for the rest of your workflow
|
You can use the input `python-version` to set the environment variable `UV_PYTHON` 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`, `.python-version`, and
|
||||||
|
an explicitly selected `.tool-versions` file.
|
||||||
|
|
||||||
|
When `version-file` points to `.tool-versions`, its `python` entry is used if neither
|
||||||
|
`python-version` nor `UV_PYTHON` is set:
|
||||||
|
|
||||||
|
```text
|
||||||
|
uv 0.12.3
|
||||||
|
python 3.13
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
||||||
|
with:
|
||||||
|
version-file: ".tool-versions"
|
||||||
|
```
|
||||||
|
|
||||||
|
Only a single Python version is supported. Multiple fallback versions and the asdf `ref:`, `path:`,
|
||||||
|
and `system` forms are ignored with a warning.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Install the latest version of uv and set the python version to 3.13t
|
- name: Install the latest version of uv and set the python version to 3.13t
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
uv 0.5.15
|
uv 0.5.15
|
||||||
|
python 3.13.1t
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const ORIGINAL_HOME = process.env.HOME;
|
|||||||
const ORIGINAL_RUNNER_ENVIRONMENT = process.env.RUNNER_ENVIRONMENT;
|
const ORIGINAL_RUNNER_ENVIRONMENT = process.env.RUNNER_ENVIRONMENT;
|
||||||
const ORIGINAL_RUNNER_TEMP = process.env.RUNNER_TEMP;
|
const ORIGINAL_RUNNER_TEMP = process.env.RUNNER_TEMP;
|
||||||
const ORIGINAL_UV_CACHE_DIR = process.env.UV_CACHE_DIR;
|
const ORIGINAL_UV_CACHE_DIR = process.env.UV_CACHE_DIR;
|
||||||
|
const ORIGINAL_UV_PYTHON = process.env.UV_PYTHON;
|
||||||
const ORIGINAL_UV_PYTHON_INSTALL_DIR = process.env.UV_PYTHON_INSTALL_DIR;
|
const ORIGINAL_UV_PYTHON_INSTALL_DIR = process.env.UV_PYTHON_INSTALL_DIR;
|
||||||
|
|
||||||
const mockDebug = jest.fn();
|
const mockDebug = jest.fn();
|
||||||
@@ -60,6 +61,7 @@ function resetEnvironment(): void {
|
|||||||
delete process.env.RUNNER_ENVIRONMENT;
|
delete process.env.RUNNER_ENVIRONMENT;
|
||||||
delete process.env.RUNNER_TEMP;
|
delete process.env.RUNNER_TEMP;
|
||||||
delete process.env.UV_CACHE_DIR;
|
delete process.env.UV_CACHE_DIR;
|
||||||
|
delete process.env.UV_PYTHON;
|
||||||
delete process.env.UV_PYTHON_INSTALL_DIR;
|
delete process.env.UV_PYTHON_INSTALL_DIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +76,7 @@ function restoreEnvironment(): void {
|
|||||||
process.env.RUNNER_ENVIRONMENT = ORIGINAL_RUNNER_ENVIRONMENT;
|
process.env.RUNNER_ENVIRONMENT = ORIGINAL_RUNNER_ENVIRONMENT;
|
||||||
process.env.RUNNER_TEMP = ORIGINAL_RUNNER_TEMP;
|
process.env.RUNNER_TEMP = ORIGINAL_RUNNER_TEMP;
|
||||||
process.env.UV_CACHE_DIR = ORIGINAL_UV_CACHE_DIR;
|
process.env.UV_CACHE_DIR = ORIGINAL_UV_CACHE_DIR;
|
||||||
|
process.env.UV_PYTHON = ORIGINAL_UV_PYTHON;
|
||||||
process.env.UV_PYTHON_INSTALL_DIR = ORIGINAL_UV_PYTHON_INSTALL_DIR;
|
process.env.UV_PYTHON_INSTALL_DIR = ORIGINAL_UV_PYTHON_INSTALL_DIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +103,52 @@ describe("loadInputs", () => {
|
|||||||
expect(inputs.resolutionStrategy).toBe("highest");
|
expect(inputs.resolutionStrategy).toBe("highest");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the Python version from an explicitly selected .tool-versions file", () => {
|
||||||
|
mockInputs["working-directory"] = createTempProject({
|
||||||
|
".tool-versions": "uv 0.12.3\npython 3.13.1t\n",
|
||||||
|
});
|
||||||
|
mockInputs["version-file"] = ".tool-versions";
|
||||||
|
|
||||||
|
const inputs = loadInputs();
|
||||||
|
|
||||||
|
expect(inputs.pythonVersion).toBe("3.13.1t");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("prefers the python-version input over .tool-versions", () => {
|
||||||
|
mockInputs["working-directory"] = createTempProject({
|
||||||
|
".tool-versions": "uv 0.12.3\npython 3.13\n",
|
||||||
|
});
|
||||||
|
mockInputs["version-file"] = ".tool-versions";
|
||||||
|
mockInputs["python-version"] = "3.12";
|
||||||
|
|
||||||
|
const inputs = loadInputs();
|
||||||
|
|
||||||
|
expect(inputs.pythonVersion).toBe("3.12");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves UV_PYTHON instead of overriding it from .tool-versions", () => {
|
||||||
|
mockInputs["working-directory"] = createTempProject({
|
||||||
|
".tool-versions": "uv 0.12.3\npython 3.13\n",
|
||||||
|
});
|
||||||
|
mockInputs["version-file"] = ".tool-versions";
|
||||||
|
process.env.UV_PYTHON = "3.11";
|
||||||
|
|
||||||
|
const inputs = loadInputs();
|
||||||
|
|
||||||
|
expect(inputs.pythonVersion).toBe("");
|
||||||
|
expect(process.env.UV_PYTHON).toBe("3.11");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not discover .tool-versions from the working directory", () => {
|
||||||
|
mockInputs["working-directory"] = createTempProject({
|
||||||
|
".tool-versions": "uv 0.12.3\npython 3.13\n",
|
||||||
|
});
|
||||||
|
|
||||||
|
const inputs = loadInputs();
|
||||||
|
|
||||||
|
expect(inputs.pythonVersion).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
it.each(["pull_request_target", "workflow_run", "release"])(
|
it.each(["pull_request_target", "workflow_run", "release"])(
|
||||||
"disables automatic caching for the %s event",
|
"disables automatic caching for the %s event",
|
||||||
(eventName) => {
|
(eventName) => {
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ async function getVersionFromToolVersions(filePath: string) {
|
|||||||
return getUvVersionFromToolVersions(filePath);
|
return getUvVersionFromToolVersions(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getPythonVersionFromToolVersions(filePath: string) {
|
||||||
|
const module = await import("../../src/version/tool-versions-file");
|
||||||
|
return module.getPythonVersionFromToolVersions(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
describe("getUvVersionFromToolVersions", () => {
|
describe("getUvVersionFromToolVersions", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
@@ -61,8 +66,8 @@ describe("getUvVersionFromToolVersions", () => {
|
|||||||
expect(result).toBe("0.3.0");
|
expect(result).toBe("0.3.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should skip commented lines", async () => {
|
it("should skip comments", async () => {
|
||||||
const fileContent = "# uv 0.1.0\npython 3.11.0\nuv 0.2.0";
|
const fileContent = "# uv 0.1.0\npython 3.11.0\nuv 0.2.0 # inline comment";
|
||||||
mockReadFileSync.mockReturnValue(fileContent);
|
mockReadFileSync.mockReturnValue(fileContent);
|
||||||
|
|
||||||
const result = await getVersionFromToolVersions(".tool-versions");
|
const result = await getVersionFromToolVersions(".tool-versions");
|
||||||
@@ -121,3 +126,68 @@ describe("getUvVersionFromToolVersions", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getPythonVersionFromToolVersions", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return version for a valid Python entry", async () => {
|
||||||
|
mockReadFileSync.mockReturnValue(
|
||||||
|
"nodejs 24.0.0\r\npython v3.13.1t # use free-threaded Python\r\nuv 0.12.3",
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await getPythonVersionFromToolVersions(".tool-versions");
|
||||||
|
|
||||||
|
expect(result).toBe("3.13.1t");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the first matching Python version", async () => {
|
||||||
|
mockReadFileSync.mockReturnValue("python 3.12\npython 3.13");
|
||||||
|
|
||||||
|
const result = await getPythonVersionFromToolVersions(".tool-versions");
|
||||||
|
|
||||||
|
expect(result).toBe("3.12");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return undefined when no Python entry is found", async () => {
|
||||||
|
mockReadFileSync.mockReturnValue("uv 0.12.3\nnodejs 24.0.0");
|
||||||
|
|
||||||
|
const result = await getPythonVersionFromToolVersions(".tool-versions");
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should warn and return undefined for multiple Python versions", async () => {
|
||||||
|
mockReadFileSync.mockReturnValue("python 3.13 3.12 system");
|
||||||
|
|
||||||
|
const result = await getPythonVersionFromToolVersions(".tool-versions");
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
expect(mockWarning).toHaveBeenCalledWith(
|
||||||
|
"Multiple Python versions in .tool-versions are not supported. The Python entry will be ignored.",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(["ref:main", "path:~/src/python", "system"])(
|
||||||
|
"should warn and return undefined for %s",
|
||||||
|
async (version) => {
|
||||||
|
mockReadFileSync.mockReturnValue(`python ${version}`);
|
||||||
|
|
||||||
|
const result = await getPythonVersionFromToolVersions(".tool-versions");
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
expect(mockWarning).toHaveBeenCalledWith(
|
||||||
|
`The Python version ${version} in .tool-versions is not supported. The Python entry will be ignored.`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it("should return undefined for non-.tool-versions files", async () => {
|
||||||
|
const result = await getPythonVersionFromToolVersions(".python-version");
|
||||||
|
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
expect(mockReadFileSync).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
+2
-2
@@ -7,10 +7,10 @@ inputs:
|
|||||||
description: "The version of uv to install, e.g., `0.5.0`, `latest`, or `latest-known`. Defaults to the version in pyproject.toml or `latest`."
|
description: "The version of uv to install, e.g., `0.5.0`, `latest`, or `latest-known`. Defaults to the version in pyproject.toml or `latest`."
|
||||||
default: ""
|
default: ""
|
||||||
version-file:
|
version-file:
|
||||||
description: "Path to a file containing the version of uv to install, e.g., uv.toml, pyproject.toml, .tool-versions, requirements.txt or uv.lock. Defaults to searching for uv.toml and if not found pyproject.toml."
|
description: "Path to a file containing the version of uv to install, e.g., uv.toml, pyproject.toml, .tool-versions, requirements.txt or uv.lock. A selected .tool-versions file can also provide the Python version. Defaults to searching for uv.toml and if not found pyproject.toml."
|
||||||
default: ""
|
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. Overrides the Python version from .tool-versions."
|
||||||
required: false
|
required: false
|
||||||
activate-environment:
|
activate-environment:
|
||||||
description: "Use uv venv to activate a venv ready to be used by later steps. "
|
description: "Use uv venv to activate a venv ready to be used by later steps. "
|
||||||
|
|||||||
+71
-7
@@ -26998,7 +26998,7 @@ __export(save_cache_exports, {
|
|||||||
run: () => run
|
run: () => run
|
||||||
});
|
});
|
||||||
module.exports = __toCommonJS(save_cache_exports);
|
module.exports = __toCommonJS(save_cache_exports);
|
||||||
var fs7 = __toESM(require("node:fs"), 1);
|
var fs9 = __toESM(require("node:fs"), 1);
|
||||||
|
|
||||||
// node_modules/@actions/core/lib/command.js
|
// node_modules/@actions/core/lib/command.js
|
||||||
var os = __toESM(require("os"), 1);
|
var os = __toESM(require("os"), 1);
|
||||||
@@ -61845,10 +61845,54 @@ var STATE_UV_PATH = "uv-path";
|
|||||||
var STATE_UV_VERSION = "uv-version";
|
var STATE_UV_VERSION = "uv-version";
|
||||||
|
|
||||||
// src/utils/inputs.ts
|
// src/utils/inputs.ts
|
||||||
|
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
||||||
var import_node_path = __toESM(require("node:path"), 1);
|
var import_node_path = __toESM(require("node:path"), 1);
|
||||||
|
|
||||||
// src/utils/config-file.ts
|
// src/version/tool-versions-file.ts
|
||||||
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
var import_node_fs2 = __toESM(require("node:fs"), 1);
|
||||||
|
function getPythonVersionFromToolVersions(filePath) {
|
||||||
|
const versions = getToolVersions(filePath, "python");
|
||||||
|
if (versions === void 0 || versions.length === 0) {
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
if (versions.length > 1) {
|
||||||
|
warning(
|
||||||
|
"Multiple Python versions in .tool-versions are not supported. The Python entry will be ignored."
|
||||||
|
);
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
const version3 = stripVersionPrefix(versions[0]);
|
||||||
|
if (version3 === "system" || version3.startsWith("ref:") || version3.startsWith("path:")) {
|
||||||
|
warning(
|
||||||
|
`The Python version ${versions[0]} in .tool-versions is not supported. The Python entry will be ignored.`
|
||||||
|
);
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
return version3;
|
||||||
|
}
|
||||||
|
function getToolVersions(filePath, toolName) {
|
||||||
|
if (!filePath.endsWith(".tool-versions")) {
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
const fileContents = import_node_fs2.default.readFileSync(filePath, "utf8");
|
||||||
|
for (const line of fileContents.split("\n")) {
|
||||||
|
const content = line.split("#", 1)[0].trim();
|
||||||
|
if (content === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const [tool, ...versions] = content.split(/\s+/);
|
||||||
|
if (tool === toolName) {
|
||||||
|
return versions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
function stripVersionPrefix(version3) {
|
||||||
|
return version3.startsWith("v") ? version3.slice(1) : version3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// src/utils/config-file.ts
|
||||||
|
var import_node_fs3 = __toESM(require("node:fs"), 1);
|
||||||
|
|
||||||
// node_modules/smol-toml/dist/date.js
|
// node_modules/smol-toml/dist/date.js
|
||||||
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
|
||||||
@@ -62532,10 +62576,10 @@ function parse3(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
|
|||||||
|
|
||||||
// src/utils/config-file.ts
|
// src/utils/config-file.ts
|
||||||
function getConfigValueFromTomlFile(filePath, key) {
|
function getConfigValueFromTomlFile(filePath, key) {
|
||||||
if (!import_node_fs2.default.existsSync(filePath) || !filePath.endsWith(".toml")) {
|
if (!import_node_fs3.default.existsSync(filePath) || !filePath.endsWith(".toml")) {
|
||||||
return void 0;
|
return void 0;
|
||||||
}
|
}
|
||||||
const fileContent = import_node_fs2.default.readFileSync(filePath, "utf-8");
|
const fileContent = import_node_fs3.default.readFileSync(filePath, "utf-8");
|
||||||
return getConfigValueFromTomlContent(filePath, fileContent, key);
|
return getConfigValueFromTomlContent(filePath, fileContent, key);
|
||||||
}
|
}
|
||||||
function getConfigValueFromTomlContent(filePath, fileContent, key) {
|
function getConfigValueFromTomlContent(filePath, fileContent, key) {
|
||||||
@@ -62555,7 +62599,7 @@ function loadInputs() {
|
|||||||
const workingDirectory = getInput("working-directory");
|
const workingDirectory = getInput("working-directory");
|
||||||
const version3 = getInput("version");
|
const version3 = getInput("version");
|
||||||
const versionFile = getVersionFile(workingDirectory);
|
const versionFile = getVersionFile(workingDirectory);
|
||||||
const pythonVersion = getInput("python-version");
|
const pythonVersion = getPythonVersion(versionFile);
|
||||||
const activateEnvironment = getBooleanInput("activate-environment");
|
const activateEnvironment = getBooleanInput("activate-environment");
|
||||||
const noProject = getBooleanInput("no-project");
|
const noProject = getBooleanInput("no-project");
|
||||||
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
||||||
@@ -62621,6 +62665,26 @@ function getVersionFile(workingDirectory) {
|
|||||||
}
|
}
|
||||||
return versionFileInput;
|
return versionFileInput;
|
||||||
}
|
}
|
||||||
|
function getPythonVersion(versionFile) {
|
||||||
|
const pythonVersionInput = getInput("python-version");
|
||||||
|
if (pythonVersionInput !== "") {
|
||||||
|
return pythonVersionInput;
|
||||||
|
}
|
||||||
|
if (process.env.UV_PYTHON !== void 0 && process.env.UV_PYTHON !== "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (versionFile === "" || !import_node_fs4.default.existsSync(versionFile)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return getPythonVersionFromToolVersions(versionFile) ?? "";
|
||||||
|
} catch (err) {
|
||||||
|
warning2(
|
||||||
|
`Error while parsing Python version from ${versionFile}: ${err.message}`
|
||||||
|
);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
function getVenvPath(workingDirectory, activateEnvironment) {
|
function getVenvPath(workingDirectory, activateEnvironment) {
|
||||||
const venvPathInput = getInput("venv-path");
|
const venvPathInput = getInput("venv-path");
|
||||||
if (venvPathInput !== "") {
|
if (venvPathInput !== "") {
|
||||||
@@ -62864,7 +62928,7 @@ async function saveCache3(inputs) {
|
|||||||
await pruneCache();
|
await pruneCache();
|
||||||
}
|
}
|
||||||
const actualCachePath = getUvCachePath(inputs);
|
const actualCachePath = getUvCachePath(inputs);
|
||||||
if (!fs7.existsSync(actualCachePath)) {
|
if (!fs9.existsSync(actualCachePath)) {
|
||||||
if (inputs.ignoreNothingToCache) {
|
if (inputs.ignoreNothingToCache) {
|
||||||
info2(
|
info2(
|
||||||
"No cacheable uv cache paths were found. Ignoring because ignore-nothing-to-cache is enabled."
|
"No cacheable uv cache paths were found. Ignoring because ignore-nothing-to-cache is enabled."
|
||||||
@@ -62884,7 +62948,7 @@ async function saveCache3(inputs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inputs.cachePython) {
|
if (inputs.cachePython) {
|
||||||
if (!fs7.existsSync(inputs.pythonDir)) {
|
if (!fs9.existsSync(inputs.pythonDir)) {
|
||||||
warning2(
|
warning2(
|
||||||
`Python cache path ${inputs.pythonDir} does not exist on disk. Skipping Python cache save because no managed Python installation was found. If you want uv to install managed Python instead of using a system interpreter, set UV_PYTHON_PREFERENCE=only-managed.`
|
`Python cache path ${inputs.pythonDir} does not exist on disk. Skipping Python cache save because no managed Python installation was found. If you want uv to install managed Python instead of using a system interpreter, set UV_PYTHON_PREFERENCE=only-managed.`
|
||||||
);
|
);
|
||||||
|
|||||||
+68
-17
@@ -56054,7 +56054,7 @@ var require_semver5 = __commonJS({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// src/setup-uv.ts
|
// src/setup-uv.ts
|
||||||
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
var import_node_fs9 = __toESM(require("node:fs"), 1);
|
||||||
var path16 = __toESM(require("node:path"), 1);
|
var path16 = __toESM(require("node:path"), 1);
|
||||||
|
|
||||||
// node_modules/@actions/core/lib/command.js
|
// node_modules/@actions/core/lib/command.js
|
||||||
@@ -98258,29 +98258,59 @@ function getUvVersionFromDependency(dependency) {
|
|||||||
// src/version/tool-versions-file.ts
|
// src/version/tool-versions-file.ts
|
||||||
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
var import_node_fs4 = __toESM(require("node:fs"), 1);
|
||||||
function getUvVersionFromToolVersions(filePath) {
|
function getUvVersionFromToolVersions(filePath) {
|
||||||
if (!filePath.endsWith(".tool-versions")) {
|
const versions = getToolVersions(filePath, "uv");
|
||||||
|
if (versions === void 0 || versions.length !== 1) {
|
||||||
return void 0;
|
return void 0;
|
||||||
}
|
}
|
||||||
const fileContents = import_node_fs4.default.readFileSync(filePath, "utf8");
|
const version3 = stripVersionPrefix(versions[0]);
|
||||||
const lines = fileContents.split("\n");
|
if (version3.startsWith("ref")) {
|
||||||
for (const line of lines) {
|
|
||||||
if (line.trim().startsWith("#")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const match2 = line.match(/^\s*uv\s*v?\s*(?<version>[^\s]+)\s*$/);
|
|
||||||
if (match2) {
|
|
||||||
const matchedVersion = match2.groups?.version.trim();
|
|
||||||
if (matchedVersion?.startsWith("ref")) {
|
|
||||||
warning(
|
warning(
|
||||||
"The ref syntax of .tool-versions is not supported. Please use a released version instead."
|
"The ref syntax of .tool-versions is not supported. Please use a released version instead."
|
||||||
);
|
);
|
||||||
return void 0;
|
return void 0;
|
||||||
}
|
}
|
||||||
return matchedVersion;
|
return version3;
|
||||||
|
}
|
||||||
|
function getPythonVersionFromToolVersions(filePath) {
|
||||||
|
const versions = getToolVersions(filePath, "python");
|
||||||
|
if (versions === void 0 || versions.length === 0) {
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
if (versions.length > 1) {
|
||||||
|
warning(
|
||||||
|
"Multiple Python versions in .tool-versions are not supported. The Python entry will be ignored."
|
||||||
|
);
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
const version3 = stripVersionPrefix(versions[0]);
|
||||||
|
if (version3 === "system" || version3.startsWith("ref:") || version3.startsWith("path:")) {
|
||||||
|
warning(
|
||||||
|
`The Python version ${versions[0]} in .tool-versions is not supported. The Python entry will be ignored.`
|
||||||
|
);
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
return version3;
|
||||||
|
}
|
||||||
|
function getToolVersions(filePath, toolName) {
|
||||||
|
if (!filePath.endsWith(".tool-versions")) {
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
const fileContents = import_node_fs4.default.readFileSync(filePath, "utf8");
|
||||||
|
for (const line of fileContents.split("\n")) {
|
||||||
|
const content = line.split("#", 1)[0].trim();
|
||||||
|
if (content === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const [tool, ...versions] = content.split(/\s+/);
|
||||||
|
if (tool === toolName) {
|
||||||
|
return versions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return void 0;
|
return void 0;
|
||||||
}
|
}
|
||||||
|
function stripVersionPrefix(version3) {
|
||||||
|
return version3.startsWith("v") ? version3.slice(1) : version3;
|
||||||
|
}
|
||||||
|
|
||||||
// src/version/uv-lock-file.ts
|
// src/version/uv-lock-file.ts
|
||||||
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
var import_node_fs5 = __toESM(require("node:fs"), 1);
|
||||||
@@ -98734,12 +98764,13 @@ function getExtension(platform2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// src/utils/inputs.ts
|
// src/utils/inputs.ts
|
||||||
|
var import_node_fs8 = __toESM(require("node:fs"), 1);
|
||||||
var import_node_path = __toESM(require("node:path"), 1);
|
var import_node_path = __toESM(require("node:path"), 1);
|
||||||
function loadInputs() {
|
function loadInputs() {
|
||||||
const workingDirectory = getInput("working-directory");
|
const workingDirectory = getInput("working-directory");
|
||||||
const version3 = getInput("version");
|
const version3 = getInput("version");
|
||||||
const versionFile = getVersionFile(workingDirectory);
|
const versionFile = getVersionFile(workingDirectory);
|
||||||
const pythonVersion = getInput("python-version");
|
const pythonVersion = getPythonVersion(versionFile);
|
||||||
const activateEnvironment2 = getBooleanInput("activate-environment");
|
const activateEnvironment2 = getBooleanInput("activate-environment");
|
||||||
const noProject = getBooleanInput("no-project");
|
const noProject = getBooleanInput("no-project");
|
||||||
const venvPath = getVenvPath(workingDirectory, activateEnvironment2);
|
const venvPath = getVenvPath(workingDirectory, activateEnvironment2);
|
||||||
@@ -98805,6 +98836,26 @@ function getVersionFile(workingDirectory) {
|
|||||||
}
|
}
|
||||||
return versionFileInput;
|
return versionFileInput;
|
||||||
}
|
}
|
||||||
|
function getPythonVersion(versionFile) {
|
||||||
|
const pythonVersionInput = getInput("python-version");
|
||||||
|
if (pythonVersionInput !== "") {
|
||||||
|
return pythonVersionInput;
|
||||||
|
}
|
||||||
|
if (process.env.UV_PYTHON !== void 0 && process.env.UV_PYTHON !== "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (versionFile === "" || !import_node_fs8.default.existsSync(versionFile)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return getPythonVersionFromToolVersions(versionFile) ?? "";
|
||||||
|
} catch (err) {
|
||||||
|
warning2(
|
||||||
|
`Error while parsing Python version from ${versionFile}: ${err.message}`
|
||||||
|
);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
function getVenvPath(workingDirectory, activateEnvironment2) {
|
function getVenvPath(workingDirectory, activateEnvironment2) {
|
||||||
const venvPathInput = getInput("venv-path");
|
const venvPathInput = getInput("venv-path");
|
||||||
if (venvPathInput !== "") {
|
if (venvPathInput !== "") {
|
||||||
@@ -99018,7 +99069,7 @@ process.on("uncaughtException", (error2) => {
|
|||||||
process.on("unhandledRejection", (reason) => {
|
process.on("unhandledRejection", (reason) => {
|
||||||
failUnexpectedly("Unhandled promise rejection", reason);
|
failUnexpectedly("Unhandled promise rejection", reason);
|
||||||
});
|
});
|
||||||
async function getPythonVersion(inputs) {
|
async function getPythonVersion2(inputs) {
|
||||||
if (inputs.pythonVersion !== "") {
|
if (inputs.pythonVersion !== "") {
|
||||||
return inputs.pythonVersion;
|
return inputs.pythonVersion;
|
||||||
}
|
}
|
||||||
@@ -99068,7 +99119,7 @@ async function run() {
|
|||||||
setOutput("uv-version", setupResult.version);
|
setOutput("uv-version", setupResult.version);
|
||||||
saveState(STATE_UV_VERSION, setupResult.version);
|
saveState(STATE_UV_VERSION, setupResult.version);
|
||||||
info2(`Successfully installed uv version ${setupResult.version}`);
|
info2(`Successfully installed uv version ${setupResult.version}`);
|
||||||
const detectedPythonVersion = await getPythonVersion(inputs);
|
const detectedPythonVersion = await getPythonVersion2(inputs);
|
||||||
setOutput("python-version", detectedPythonVersion);
|
setOutput("python-version", detectedPythonVersion);
|
||||||
if (inputs.enableCache) {
|
if (inputs.enableCache) {
|
||||||
await restoreCache2(inputs, detectedPythonVersion);
|
await restoreCache2(inputs, detectedPythonVersion);
|
||||||
@@ -99080,7 +99131,7 @@ async function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function detectEmptyWorkdir(inputs) {
|
function detectEmptyWorkdir(inputs) {
|
||||||
if (import_node_fs8.default.readdirSync(inputs.workingDirectory).length === 0) {
|
if (import_node_fs9.default.readdirSync(inputs.workingDirectory).length === 0) {
|
||||||
if (inputs.ignoreEmptyWorkdir) {
|
if (inputs.ignoreEmptyWorkdir) {
|
||||||
info2(
|
info2(
|
||||||
"Empty workdir detected. Ignoring because ignore-empty-workdir is enabled"
|
"Empty workdir detected. Ignoring because ignore-empty-workdir is enabled"
|
||||||
|
|||||||
@@ -85,7 +85,10 @@ You can use the `version-file` input to specify a file that contains the version
|
|||||||
This can either be a `pyproject.toml` or `uv.toml` file which defines a `required-version` or
|
This can either be a `pyproject.toml` or `uv.toml` file which defines a `required-version` or
|
||||||
uv defined as a dependency in `pyproject.toml` or `requirements.txt`.
|
uv defined as a dependency in `pyproject.toml` or `requirements.txt`.
|
||||||
|
|
||||||
[asdf](https://asdf-vm.com/) `.tool-versions` is also supported, but without the `ref` syntax.
|
[asdf](https://asdf-vm.com/) `.tool-versions` is also supported for selecting uv. If neither
|
||||||
|
`python-version` nor `UV_PYTHON` is set, the `python` entry from the selected file is also exported
|
||||||
|
as `UV_PYTHON`. Only a single Python version is supported; multiple fallback versions and the asdf
|
||||||
|
`ref:`, `path:`, and `system` forms are ignored with a warning.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Install uv based on the version defined in pyproject.toml
|
- name: Install uv based on the version defined in pyproject.toml
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ If you want to ignore this, set the `ignore-empty-workdir` input to `true`.
|
|||||||
|
|
||||||
This action sets several environment variables that influence uv's behavior and can be used by subsequent steps:
|
This action sets several environment variables that influence uv's behavior and can be used by subsequent steps:
|
||||||
|
|
||||||
- `UV_PYTHON`: Set when `python-version` input is specified. Controls which Python version uv uses.
|
- `UV_PYTHON`: Set when `python-version` is specified or the selected `.tool-versions` file contains a supported `python` entry. Controls which Python version uv uses.
|
||||||
- `UV_CACHE_DIR`: Set when caching is enabled (unless already configured in uv config files). Controls where uv stores its cache.
|
- `UV_CACHE_DIR`: Set when caching is enabled (unless already configured in uv config files). Controls where uv stores its cache.
|
||||||
- `UV_TOOL_DIR`: Set when `tool-dir` input is specified. Controls where uv installs tool environments.
|
- `UV_TOOL_DIR`: Set when `tool-dir` input is specified. Controls where uv installs tool environments.
|
||||||
- `UV_TOOL_BIN_DIR`: Set when `tool-bin-dir` input is specified. Controls where uv installs tool binaries.
|
- `UV_TOOL_BIN_DIR`: Set when `tool-bin-dir` input is specified. Controls where uv installs tool binaries.
|
||||||
@@ -142,6 +142,7 @@ This action sets several environment variables that influence uv's behavior and
|
|||||||
|
|
||||||
- `UV_NO_MODIFY_PATH`: If set, prevents the action from modifying PATH. Cannot be used with `activate-environment`.
|
- `UV_NO_MODIFY_PATH`: If set, prevents the action from modifying PATH. Cannot be used with `activate-environment`.
|
||||||
- `UV_CACHE_DIR`: If already set, the action will respect it instead of setting its own cache directory.
|
- `UV_CACHE_DIR`: If already set, the action will respect it instead of setting its own cache directory.
|
||||||
|
- `UV_PYTHON`: If already set and `python-version` is not specified, the action will respect it instead of using the `python` entry from `.tool-versions`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- name: Example using environment variables
|
- name: Example using environment variables
|
||||||
|
|||||||
+25
-1
@@ -1,5 +1,7 @@
|
|||||||
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import * as core from "@actions/core";
|
import * as core from "@actions/core";
|
||||||
|
import { getPythonVersionFromToolVersions } from "../version/tool-versions-file";
|
||||||
import { getConfigValueFromTomlFile } from "./config-file";
|
import { getConfigValueFromTomlFile } from "./config-file";
|
||||||
import * as log from "./logging";
|
import * as log from "./logging";
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ export function loadInputs(): SetupInputs {
|
|||||||
const workingDirectory = core.getInput("working-directory");
|
const workingDirectory = core.getInput("working-directory");
|
||||||
const version = core.getInput("version");
|
const version = core.getInput("version");
|
||||||
const versionFile = getVersionFile(workingDirectory);
|
const versionFile = getVersionFile(workingDirectory);
|
||||||
const pythonVersion = core.getInput("python-version");
|
const pythonVersion = getPythonVersion(versionFile);
|
||||||
const activateEnvironment = core.getBooleanInput("activate-environment");
|
const activateEnvironment = core.getBooleanInput("activate-environment");
|
||||||
const noProject = core.getBooleanInput("no-project");
|
const noProject = core.getBooleanInput("no-project");
|
||||||
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
const venvPath = getVenvPath(workingDirectory, activateEnvironment);
|
||||||
@@ -122,6 +124,28 @@ function getVersionFile(workingDirectory: string): string {
|
|||||||
return versionFileInput;
|
return versionFileInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPythonVersion(versionFile: string): string {
|
||||||
|
const pythonVersionInput = core.getInput("python-version");
|
||||||
|
if (pythonVersionInput !== "") {
|
||||||
|
return pythonVersionInput;
|
||||||
|
}
|
||||||
|
if (process.env.UV_PYTHON !== undefined && process.env.UV_PYTHON !== "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (versionFile === "" || !fs.existsSync(versionFile)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getPythonVersionFromToolVersions(versionFile) ?? "";
|
||||||
|
} catch (err) {
|
||||||
|
log.warning(
|
||||||
|
`Error while parsing Python version from ${versionFile}: ${(err as Error).message}`,
|
||||||
|
);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getVenvPath(
|
function getVenvPath(
|
||||||
workingDirectory: string,
|
workingDirectory: string,
|
||||||
activateEnvironment: boolean,
|
activateEnvironment: boolean,
|
||||||
|
|||||||
@@ -4,28 +4,72 @@ import * as core from "@actions/core";
|
|||||||
export function getUvVersionFromToolVersions(
|
export function getUvVersionFromToolVersions(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!filePath.endsWith(".tool-versions")) {
|
const versions = getToolVersions(filePath, "uv");
|
||||||
|
if (versions === undefined || versions.length !== 1) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const fileContents = fs.readFileSync(filePath, "utf8");
|
|
||||||
const lines = fileContents.split("\n");
|
|
||||||
|
|
||||||
for (const line of lines) {
|
const version = stripVersionPrefix(versions[0]);
|
||||||
// Skip commented lines
|
if (version.startsWith("ref")) {
|
||||||
if (line.trim().startsWith("#")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const match = line.match(/^\s*uv\s*v?\s*(?<version>[^\s]+)\s*$/);
|
|
||||||
if (match) {
|
|
||||||
const matchedVersion = match.groups?.version.trim();
|
|
||||||
if (matchedVersion?.startsWith("ref")) {
|
|
||||||
core.warning(
|
core.warning(
|
||||||
"The ref syntax of .tool-versions is not supported. Please use a released version instead.",
|
"The ref syntax of .tool-versions is not supported. Please use a released version instead.",
|
||||||
);
|
);
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return matchedVersion;
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPythonVersionFromToolVersions(
|
||||||
|
filePath: string,
|
||||||
|
): string | undefined {
|
||||||
|
const versions = getToolVersions(filePath, "python");
|
||||||
|
if (versions === undefined || versions.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (versions.length > 1) {
|
||||||
|
core.warning(
|
||||||
|
"Multiple Python versions in .tool-versions are not supported. The Python entry will be ignored.",
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const version = stripVersionPrefix(versions[0]);
|
||||||
|
if (
|
||||||
|
version === "system" ||
|
||||||
|
version.startsWith("ref:") ||
|
||||||
|
version.startsWith("path:")
|
||||||
|
) {
|
||||||
|
core.warning(
|
||||||
|
`The Python version ${versions[0]} in .tool-versions is not supported. The Python entry will be ignored.`,
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getToolVersions(
|
||||||
|
filePath: string,
|
||||||
|
toolName: string,
|
||||||
|
): string[] | undefined {
|
||||||
|
if (!filePath.endsWith(".tool-versions")) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const fileContents = fs.readFileSync(filePath, "utf8");
|
||||||
|
|
||||||
|
for (const line of fileContents.split("\n")) {
|
||||||
|
const content = line.split("#", 1)[0].trim();
|
||||||
|
if (content === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [tool, ...versions] = content.split(/\s+/);
|
||||||
|
if (tool === toolName) {
|
||||||
|
return versions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripVersionPrefix(version: string): string {
|
||||||
|
return version.startsWith("v") ? version.slice(1) : version;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user