跳到内容

在 GitHub Actions 中使用 uv

安装

对于 GitHub Actions,我们推荐使用官方的 astral-sh/setup-uv action。它负责安装 uv、将其添加到 PATH、(可选) 持久化缓存等,并支持所有 uv 支持的平台。

安装最新版本的 uv

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

最佳实践是锁定特定的 uv 版本,例如:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7
        with:
          # Install a specific version of uv.
          version: "0.10.9"

设置 Python

可以使用 python install 命令安装 Python

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Set up Python
        run: uv python install

这将遵循项目中指定的 Python 版本。

或者,也可以使用官方的 GitHub setup-python action。这可能更快,因为 GitHub 会在运行器上缓存 Python 版本。

设置 python-version-file 选项,以使用项目中锁定的版本

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: "Set up Python"
        uses: actions/setup-python@v6
        with:
          python-version-file: ".python-version"

      - name: Install uv
        uses: astral-sh/setup-uv@v7

或者,指定 pyproject.toml 文件以忽略锁定版本,并使用与项目 requires-python 约束兼容的最新版本

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: "Set up Python"
        uses: actions/setup-python@v6
        with:
          python-version-file: "pyproject.toml"

      - name: Install uv
        uses: astral-sh/setup-uv@v7

多版本 Python

当使用矩阵(matrix)测试多个 Python 版本时,请使用 astral-sh/setup-uv 设置 Python 版本,这将覆盖 pyproject.toml.python-version 文件中的 Python 版本规范

example.yml
jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"

    steps:
      - uses: actions/checkout@v6

      - name: Install uv and set the Python version
        uses: astral-sh/setup-uv@v7
        with:
          python-version: ${{ matrix.python-version }}

如果不使用 setup-uv action,可以设置 UV_PYTHON 环境变量

example.yml
jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"
    env:
      UV_PYTHON: ${{ matrix.python-version }}
    steps:
      - uses: actions/checkout@v6

同步与运行

一旦安装了 uv 和 Python,就可以使用 uv sync 安装项目,并使用 uv run 在环境中运行命令

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install uv
        uses: astral-sh/setup-uv@v7

      - name: Install the project
        run: uv sync --locked --all-extras --dev

      - name: Run tests
        # For example, using `pytest`
        run: uv run pytest tests

提示

可以使用 UV_PROJECT_ENVIRONMENT 设置 将其安装到系统 Python 环境中,而不是创建虚拟环境。

缓存

存储 uv 的缓存跨工作流运行可能会改善 CI 时间。

astral-sh/setup-uv 内置支持缓存持久化

example.yml
- name: Enable caching
  uses: astral-sh/setup-uv@v7
  with:
    enable-cache: true

或者,您可以使用 actions/cache action 手动管理缓存

example.yml
jobs:
  install_job:
    env:
      # Configure a constant location for the uv cache
      UV_CACHE_DIR: /tmp/.uv-cache

    steps:
      # ... setup up Python and uv ...

      - name: Restore uv cache
        uses: actions/cache@v5
        with:
          path: /tmp/.uv-cache
          key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
          restore-keys: |
            uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
            uv-${{ runner.os }}

      # ... install packages, run tests, etc ...

      - name: Minimize uv cache
        run: uv cache prune --ci

uv cache prune --ci 命令用于减小缓存大小,并针对 CI 进行了优化。其性能影响取决于所安装的软件包。

提示

如果使用 uv pip,请在缓存键中使用 requirements.txt 而不是 uv.lock

注意

当使用非临时性、自托管的运行器时,默认缓存目录可能会无限增长。在这种情况下,在作业之间共享缓存可能不是最优选择。相反,应将缓存移动到 GitHub 工作区内,并在作业完成后使用 作业后钩子 (Post Job Hook) 将其删除。

install_job:
  env:
    # Configure a relative location for the uv cache
    UV_CACHE_DIR: ${{ github.workspace }}/.cache/uv

使用作业后钩子需要将自托管运行器上的 ACTIONS_RUNNER_HOOK_JOB_STARTED 环境变量设置为清理脚本的路径,如下所示。

clean-uv-cache.sh
#!/usr/bin/env sh
uv cache clean

使用 uv pip

如果使用 uv pip 接口而不是 uv 项目接口,uv 默认需要虚拟环境。要允许安装包到系统环境,请在所有 uv 调用中使用 --system 标志,或设置 UV_SYSTEM_PYTHON 变量。

UV_SYSTEM_PYTHON 变量可以在不同作用域下定义。

通过在顶层定义它,为整个工作流启用

example.yml
env:
  UV_SYSTEM_PYTHON: 1

jobs: ...

或者,为工作流中的特定作业启用

example.yml
jobs:
  install_job:
    env:
      UV_SYSTEM_PYTHON: 1
    ...

或者,为作业中的特定步骤启用

example.yml
steps:
  - name: Install requirements
    run: uv pip install -r requirements.txt
    env:
      UV_SYSTEM_PYTHON: 1

若要再次禁用,可以在任何 uv 调用中使用 --no-system 标志。

私有仓库

如果您的项目对私有 GitHub 仓库有 依赖,您需要配置 个人访问令牌 (PAT) 以允许 uv 获取它们。

在创建了对私有仓库具有读取权限的 PAT 后,将其添加为 仓库密钥 (repository secret)

然后,您可以使用 gh CLI(GitHub Actions 运行器中默认安装)来配置 Git 凭据助手,从而对托管在 github.com 上的仓库使用该 PAT 进行查询。

例如,如果您将仓库密钥命名为 MY_PAT

example.yml
steps:
  - name: Register the personal access token
    run: echo "${{ secrets.MY_PAT }}" | gh auth login --with-token
  - name: Configure the Git credential helper
    run: gh auth setup-git

发布到 PyPI

uv 可用于从 GitHub Actions 构建您的包并将其发布到 PyPI。我们在 astral-sh/trusted-publishing-examples 中提供了一个独立示例。该工作流使用了 受信任的发布 (trusted publishing),因此无需配置任何凭据。

在示例工作流中,我们使用脚本来测试源分发包 (sdist) 和 wheel 是否功能正常,以及是否漏掉了任何文件。此步骤建议执行,但可选。

首先,将发布工作流添加到您的项目中

.github/workflows/publish.yml
name: "Publish"

on:
  push:
    tags:
      # Publish on any tag starting with a `v`, e.g., v0.1.0
      - v*

jobs:
  run:
    runs-on: ubuntu-latest
    environment:
      name: pypi
    permissions:
      id-token: write
      contents: read
    steps:
      - name: Checkout
        uses: actions/checkout@v6
      - name: Install uv
        uses: astral-sh/setup-uv@v7
      - name: Install Python 3.13
        run: uv python install 3.13
      - name: Build
        run: uv build
      # Check that basic features work and we didn't miss to include crucial files
      - name: Smoke test (wheel)
        run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
      - name: Smoke test (source distribution)
        run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
      - name: Publish
        run: uv publish

然后,在 GitHub 仓库的“设置 (Settings)” -> “环境 (Environments)”下创建工作流中定义的环境。

GitHub settings dialog showing how to add the "pypi" environment under "Settings" -> "Environments"

在项目设置的“发布 (Publishing)”下,向您的 PyPI 项目添加一个 受信任的发布者。确保所有字段与您的 GitHub 配置匹配。

PyPI project publishing settings dialog showing how to set all fields for a trusted publisher configuration

保存后

PyPI project publishing settings dialog showing the configured trusted publishing settings

最后,对发布打标签并推送。请确保它以 v 开头,以匹配工作流中的模式。

$ git tag -a v0.1.0 -m v0.1.0
$ git push --tags