用 GitHub Actions 自動打包釋出 Python 專案

CDFMLR發表於2021-07-20

前言

還在手動打包上傳 PyPI?GitHub Actions 自動化真香~!

在《Python 程式碼一鍵轉流程圖》一文裡,我介紹了我的開源專案 PyFlowchart。過去這段時間裡,已經有好幾位小夥伴為這個專案提出了建議,或者報告了 Bug 啦。在這幾位朋友的幫助下,專案也迭代了幾個版本了。之前,這個專案每次版本更新,我都需要做很多寫程式碼意外的麻煩工作:

  1. 在 GitHub 上 publish 一個 release,
  2. 手動打包上傳 PyPI。

這個過程非常反人類,release 一個版本要做兩個工作。更可怕的是,打包上傳 PyPI 的工作十分模版化(鄙人拙作《如何用 pip 安裝自己寫的包》一文介紹了這個過程)。我覺得作為開發者,不應該把時間浪費在這種套路工作上。

於是我想去了過去我寫過一篇叫做《還在手動發部落格?GitHub Actions自動化真香》的文章,大致介紹了我是如何利用 GitHub Actions 自動更新部落格網站的。所以,今回,我嘗試用 GitHub Actions 搭建了一套釋出新版本時,自動打包上傳 PyPI ? 的工作流程。

現在,釋出新的版本時,就只需在 GitHub 上新建一個 Release。GitHub Actions 會自動幫我完成構建、打包、上傳 PyPI 的工作。

本文就介紹如何利用 GitHub Actions 自動釋出 Python 包到 PyPI。

(注:我在 PyFlowchart 專案中使用的實現和下文略有不同,我根據需求做了一些修改,如果你感興趣,可以看一看我的實現:github.com/cdfmlr/pyfl…


下文大部分內容主要參(fan)考(yi)自 PyPA 的文章《Publishing package distribution releases using GitHub Actions CI/CD workflows》

原文連結:packaging.python.org/guides/publ…

GitHub Actions CI/CD 允許在 GitHub 平臺上特定的事件發生時自動執行一系列的命令。用這個就可以做設定一個響應 push 事件的工作流程。本文將展示如何當有 git push 時釋出一個新的 Python 包發行版(到 PyPI)。我們將使用到 pypa/gh-action-pypi-publish GitHub Action

注意:這個教程假設你已經有在 GitHub 上有一個 Python 專案,並且你知道如何構建包,並把它釋出到 PyPI。

在 GitHub 上儲存 token

在本文中,我們會把專案上傳到 PyPI 和 TestPyPI。所以需要生成兩份獨立的 token,並把它們儲存到 GitHub 的倉庫設定中。

我們開始吧!?

  1. 訪問 pypi.org/manage/acco… ,建立一個新的 API token。 如果你已經在 PyPI 裡釋出過你的專案了,那麼你應該把 token 的範圍(token scope) 限定為只能操作這個專案的。你可以把新 token 命名為 GitHub Actions CI/CD —project-org/project-repo 之類的,方便辨識。生成 token 後不要關閉瀏覽器頁面—— token 只會顯示一次
  2. 在另一個瀏覽器選項卡或視窗中,開啟 GitHub 上你的專案頁面,點選 Settings 選項卡,然後點選左側邊欄裡的 Secrets
  3. 建立一個新的 sercret,命令為 PYPI_API_TOKEN,然後複製貼上第一步生成的 token。
  4. 訪問 test.pypi.org/manage/acco… ,重複之前的步驟,把 TestPyPI 的 token 儲存成 TEST_PYPI_API_TOKEN

注意:如果你還沒有 TestPyPI 賬號,你應該註冊一個。TestPyPI 和 PyPI 的賬號不共通哦。

建立 workflow

GitHub CI/CD 工作流程(workflow)是用 YAML 格式的檔案儲存到倉庫的 .github/workflows/ 目錄裡的。

我們建立一個 .github/workflows/publish-to-test-pypi.yml 檔案。

我們將從一個有意義的名稱開始,然後定義觸發 GitHub 執行此工作流程的事件:

name: Publish Python ? distributions ? to PyPI and TestPyPI

on: push
複製程式碼

定義工作流程的工作環境

現在,我們來為工作(job)新增初始設定。這個過程將執行我們稍後定義的命令。在這裡,我們將使用Ubuntu 18.04:

jobs:
  build-n-publish:
    name: Build and publish Python ? distributions ? to PyPI and TestPyPI
    runs-on: ubuntu-18.04
複製程式碼

簽出專案,構建發行版

然後,在該 build-n-publish 部分下新增以下內容:

    steps:
    - uses: actions/checkout@master
    - name: Set up Python 3.7
      uses: actions/setup-python@v1
      with:
        python-version: 3.7
複製程式碼

這些操作會把我們的專案原始碼下載到 CI 執行容器裡,然後安裝並啟用 Python 3.7 環境。

現在,我們就可以從原始碼構建 dist 了。在此示例中,我們將使用build包,所以假設專案裡已正確設定 pyproject.toml (請參見 PEP 517 / PEP 518)。

(注:emmm,其實這裡不寫 pyproject.toml 問題也不大)

提示:你可以使用任何其他方法來構建發行版,只要將準備好上傳的包儲存到 dist/ 資料夾中即可。

將下面的程式碼加到 steps 裡:

    - name: Install pypa/build
      run: >-
        python -m
        pip install
        build
        --user
    - name: Build a binary wheel and a source tarball
      run: >-
        python -m
        build
        --sdist
        --wheel
        --outdir dist/
        .
複製程式碼

釋出到 PyPI 和 TestPyPI

最後,新增如下程式碼:

    - name: Publish distribution ? to Test PyPI
      uses: pypa/gh-action-pypi-publish@master
      with:
        password: ${{ secrets.TEST_PYPI_API_TOKEN }}
        repository_url: https://test.pypi.org/legacy/
    - name: Publish distribution ? to PyPI
      if: startsWith(github.ref, 'refs/tags')
      uses: pypa/gh-action-pypi-publish@master
      with:
        password: ${{ secrets.PYPI_API_TOKEN }}
複製程式碼

這兩個 step 呼叫了 pypa/gh-action-pypi-publish GitHub Action:

第一個步驟無條件地將 dist/ 資料夾的內容上傳到TestPyPI。第二個步驟將其內容上傳到 PyPI,這一步只會對被打了標籤(git tag)的提交執行。

完事,收工!

現在,每當你將打了標籤(tag)的提交 push 到 GitHub 上時,此工作流程都會將其釋出到 PyPI。同時,對於任意 push ,它都會將其打包釋出到 TestPyPI,這對於提供 alpha 測試版本以及確保釋出渠道保持健康非常有用!


by("CDFMLR", "2021-01-17")
# 啊,今天昆明都下雪了,家裡巨冷。。。
# See you ❄️
複製程式碼

相關文章