🚀

PDM + GitHub Actions でテストとパッケージングを自動化する

2023/03/13に公開

PDMを使ってパッケージ管理している Python プロジェクトで GitHub Actions を使ってテストや静的解析、パッケージングを自動化する方法について記述する。

なお、 PDM のインストールや初期設定については過去に書いた記事があるのでこちらを参照。

環境

  • macOS: Ventura 13.0.1
  • Python: 3.11.2
  • PDM: 2.4.5

PDM の GitHub Action

PDM から提供されている GitHub Action を使用する。

https://github.com/marketplace/actions/setup-pdm

以降では hamakou108/depwatch という PDM のプロジェクトをベースに GitHub Actions の設定内容を見ていく。

静的解析とテスト

テストや静的解析の Action のジョブの設定内容は以下の通り。

.github/workflows/ci.yml
jobs:
  check-and-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11"]
    steps:
      - uses: actions/checkout@v3
      - name: Setup PDM
        uses: pdm-project/setup-pdm@v3
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install dependencies
        run: pdm install
      - name: Check type
        run: pdm run check_type
      - name: Check Lint
        run: pdm run check_lint
      - name: Check Format
        run: pdm run check_format
      - name: Test
        run: pdm run test

まず name: Setup PDM のステップでは pdm-project/setup-pdm を使用するとともに with で設定を行っている。 python-version: ${{ matrix.python-version }} を指定することで strategy.matrix.python-version で指定した各バージョンの Python で Action が起動する。

name: Check type 以降のステップで静的解析やテストを実行している。実行用のコマンドは pyproject.toml に定義している。

pyproject.toml
[tool.pdm.scripts]
check_type = "mypy depwatch tests"
check_lint = "flake8 depwatch tests"
check_format = "black --check depwatch tests"
test = "pytest tests"

パッケージング

ここでは Release Please も併用してパッケージングを行う例を示す。 Release Please の設定の詳細に関しては過去に書いた記事があるので、そちらを参照。

パッケージングの Action のジョブの設定内容は以下の通り。

.github/workflows/release.yml
jobs:
  create-the-release-pull-request-and-release:
    runs-on: ubuntu-latest
    steps:
      - uses: google-github-actions/release-please-action@v3
        id: release
        with:
          release-type: python
          package-name: depwatch
      - uses: actions/checkout@v2
        # these if statements ensure that a publication only occurs when
        # a new release is created:
        if: ${{ steps.release.outputs.release_created }}
      - name: Setup PDM
        uses: pdm-project/setup-pdm@v3
        with:
          python-version: "3.11"
        if: ${{ steps.release.outputs.release_created }}
      - name: Publish package
        run: |
          pdm config repository.pypi.username "__token__"
          pdm config repository.pypi.password ${{secrets.PYPI_TOKEN}}
          pdm publish
        if: ${{ steps.release.outputs.release_created }}

前段階として各 PR がマージされたタイミングで Release Please によってリリース PR が作成され、この中に CHANGELOG の更新やパッケージ管理ツール内のバージョン番号の更新が含まれている。このリリース PR がマージされたとき、 uses: google-github-actions/release-please-action@v3 のステップで Release Please によってタグの作成、リリースノートの作成が行われる。以降のステップがパッケージングに関わる部分で、これらはリリース PR がマージされた場合のみ実行されるようにするため、 if: ${{ steps.release.outputs.release_created }} でそれを判定している。

name: Publish package のステップではパッケージのアップロードに必要な認証情報として PyPI のアクセストークンを設定した上で pdm publish を行っている。

PyPI アクセストークンのスコープについて

PyPI アクセストークンのスコープとして最初はアカウント全体 (Entire account (all projects)) のスコープしか選択できないが、一度 PyPI にパッケージをアップロードしてプロジェクトを作成するとそのプロジェクト限定のスコープを選択できるようになる。ただしトークンのスコープを後から変更することはできないため、一度アカウント全体スコープのトークンでプロジェクトを作成した後、プロジェクトスコープのトークンを作り直すと良い。

認証情報の保管場所として Repository の Actions Secrets を利用することで、 GitHub Actions の実行ログ上で認証情報をマスクすることができる。 gh コマンドで CLI から設定できる。

$ gh secret set PYPI_TOKEN
# ダイアログが表示されるのでトークンを入力する
$ gh secret list
PYPI_TOKEN  Updated 2023-03-10

Discussion