Implement PEP 440-compliant local version semantics #17916
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
on: | |
push: | |
branches: [main] | |
pull_request: | |
workflow_dispatch: | |
concurrency: | |
group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} | |
cancel-in-progress: true | |
env: | |
CARGO_INCREMENTAL: 0 | |
CARGO_NET_RETRY: 10 | |
CARGO_TERM_COLOR: always | |
RUSTUP_MAX_RETRIES: 10 | |
PYTHON_VERSION: "3.12" | |
jobs: | |
determine_changes: | |
name: "Determine changes" | |
runs-on: ubuntu-latest | |
outputs: | |
# Flag that is raised when any code is changed | |
code: ${{ steps.changed.outputs.code_any_changed }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: tj-actions/changed-files@v45 | |
id: changed | |
with: | |
files_yaml: | | |
code: | |
- "**/*" | |
- "!docs/**/*" | |
- "!mkdocs.*.yml" | |
- "!**/*.md" | |
- "!bin/**" | |
- "!assets/**" | |
# Generated markdown and JSON files are checked during test runs | |
- "docs/reference/cli.md" | |
- "docs/reference/settings.md" | |
- "uv.schema.json" | |
lint: | |
timeout-minutes: 10 | |
name: "lint" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: 3.12 | |
- name: "Install Rustfmt" | |
run: rustup component add rustfmt | |
- name: "Install uv" | |
uses: astral-sh/setup-uv@v3 | |
- name: "rustfmt" | |
run: cargo fmt --all --check | |
- name: "Prettier" | |
run: | | |
npx prettier --check "**/*.{json5,yaml,yml}" | |
npx prettier --prose-wrap always --check "**/*.md" | |
- name: "README check" | |
run: python scripts/transform_readme.py --target pypi | |
- name: "Python format" | |
run: uvx ruff format --diff . | |
- name: "Python lint" | |
run: uvx ruff check . | |
- name: "Python type check" | |
run: uvx mypy | |
- name: "Lint shell scripts" | |
uses: ludeeus/[email protected] | |
env: | |
# renovate: datasource=github-tags depName=koalaman/shellcheck | |
SHELLCHECK_VERSION: "v0.10.0" | |
SHELLCHECK_OPTS: --shell bash | |
with: | |
version: ${{ env.SHELLCHECK_VERSION }} | |
severity: style | |
check_together: "yes" | |
cargo-clippy: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: ubuntu-latest | |
name: "cargo clippy | ubuntu" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
save-if: ${{ github.ref == 'refs/heads/main' }} | |
- name: "Install Rust toolchain" | |
run: rustup component add clippy | |
- name: "Clippy" | |
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings | |
cargo-clippy-windows: | |
timeout-minutes: 15 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: "windows-latest-xlarge" | |
name: "cargo clippy | windows" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: Swatinem/rust-cache@v2 | |
- name: Create Dev Drive using ReFS | |
run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1 | |
# actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone... | |
- name: Copy Git Repo to Dev Drive | |
run: | | |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse | |
- name: "Install Rust toolchain" | |
run: rustup component add clippy | |
- name: "Clippy" | |
run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings | |
cargo-dev-generate-all: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: ubuntu-latest | |
name: "cargo dev generate-all" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
save-if: ${{ github.ref == 'refs/heads/main' }} | |
- name: "Generate all" | |
run: cargo dev generate-all --mode check | |
cargo-shear: | |
timeout-minutes: 10 | |
name: "cargo shear" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: cargo-bins/cargo-binstall@main | |
- run: cargo binstall --no-confirm cargo-shear | |
- run: cargo shear | |
# We use the large GitHub actions runners | |
# For Ubuntu and Windows, this requires Organization-level configuration | |
# See: https://docs.github.com/en/actions/using-github-hosted-runners/about-larger-runners/about-larger-runners#about-ubuntu-and-windows-larger-runners | |
cargo-test-linux: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: "ubuntu-latest-xlarge" | |
name: "cargo test | ubuntu" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Install Rust toolchain" | |
run: rustup show | |
- uses: astral-sh/setup-uv@v3 | |
- name: "Install required Python versions" | |
run: uv python install | |
- name: "Install cargo nextest" | |
uses: taiki-e/install-action@v2 | |
with: | |
tool: cargo-nextest | |
- name: "Cargo test" | |
run: | | |
cargo nextest run \ | |
--features python-patch \ | |
--workspace \ | |
--status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow | |
- name: "Smoke test" | |
run: | | |
uv="./target/debug/uv" | |
$uv venv -v | |
$uv pip install ruff -v | |
- name: "Smoke test completion" | |
run: | | |
uv="./target/debug/uv" | |
uvx="./target/debug/uvx" | |
eval "$($uv generate-shell-completion bash)" | |
eval "$($uvx --generate-shell-completion bash)" | |
cargo-test-macos: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: "macos-latest-xlarge" | |
name: "cargo test | macos" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Install Rust toolchain" | |
run: rustup show | |
- uses: astral-sh/setup-uv@v3 | |
- name: "Install required Python versions" | |
run: uv python install | |
- name: "Install cargo nextest" | |
uses: taiki-e/install-action@v2 | |
with: | |
tool: cargo-nextest | |
- name: "Cargo test" | |
run: | | |
cargo nextest run \ | |
--features python-patch \ | |
--workspace \ | |
--status-level skip --failure-output immediate-final --no-fail-fast -j 12 --final-status-level slow | |
- name: "Smoke test" | |
run: | | |
uv="./target/debug/uv" | |
$uv venv -v | |
$uv pip install ruff -v | |
cargo-test-windows: | |
timeout-minutes: 15 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: "windows-latest-xlarge" | |
name: "cargo test | windows" | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Create Dev Drive using ReFS | |
run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1 | |
# actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone... | |
- name: Copy Git Repo to Dev Drive | |
run: | | |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse | |
# We do not test with Python patch versions on Windows | |
# so we can use `setup-python` instead of our bootstrapping code | |
# this is much faster on the extremely slow GitHub Windows runners. | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: | | |
3.8 | |
3.9 | |
3.10 | |
3.11 | |
3.12 | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
workspaces: ${{ env.UV_WORKSPACE }} | |
- name: "Install Rust toolchain" | |
working-directory: ${{ env.UV_WORKSPACE }} | |
run: rustup show | |
- name: "Install cargo nextest" | |
uses: taiki-e/install-action@v2 | |
with: | |
tool: cargo-nextest | |
- name: "Cargo test" | |
working-directory: ${{ env.UV_WORKSPACE }} | |
env: | |
# Avoid permission errors during concurrent tests | |
# See https://github.com/astral-sh/uv/issues/6940 | |
UV_LINK_MODE: copy | |
run: | | |
cargo nextest run --no-default-features --features python,pypi,python-managed --workspace --status-level skip --failure-output immediate-final --no-fail-fast -j 20 --final-status-level slow | |
- name: "Smoke test" | |
working-directory: ${{ env.UV_WORKSPACE }} | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
run: | | |
Set-Alias -Name uv -Value ./target/debug/uv | |
uv venv -v | |
uv pip install ruff -v | |
- name: "Smoke test completion" | |
working-directory: ${{ env.UV_WORKSPACE }} | |
shell: powershell | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 | |
run: | | |
Set-Alias -Name uv -Value ./target/debug/uv | |
Set-Alias -Name uvx -Value ./target/debug/uvx | |
(& uv generate-shell-completion powershell) | Out-String | Invoke-Expression | |
(& uvx --generate-shell-completion powershell) | Out-String | Invoke-Expression | |
# Separate jobs for the nightly crate | |
windows-trampoline-check: | |
timeout-minutes: 15 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: windows-latest-xlarge | |
name: "check windows trampoline | ${{ matrix.target-arch }}" | |
strategy: | |
fail-fast: false | |
matrix: | |
target-arch: ["x86_64", "i686", "aarch64"] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Create Dev Drive using ReFS | |
run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1 | |
# actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone... | |
- name: Copy Git Repo to Dev Drive | |
run: | | |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
workspaces: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline | |
- name: "Install Rust toolchain" | |
working-directory: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline | |
run: | | |
rustup target add ${{ matrix.target-arch }}-pc-windows-msvc | |
rustup component add rust-src --target ${{ matrix.target-arch }}-pc-windows-msvc | |
- name: "Install cargo-bloat" | |
uses: taiki-e/install-action@v2 | |
with: | |
tool: cargo-bloat | |
- name: "Clippy" | |
working-directory: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline | |
run: cargo clippy --all-features --locked --target x86_64-pc-windows-msvc --tests -- -D warnings | |
- name: "Bloat Check" | |
working-directory: ${{ env.UV_WORKSPACE }}/crates/uv-trampoline | |
run: | | |
$output = cargo bloat --release --target x86_64-pc-windows-msvc | |
$filteredOutput = $output | Select-String -Pattern 'core::fmt::write|core::fmt::getcount' -NotMatch | |
$containsPatterns = $filteredOutput | Select-String -Pattern 'core::fmt|std::panicking|std::backtrace_rs' | |
if ($containsPatterns) { | |
Exit 1 | |
} else { | |
Exit 0 | |
} | |
# Separate jobs for the nightly crate | |
windows-trampoline-test: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: windows-latest | |
name: "test windows trampoline | ${{ matrix.target-arch }}" | |
strategy: | |
fail-fast: false | |
matrix: | |
# Note, we exclude `aarch64` because it's not supported by the GitHub runner | |
target-arch: ["x86_64", "i686"] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Rust toolchain" | |
working-directory: ${{ github.workspace }}/crates/uv-trampoline | |
run: | | |
rustup target add ${{ matrix.target-arch }}-pc-windows-msvc | |
rustup component add rust-src --target ${{ matrix.target-arch }}-pc-windows-msvc | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
workspaces: ${{ github.workspace }}/crates/uv-trampoline | |
- name: "Test committed binaries" | |
working-directory: ${{ github.workspace }} | |
run: | | |
rustup target add ${{ matrix.target-arch }}-pc-windows-msvc | |
cargo test -p uv-trampoline-builder --target ${{ matrix.target-arch }}-pc-windows-msvc | |
# Build and copy the new binaries | |
- name: "Build" | |
working-directory: ${{ github.workspace }}/crates/uv-trampoline | |
run: | | |
cargo build --target ${{ matrix.target-arch }}-pc-windows-msvc | |
cp target/${{ matrix.target-arch }}-pc-windows-msvc/debug/uv-trampoline-console.exe trampolines/uv-trampoline-${{ matrix.target-arch }}-console.exe | |
cp target/${{ matrix.target-arch }}-pc-windows-msvc/debug/uv-trampoline-gui.exe trampolines/uv-trampoline-${{ matrix.target-arch }}-gui.exe | |
- name: "Test new binaries" | |
working-directory: ${{ github.workspace }} | |
run: | | |
# We turn off the default "production" test feature since these are debug binaries | |
cargo test -p uv-trampoline-builder --target ${{ matrix.target-arch }}-pc-windows-msvc --no-default-features | |
typos: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: crate-ci/typos@master | |
docs: | |
timeout-minutes: 10 | |
name: "mkdocs" | |
runs-on: ubuntu-latest | |
env: | |
MKDOCS_INSIDERS_SSH_KEY_EXISTS: ${{ secrets.MKDOCS_INSIDERS_SSH_KEY != '' }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: astral-sh/setup-uv@v3 | |
- uses: actions/setup-python@v5 | |
- name: "Add SSH key" | |
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} | |
uses: webfactory/[email protected] | |
with: | |
ssh-private-key: ${{ secrets.MKDOCS_INSIDERS_SSH_KEY }} | |
- name: "Build docs (public)" | |
run: uvx --with-requirements docs/requirements.txt mkdocs build --strict -f mkdocs.public.yml | |
- name: "Build docs (insiders)" | |
if: ${{ env.MKDOCS_INSIDERS_SSH_KEY_EXISTS == 'true' }} | |
run: uvx --with-requirements docs/requirements.txt mkdocs build --strict -f mkdocs.insiders.yml | |
build-binary-linux: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: ubuntu-latest-large | |
name: "build binary | linux" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
- name: "Setup musl" | |
run: | | |
sudo apt-get install musl-tools | |
rustup target add x86_64-unknown-linux-musl | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Build" | |
run: cargo build --target x86_64-unknown-linux-musl | |
- name: "Upload binary" | |
uses: actions/upload-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
path: ./target/x86_64-unknown-linux-musl/debug/uv | |
retention-days: 1 | |
build-binary-macos-aarch64: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: macos-14 | |
name: "build binary | macos aarch64" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Build" | |
run: cargo build | |
- name: "Upload binary" | |
uses: actions/upload-artifact@v4 | |
with: | |
name: uv-macos-aarch64-${{ github.sha }} | |
path: ./target/debug/uv | |
retention-days: 1 | |
build-binary-macos-x86_64: | |
timeout-minutes: 10 | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: macos-14-large | |
name: "build binary | macos x86_64" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: rui314/setup-mold@v1 | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Build" | |
run: cargo build | |
- name: "Upload binary" | |
uses: actions/upload-artifact@v4 | |
with: | |
name: uv-macos-x86_64-${{ github.sha }} | |
path: ./target/debug/uv | |
retention-days: 1 | |
build-binary-windows: | |
needs: determine_changes | |
timeout-minutes: 10 | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: windows-latest-large | |
name: "build binary | windows" | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Create Dev Drive using ReFS | |
run: ${{ github.workspace }}/.github/workflows/setup-dev-drive.ps1 | |
# actions/checkout does not let us clone into anywhere outside ${{ github.workspace }}, so we have to copy the clone... | |
- name: Copy Git Repo to Dev Drive | |
run: | | |
Copy-Item -Path "${{ github.workspace }}" -Destination "${{ env.UV_WORKSPACE }}" -Recurse | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
workspaces: ${{ env.UV_WORKSPACE }} | |
- name: "Build" | |
working-directory: ${{ env.UV_WORKSPACE }} | |
run: cargo build | |
- name: "Upload binary" | |
uses: actions/upload-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
path: ${{ env.UV_WORKSPACE }}/target/debug/uv.exe | |
retention-days: 1 | |
build-binary-freebsd: | |
needs: determine_changes | |
timeout-minutes: 10 | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
runs-on: | |
labels: ubuntu-latest | |
name: "build binary | freebsd" | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Cross build" | |
run: | | |
# Install cross from `freebsd-firecracker` | |
wget -q -O cross https://github.com/acj/freebsd-firecracker/releases/download/v0.0.10/cross | |
chmod +x cross | |
mv cross /usr/local/bin/cross | |
cross build --target x86_64-unknown-freebsd | |
- name: Test in Firecracker VM | |
uses: acj/[email protected] | |
with: | |
verbose: false | |
pre-run: | | |
# The exclude `*` prevents examination of directories so we need to | |
# include each parent directory of the binary | |
include_path="$(mktemp)" | |
cat <<EOF > $include_path | |
target | |
target/x86_64-unknown-freebsd | |
target/x86_64-unknown-freebsd/debug | |
target/x86_64-unknown-freebsd/debug/uv | |
EOF | |
rsync -r -e "ssh" \ | |
--relative \ | |
--copy-links \ | |
--include-from "$include_path" \ | |
--exclude "*" \ | |
. firecracker: | |
run-in-vm: | | |
cp target/x86_64-unknown-freebsd/debug/uv uv | |
chmod +x uv | |
./uv --version | |
ecosystem-test: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "ecosystem test | ${{ matrix.repo }}" | |
runs-on: ubuntu-latest | |
strategy: | |
matrix: | |
include: | |
- repo: "prefecthq/prefect" | |
command: "uv pip install -e '.[dev]'" | |
python: "3.9" | |
- repo: "pallets/flask" | |
command: "uv pip install -r requirements/dev.txt" | |
python: "3.12" | |
fail-fast: false | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
repository: ${{ matrix.repo }} | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python }} | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Test" | |
run: | | |
./uv venv | |
./${{ matrix.command }} | |
integration-test-conda: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "integration test | conda on ubuntu" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: conda-incubator/setup-miniconda@v3 | |
with: | |
miniconda-version: latest | |
activate-environment: uv | |
python-version: "3.12" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: Conda info | |
shell: bash -el {0} | |
run: conda info | |
- name: "Install a package" | |
shell: bash -el {0} | |
run: | | |
echo "$CONDA_PREFIX" | |
./uv pip install anyio | |
integration-test-free-threaded-linux: | |
timeout-minutes: 5 | |
needs: build-binary-linux | |
name: "integration test | free-threaded on linux" | |
runs-on: ubuntu-latest | |
steps: | |
- name: "install python3.13-nogil" | |
run: | | |
sudo add-apt-repository ppa:deadsnakes | |
sudo apt-get update | |
sudo apt-get install python3.13-nogil | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Create a virtual environment" | |
run: | | |
./uv venv -p 3.13t --python-preference only-system | |
- name: "Check version" | |
run: | | |
.venv/bin/python --version | |
- name: "Check is free-threaded" | |
run: | | |
.venv/bin/python -c "import sys; exit(1) if sys._is_gil_enabled() else exit(0)" | |
- name: "Check install" | |
run: | | |
./uv pip install -v anyio | |
- name: "Install free-threaded Python via uv" | |
run: | | |
./uv python install -v 3.13t | |
./uv venv -p 3.13t --python-preference only-managed | |
- name: "Check version" | |
run: | | |
.venv/bin/python --version | |
- name: "Check is free-threaded" | |
run: | | |
.venv/bin/python -c "import sys; exit(1) if sys._is_gil_enabled() else exit(0)" | |
- name: "Check install" | |
run: | | |
./uv pip install -v anyio | |
integration-test-free-threaded-windows: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "integration test | free-threaded on windows" | |
runs-on: windows-latest | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 | |
steps: | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: "Install free-threaded Python via uv" | |
run: | | |
./uv python install -v 3.13t | |
- name: "Create a virtual environment" | |
run: | | |
./uv venv -p 3.13t --python-preference only-managed | |
- name: "Check version" | |
run: | | |
.venv/Scripts/python --version | |
- name: "Check is free-threaded" | |
run: | | |
.venv/Scripts/python -c "import sys; exit(1) if sys._is_gil_enabled() else exit(0)" | |
- name: "Check install" | |
run: | | |
./uv pip install -v anyio | |
- name: "Check uv run" | |
run: | | |
./uv run python -c "" | |
./uv run -p 3.13t python -c "" | |
integration-test-pypy-linux: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "integration test | pypy on ubuntu" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Install PyPy" | |
run: ./uv python install -v pypy3.9 | |
- name: "Create a virtual environment" | |
run: | | |
./uv venv -p pypy3.9 --python-preference only-managed | |
- name: "Check for executables" | |
run: | | |
check_in_bin() { | |
local executable_name=$1 | |
local bin_path=".venv/bin" | |
if [[ -x "$bin_path/$executable_name" ]]; then | |
return 0 | |
else | |
echo "Executable '$executable_name' not found in folder '$bin_path'." | |
return 1 | |
fi | |
} | |
executables=("pypy" "pypy3" "python") | |
all_found=true | |
for executable_name in "${executables[@]}"; do | |
check_in_bin "$executable_name" "$folder_path" | |
result=$? | |
if [[ $result -ne 0 ]]; then | |
all_found=false | |
fi | |
done | |
if ! $all_found; then | |
echo "One or more expected executables were not found." | |
exit 1 | |
fi | |
- name: "Check version" | |
run: | | |
.venv/bin/pypy --version | |
.venv/bin/pypy3 --version | |
.venv/bin/python --version | |
- name: "Check install" | |
run: | | |
./uv pip install anyio | |
integration-test-pypy-windows: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "integration test | pypy on windows" | |
runs-on: windows-latest | |
steps: | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: "Install PyPy" | |
run: .\uv.exe python install pypy3.9 | |
- name: "Create a virtual environment" | |
run: | | |
.\uv.exe venv -p pypy3.9 --python-preference only-managed | |
- name: "Check for executables" | |
shell: python | |
run: | | |
import sys | |
from pathlib import Path | |
def binary_exist(binary): | |
binaries_path = Path(".venv\\Scripts") | |
if (binaries_path / binary).exists(): | |
return True | |
print(f"Executable '{binary}' not found in folder '{binaries_path}'.") | |
all_found = True | |
expected_binaries = [ | |
"pypy3.9.exe", | |
"pypy3.9w.exe", | |
"pypy3.exe", | |
"pypyw.exe", | |
"python.exe", | |
"python3.9.exe", | |
"python3.exe", | |
"pythonw.exe", | |
] | |
for binary in expected_binaries: | |
if not binary_exist(binary): | |
all_found = False | |
if not all_found: | |
print("One or more expected executables were not found.") | |
sys.exit(1) | |
- name: "Check version" | |
run: | | |
& .venv\Scripts\pypy3.9.exe --version | |
& .venv\Scripts\pypy3.exe --version | |
& .venv\Scripts\python.exe --version | |
- name: "Check install" | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
run: | | |
.\uv.exe pip install anyio | |
integration-test-graalpy-linux: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "integration test | graalpy on ubuntu" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "graalpy24.1" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: Graalpy info | |
run: | | |
which graalpy | |
- name: "Create a virtual environment" | |
run: | | |
./uv venv -p $(which graalpy) | |
- name: "Check for executables" | |
run: | | |
check_in_bin() { | |
local executable_name=$1 | |
local bin_path=".venv/bin" | |
if [[ -x "$bin_path/$executable_name" ]]; then | |
return 0 | |
else | |
echo "Executable '$executable_name' not found in folder '$bin_path'." | |
return 1 | |
fi | |
} | |
executables=("graalpy" "python3" "python") | |
all_found=true | |
for executable_name in "${executables[@]}"; do | |
check_in_bin "$executable_name" "$folder_path" | |
result=$? | |
if [[ $result -ne 0 ]]; then | |
all_found=false | |
fi | |
done | |
if ! $all_found; then | |
echo "One or more expected executables were not found." | |
exit 1 | |
fi | |
- name: "Check version" | |
run: | | |
.venv/bin/graalpy --version | |
.venv/bin/python3 --version | |
.venv/bin/python --version | |
- name: "Check install" | |
run: | | |
./uv pip install anyio | |
integration-test-graalpy-windows: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "integration test | graalpy on windows" | |
runs-on: windows-latest | |
steps: | |
- uses: timfel/setup-python@fc9bcb4a04f5b1ea7d678c2ca7ea1c479a2468d7 | |
with: | |
python-version: "graalpy24.1" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: Graalpy info | |
run: Get-Command graalpy | |
- name: "Create a virtual environment" | |
run: | | |
$graalpy = (Get-Command graalpy).source | |
.\uv.exe venv -p $graalpy | |
- name: "Check for executables" | |
shell: python | |
run: | | |
import sys | |
from pathlib import Path | |
def binary_exist(binary): | |
binaries_path = Path(".venv\\Scripts") | |
if (binaries_path / binary).exists(): | |
return True | |
print(f"Executable '{binary}' not found in folder '{binaries_path}'.") | |
all_found = True | |
expected_binaries = [ | |
"graalpy.exe", | |
"python.exe", | |
"python3.exe", | |
] | |
for binary in expected_binaries: | |
if not binary_exist(binary): | |
all_found = False | |
if not all_found: | |
print("One or more expected executables were not found.") | |
sys.exit(1) | |
- name: "Check version" | |
run: | | |
& .venv\Scripts\graalpy.exe --version | |
& .venv\Scripts\python3.exe --version | |
& .venv\Scripts\python.exe --version | |
- name: "Check install" | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
run: | | |
.\uv.exe pip install anyio | |
integration-test-github-actions: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "integration test | github actions" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.12.7" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Install a package without system opt-in" | |
run: | | |
./uv pip install anyio && exit 1 || echo "Failed as expected" | |
- name: "Install a package with system opt-in" | |
run: | | |
./uv pip install anyio --system | |
- name: Configure uv to use the system Python by default | |
run: echo "UV_SYSTEM_PYTHON=1" >> $GITHUB_ENV | |
- name: "Install a package with system opt-in via the environment" | |
run: | | |
./uv pip install anyio --reinstall | |
- name: "Create a project" | |
run: | | |
# Use Python 3.11 as the minimum required version | |
./uv init --python 3.11 | |
./uv add anyio | |
- name: "Sync to the system Python" | |
run: ./uv sync -v --python 3.12 | |
env: | |
UV_PROJECT_ENVIRONMENT: "/opt/hostedtoolcache/Python/3.12.7/x64" | |
- name: "Attempt to sync to the system Python with an incompatible version" | |
run: | | |
./uv sync -v --python 3.11 && { echo "ci: Error; should not succeed"; exit 1; } || { echo "ci: Ok; expected failure"; exit 0; } | |
env: | |
UV_PROJECT_ENVIRONMENT: "/opt/hostedtoolcache/Python/3.12.7/x64" | |
- name: "Attempt to sync to a non-Python environment directory" | |
run: | | |
mkdir -p /home/runner/example | |
touch /home/runner/example/some-file | |
./uv sync -v && { echo "ci: Error; should not succeed"; exit 1; } || { echo "ci: Ok; expected failure"; exit 0; } | |
env: | |
UV_PROJECT_ENVIRONMENT: "/home/runner/example" | |
integration-test-publish-changed: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "integration test | determine publish changes" | |
runs-on: ubuntu-latest | |
outputs: | |
# Flag that is raised when any code is changed | |
code: ${{ steps.changed.outputs.code_any_changed }} | |
# Only the main repository is a trusted publisher | |
if: github.repository == 'astral-sh/uv' | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
# Only publish a new release if the publishing code changed | |
- uses: tj-actions/changed-files@v45 | |
id: changed | |
with: | |
files_yaml: | | |
code: | |
- "crates/uv-publish/**/*" | |
- "scripts/publish/**/*" | |
- ".github/workflows/ci.yml" | |
integration-test-publish: | |
timeout-minutes: 10 | |
needs: integration-test-publish-changed | |
name: "integration test | uv publish" | |
runs-on: ubuntu-latest | |
if: ${{ github.repository == 'astral-sh/uv' && github.event.pull_request.head.repo.fork != true && (needs.integration-test-publish-changed.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
environment: uv-test-publish | |
env: | |
# No dbus in GitHub Actions | |
PYTHON_KEYRING_BACKEND: keyrings.alt.file.PlaintextKeyring | |
permissions: | |
# For trusted publishing | |
id-token: write | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.12" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Add password to keyring" | |
run: | | |
# `keyrings.alt` contains the plaintext keyring | |
./uv tool install --with keyrings.alt "keyring<25.4.0" # TODO(konsti): Remove upper bound once fix is released | |
echo $UV_TEST_PUBLISH_KEYRING | keyring set https://test.pypi.org/legacy/?astral-test-keyring __token__ | |
env: | |
UV_TEST_PUBLISH_KEYRING: ${{ secrets.UV_TEST_PUBLISH_KEYRING }} | |
- name: "Publish test packages" | |
# `-p 3.12` prefers the python we just installed over the one locked in `.python_version`. | |
run: ./uv run -p 3.12 scripts/publish/test_publish.py --uv ./uv all | |
env: | |
RUST_LOG: uv=debug,uv_publish=trace | |
UV_TEST_PUBLISH_TOKEN: ${{ secrets.UV_TEST_PUBLISH_TOKEN }} | |
UV_TEST_PUBLISH_PASSWORD: ${{ secrets.UV_TEST_PUBLISH_PASSWORD }} | |
UV_TEST_PUBLISH_GITLAB_PAT: ${{ secrets.UV_TEST_PUBLISH_GITLAB_PAT }} | |
UV_TEST_PUBLISH_CODEBERG_TOKEN: ${{ secrets.UV_TEST_PUBLISH_CODEBERG_TOKEN }} | |
UV_TEST_PUBLISH_CLOUDSMITH_TOKEN: ${{ secrets.UV_TEST_PUBLISH_CLOUDSMITH_TOKEN }} | |
cache-test-ubuntu: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check cache | ubuntu" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.12" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Download binary for last version" | |
run: curl -LsSf "https://github.com/astral-sh/uv/releases/latest/download/uv-x86_64-unknown-linux-gnu.tar.gz" | tar -xvz | |
- name: "Check cache compatibility" | |
run: python scripts/check_cache_compat.py --uv-current ./uv --uv-previous ./uv-x86_64-unknown-linux-gnu/uv | |
cache-test-macos-aarch64: | |
timeout-minutes: 10 | |
needs: build-binary-macos-aarch64 | |
name: "check cache | macos aarch64" | |
runs-on: macos-14 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-macos-aarch64-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Download binary for last version" | |
run: curl -LsSf "https://github.com/astral-sh/uv/releases/latest/download/uv-aarch64-apple-darwin.tar.gz" | tar -xvz | |
- name: "Check cache compatibility" | |
run: python scripts/check_cache_compat.py --uv-current ./uv --uv-previous ./uv-aarch64-apple-darwin/uv | |
system-test-debian: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | python on debian" | |
runs-on: ubuntu-latest | |
container: debian:bookworm | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: apt-get update && apt-get install -y python3.11 python3-pip python3.11-venv | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3.11) | |
- name: "Validate global Python install" | |
run: python3.11 scripts/check_system_python.py --uv ./uv --externally-managed | |
system-test-fedora: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | python on fedora" | |
runs-on: ubuntu-latest | |
container: fedora:42 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: dnf install python3 which -y && python3 -m ensurepip | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv | |
system-test-ubuntu: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | python on ubuntu" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.12" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python) | |
- name: "Validate global Python install" | |
run: python scripts/check_system_python.py --uv ./uv | |
system-test-opensuse: | |
timeout-minutes: 5 | |
needs: build-binary-linux | |
name: "check system | python on opensuse" | |
runs-on: ubuntu-latest | |
container: opensuse/tumbleweed | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: > | |
until | |
zypper install -y python310 which && python3.10 -m ensurepip && mv /usr/bin/python3.10 /usr/bin/python3; | |
do sleep 10; | |
done | |
# We retry because `zypper` can fail during remote repository updates | |
# The above will not sleep forever due to the job level timeout | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv | |
# Note: rockylinux is a 1-1 code compatible distro to rhel | |
# rockylinux mimics centos but with added maintenance stability | |
# and avoids issues with centos stream uptime concerns | |
system-test-rocky-linux: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | python on rocky linux ${{ matrix.rocky-version }}" | |
runs-on: ubuntu-latest | |
container: rockylinux:${{ matrix.rocky-version }} | |
strategy: | |
fail-fast: false | |
matrix: | |
rocky-version: ["8", "9"] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
if: matrix.rocky-version == '8' | |
run: | | |
dnf install python39 python39-pip which -y | |
- name: "Install Python" | |
if: matrix.rocky-version == '9' | |
run: | | |
dnf install python3.9 python3.9-pip which -y | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv | |
system-test-pypy: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | pypy on ubuntu" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "pypy3.9" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which pypy) | |
- name: "Validate global Python install" | |
run: pypy scripts/check_system_python.py --uv ./uv | |
system-test-pyston: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | pyston" | |
runs-on: ubuntu-latest | |
container: pyston/pyston:2.3.5 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which pyston) | |
- name: "Validate global Python install" | |
run: pyston scripts/check_system_python.py --uv ./uv | |
system-test-alpine: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | alpine" | |
runs-on: ubuntu-latest | |
container: alpine:latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: apk add --update --no-cache python3 py3-pip | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv --externally-managed | |
system-test-macos-aarch64: | |
timeout-minutes: 10 | |
needs: build-binary-macos-aarch64 | |
name: "check system | python on macos aarch64" | |
runs-on: macos-14 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-macos-aarch64-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
# This should be the macOS system Python | |
# We'd like to test with Homebrew but this Python takes precedence in system Python discovery | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv --externally-managed | |
system-test-macos-aarch64-homebrew: | |
timeout-minutes: 10 | |
needs: build-binary-macos-aarch64 | |
name: "check system | homebrew python on macos aarch64" | |
runs-on: macos-14 | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: brew install python3 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-macos-aarch64-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv --externally-managed | |
system-test-macos-x86_64: | |
timeout-minutes: 10 | |
needs: build-binary-macos-x86_64 | |
name: "check system | python on macos x86_64" | |
runs-on: macos-13 | |
steps: | |
- uses: actions/checkout@v4 | |
# We test with GitHub's Python as a regression test for | |
# https://github.com/astral-sh/uv/issues/2450 | |
- uses: actions/setup-python@v5 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-macos-x86_64-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv | |
system-test-windows-python-310: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "check system | python3.10 on windows" | |
runs-on: windows-latest | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.10" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: "Print Python path" | |
run: echo $(which python) | |
- name: "Validate global Python install" | |
run: py -3.10 ./scripts/check_system_python.py --uv ./uv.exe | |
system-test-windows-x86-python-310: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "check system | python3.10 on windows x86" | |
runs-on: windows-latest | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.10" | |
architecture: "x86" | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: "Print Python path" | |
run: echo $(which python) | |
- name: "Validate global Python install" | |
run: python ./scripts/check_system_python.py --uv ./uv.exe | |
system-test-windows-python-313: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "check system | python3.13 on windows" | |
runs-on: windows-latest | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: "3.13" | |
allow-prereleases: true | |
cache: pip | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: "Print Python path" | |
run: echo $(which python) | |
- name: "Validate global Python install" | |
run: py -3.13 ./scripts/check_system_python.py --uv ./uv.exe | |
system-test-choco: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "check system | python3.12 via chocolatey" | |
runs-on: windows-latest | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: choco install python3 --verbose --version=3.9.13 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: py -3.9 ./scripts/check_system_python.py --uv ./uv.exe | |
system-test-pyenv: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | python3.9 via pyenv" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Install pyenv" | |
run: | | |
# Install pyenv | |
curl https://pyenv.run | bash | |
# Set up environment variables for current step | |
export PYENV_ROOT="$HOME/.pyenv" | |
export PATH="$PYENV_ROOT/bin:$PATH" | |
eval "$(pyenv init -)" | |
# Install Python 3.9 | |
pyenv install 3.9 | |
pyenv global 3.9 | |
# Make environment variables persist across steps | |
echo "PYENV_ROOT=$HOME/.pyenv" >> $GITHUB_ENV | |
echo "$HOME/.pyenv/bin" >> $GITHUB_PATH | |
echo "$HOME/.pyenv/shims" >> $GITHUB_PATH | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3.9) | |
- name: "Validate global Python install" | |
run: python3.9 scripts/check_system_python.py --uv ./uv | |
system-test-linux-313: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | python3.13" | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: 3.13 | |
allow-prereleases: true | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3.13) | |
- name: "Validate global Python install" | |
run: python3.13 scripts/check_system_python.py --uv ./uv | |
system-test-conda: | |
timeout-minutes: 10 | |
needs: | |
[build-binary-windows, build-binary-macos-aarch64, build-binary-linux] | |
name: check system | conda${{ matrix.python-version }} on ${{ matrix.os }} | |
runs-on: ${{ matrix.runner }} | |
strategy: | |
fail-fast: false | |
matrix: | |
os: ["linux", "windows", "macos"] | |
python-version: ["3.8", "3.11"] | |
include: | |
- { os: "linux", target: "linux", runner: "ubuntu-latest" } | |
- { os: "windows", target: "windows", runner: "windows-latest" } | |
- { os: "macos", target: "macos-aarch64", runner: "macos-14" } | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: conda-incubator/setup-miniconda@v3 | |
with: | |
miniconda-version: "latest" | |
activate-environment: uv | |
python-version: ${{ matrix.python-version }} | |
- name: Conda info | |
shell: bash -el {0} | |
run: conda info | |
- name: Conda list | |
shell: pwsh | |
run: conda list | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-${{ matrix.target }}-${{ github.sha }} | |
- name: "Prepare binary" | |
if: ${{ matrix.os != 'windows' }} | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
shell: bash -el {0} | |
run: echo $(which python) | |
- name: "Validate global Python install" | |
shell: bash -el {0} | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
run: python ./scripts/check_system_python.py --uv ./uv | |
system-test-amazonlinux: | |
timeout-minutes: 10 | |
needs: build-binary-linux | |
name: "check system | amazonlinux" | |
runs-on: ubuntu-latest | |
container: amazonlinux:2023 | |
steps: | |
- name: "Install base requirements" | |
run: | | |
# Needed for `actions/checkout` | |
yum install tar gzip which -y | |
- uses: actions/checkout@v4 | |
- name: "Install Python" | |
run: yum install python3 python3-pip -y | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-linux-${{ github.sha }} | |
- name: "Prepare binary" | |
run: chmod +x ./uv | |
- name: "Print Python path" | |
run: echo $(which python3) | |
- name: "Validate global Python install" | |
run: python3 scripts/check_system_python.py --uv ./uv | |
system-test-windows-embedded-python-310: | |
timeout-minutes: 10 | |
needs: build-binary-windows | |
name: "check system | embedded python3.10 on windows" | |
runs-on: windows-latest | |
env: | |
# Avoid debug build stack overflows. | |
UV_STACK_SIZE: 2000000 # 2 megabyte, double the default on windows | |
steps: | |
- uses: actions/checkout@v4 | |
- name: "Download binary" | |
uses: actions/download-artifact@v4 | |
with: | |
name: uv-windows-${{ github.sha }} | |
# Download embedded Python. | |
- name: "Download embedded Python" | |
run: curl -LsSf https://www.python.org/ftp/python/3.11.8/python-3.11.8-embed-amd64.zip -o python-3.11.8-embed-amd64.zip | |
- name: "Unzip embedded Python" | |
run: 7z x python-3.11.8-embed-amd64.zip -oembedded-python | |
- name: "Show embedded Python contents" | |
run: ls embedded-python | |
- name: "Set PATH" | |
run: echo "${{ github.workspace }}\embedded-python" >> $env:GITHUB_PATH | |
- name: "Print Python path" | |
run: echo $(which python) | |
- name: "Validate embedded Python install" | |
run: python ./scripts/check_embedded_python.py --uv ./uv.exe | |
benchmarks: | |
runs-on: ubuntu-latest | |
needs: determine_changes | |
if: ${{ github.repository == 'astral-sh/uv' && (needs.determine_changes.outputs.code == 'true' || github.ref == 'refs/heads/main') }} | |
timeout-minutes: 20 | |
steps: | |
- name: "Checkout Branch" | |
uses: actions/checkout@v4 | |
- uses: Swatinem/rust-cache@v2 | |
- name: "Install Rust toolchain" | |
run: rustup show | |
- name: "Install codspeed" | |
uses: taiki-e/install-action@v2 | |
with: | |
tool: cargo-codspeed | |
- name: "Install requirements and prime cache" | |
run: | | |
sudo apt-get update | |
sudo apt-get install -y libsasl2-dev libldap2-dev libkrb5-dev | |
cargo run --bin uv -- venv --cache-dir .cache | |
cargo run --bin uv -- pip compile scripts/requirements/jupyter.in --universal --exclude-newer 2024-08-08 --cache-dir .cache | |
cargo run --bin uv -- pip compile scripts/requirements/airflow.in --universal --exclude-newer 2024-08-08 --cache-dir .cache | |
- name: "Build benchmarks" | |
run: cargo codspeed build --profile profiling --features codspeed -p uv-bench | |
- name: "Run benchmarks" | |
uses: CodSpeedHQ/action@v3 | |
with: | |
run: cargo codspeed run | |
token: ${{ secrets.CODSPEED_TOKEN }} |