目录

GitHub Actions:纯 Python 轮子

我们将介绍二进制轮子 下一页,但是如果你没有编译扩展,这被称为通用(纯 Python)包,制作“构建”轮子的过程很简单。在本页末尾,有一个配方通常可以准确地用于纯 Python 轮子(如果遵循了先前的建议)。

当没有要编译的东西时,为什么要制作轮子?轮子比只提供 sdist 好有很多原因

  • 轮子不运行 setup.py,而只是将文件安装到特定位置
    • 降低安装要求 - 用户不需要你的安装工具
    • 安装更快
    • 安装更安全 - 没有任意的代码执行
    • 安装高度一致
  • 轮子在安装时预先编译字节码
    • 初始导入速度不比后续导入慢
    • 减少权限问题的机会
  • 你可以查看 .whl(实际上是一个 .zip)并查看所有内容将被放置到哪里

作业设置

name: CD

on:
  workflow_dispatch:
  release:
    types:
      - published

jobs:

当你手动触发构建时,这将运行 (workflow_dispatch),或者当你发布版本时。稍后,我们将确保实际的发布步骤要求事件为发布事件,以便手动触发(以及分支/PR,如果启用了这些)。

如果你想要标签而不是版本,你可以添加 on: push: tags: "v*" 键,而不是版本 - 但是,记住为你的标签制作一个 GitHub 版本!它会在 GUI 中显示出来,并且会通知任何关注版本(-only)的人。你还需要更改下面的事件过滤器。

如果你愿意,可以合并 CI 作业和 CD 作业。为此,最好使用名称“CI/CD”,你可以只组合两个 on 字典。

分发:纯 Python 轮子

dist:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Build SDist and wheel
      run: pipx run build

    - uses: actions/upload-artifact@v4
      with:
        name: Packages
        path: dist/*

    - name: Check metadata
      run: pipx run twine check dist/*

我们使用 PyPA-Build,一个新的构建工具,旨在简化构建轮子和 SDists。它运行 PEP 517 后端,并且即使是制作 SDists 也能获取 PEP 518 需求。

默认情况下,这将从当前目录中的包制作一个 SDist 和一个轮子,它们将被放置在 ./dist 中。你只能构建 SDist (-s),只能构建轮子 (-w),更改输出文件夹 (-o <dir>) 或者如果你愿意,可以提供不同的输入文件夹。

你可以使用 setup-python 操作,使用 pip 安装 buildtwine,然后使用 python -m buildpyproject-build,但最好使用 pipx 来安装和运行 python 应用程序。Pipx 由 GitHub Actions 默认提供(实际上,它们使用它来设置其他应用程序)。

我们上传工件只是为了通过 GitHub PR/Checks API 使其可用。如果你愿意,可以在没有发布的情况下下载文件以在本地进行测试。

upload-artifact@v4 开始,工件名称必须是唯一的。不再支持扩展现有工件。

我们还添加了使用 twine 对元数据进行可选检查(它将在发布作业的上传操作中稍后进行测试)。

一体化操作

有一个 一体化操作,它为纯 Python 包完成所有工作,包括额外的预上传检查和漂亮的 GitHub 摘要。

steps:
  - uses: actions/checkout@v4
  - uses: hynek/build-and-inspect-python-package@v2

它生成的工件名为 Packages,因此这是你稍后发布时需要使用的名称。这将用于替代下面的手动步骤。

然后,你需要一个发布作业

publish:
  needs: [dist]
  environment: pypi
  permissions:
    id-token: write
    attestations: write
    contents: read
  runs-on: ubuntu-latest
  if: github.event_name == 'release' && github.event.action == 'published'
  steps:
    - uses: actions/download-artifact@v4
      with:
        name: Packages
        path: dist

    - name: Generate artifact attestation for sdist and wheel
      uses: actions/attest-build-provenance@v1.4.3
      with:
        subject-path: "dist/*"

    - uses: pypa/gh-action-pypi-publish@release/v1

当你通过网页界面创建 GitHub 版本时,我们会发布到 PyPI。你只需要告诉 PyPI 哪个组织、仓库、工作流程,并设置 pypi 环境以允许从 GitHub 推送。如果这是你第一次发布包,请查看 PyPI 可信发布者文档,了解有关准备 PyPI 以接受你的初始包发布的说明。

我们还在生成工件证明,这可以让用户验证工件是否是在你的操作上构建的。

完整配方

这几乎可以用于任何具有标准 .github/workflows/cd.yml 配方的包。这之所以有效,是因为 pyproject.toml 准确地描述了如何构建你的包,因此所有包都通过相同的接口构建

name: CD

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - main
  release:
    types:
      - published

jobs:
  dist:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: hynek/build-and-inspect-python-package@v2

  publish:
    needs: [dist]
    environment: pypi
    permissions:
      id-token: write
      attestations: write
      contents: read
    runs-on: ubuntu-latest
    if: github.event_name == 'release' && github.event.action == 'published'

    steps:
      - uses: actions/download-artifact@v4
        with:
          name: Packages
          path: dist

      - name: Generate artifact attestation for sdist and wheel
        uses: actions/attest-build-provenance@v1.4.3
        with:
          subject-path: "dist/*"

      - uses: pypa/gh-action-pypi-publish@release/v1