利用 GitHub Action 自动发布 PyPI 包

Posted on Mar 30, 2020

在 2019 年夏天,我们将两个 Python 包 ujsonrb 做了些调整与更新,以适合 Python3.6+ 环境下的运行。发现 PyPI 的发布比较繁琐,当时试图做些自动化的工作,但是没找到方向,就先搁置了。后来在一次的小版本发布时出现了 GitHub Release 的 tag 和 PyPI 最新版的 tag 不一致的情况 caiyunapp/ultrajson#8

2020 年年初,开源社区开始逐步接手 ujson 的维护工作,hugovk,若干开源软件的维护者,将基于 Github Actions 的自动化发布的流程引入到了 ujson 的维护工作中。所以我(ringsaturn)抄袭了一下他的部分工作,让 PyPI 的发布变成自动化的事情。

首先我们要到 PyPI 和 Test PyPI 生成两个 Token,然后添加到仓库的 Settings -> Secrets 中。PyPI token 以 pypi_password 的名字存储,Test PyPI token 则以 test_pypi_password 的名字存储。

然后在仓库的根目录下创建 .github/workflows/deploy.yml,内容如下:

name: Deploy

on:
  push:
    branches:
      - master
  release:
    types:
      - published

jobs:
  build:
    if: github.repository == 'ringsaturn/cnholiday'
    runs-on: ubuntu-18.04

    steps:
      - uses: actions/checkout@v2
      - run: |
                        git fetch --prune --unshallow

      - name: Set up Python 3.8
        uses: actions/setup-python@v1
        with:
          python-version: 3.8

      - name: Install dependencies
        run: |
          python -m pip install -U pip
          python -m pip install -U poetry
          poetry install          

      - name: Build package
        run: |
          git tag
          poetry build          

      - name: Publish package to PyPI
        if: github.event.action == 'published'
        uses: pypa/gh-action-pypi-publish@master
        with:
          user: __token__
          password: ${{ secrets.pypi_password }}

      - name: Publish package to TestPyPI
        uses: pypa/gh-action-pypi-publish@master
        with:
          user: __token__
          password: ${{ secrets.test_pypi_password }}
          repository_url: https://test.pypi.org/legacy/

然后 master 分支每一次有新的 commit 都会尝试发布到 Test PyPI 上(可以理解为正式发布之前的 pre-release)。而 GitHub 上执行的 release 也会自动发布到 PyPI 上。再也不会有 nujson 之前维护时出现的PyPI 和 GitHub 仓库的 tag 不一致的低级错误了。

目前这个功能已经应用在了 ringsaturn/cnholiday 的项目中,PyPI 见 cnholiday

这个仓库主要是我个人实验各种新技术的仓库,