2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

uvとgithub actionsによる効率的なpythonパッケージのバージョン更新

Last updated at Posted at 2024-10-22

概要

uvで作成したpythonパッケージのバージョン更新をgithub actionsから実施するワークフローサンプルを作りました。主な機能は以下の通りです。

  • lint、format、testの実行
  • Gitタグを用いたバージョン更新
  • PyPIおよびTestPyPIへの公開

モチベーション

uvで作成したpythonパッケージのバージョン管理を一元化し、GitHubとPyPIの状態を自然に同期させるために、本サンプルを作りました。

通常、uvを使ってPythonパッケージを作成する際のバージョンアップ手順は以下の通りです:

  • pyproject.tomlproject.version を手動で更新
  • uv build && uv publish を実行(バージョンは pyproject.toml に基づいて決定)

GitHubでソースコードを管理する場合、さらに以下の作業が必要です:

  • 更新内容をGitHubに反映
  • 最新バージョンに対応するGitタグを追加

これらの手順には以下の課題があります:

  • バージョンがGitのタグと pyproject.toml で二重管理される
  • プルリクエスト時に pyproject.toml の更新を忘れることがある。忘れると、バージョン更新のためだけのコミットやプルリクエストが必要になる
  • GitHubへのプッシュとPyPIへの公開が別々に行われるため、GitHubとPyPIを同じ状態に保つには注意が必要

これらの課題を解決するために、以下を目指しました:

  • バージョン情報をGitタグで一元管理
  • GitHub Actionsでバージョン更新、ビルド、公開を同時に実行

これにより、pyproject.toml とGitタグのバージョンの二重管理を避けることができます。また、GitHub Actionsを通じてPyPIを更新することで、GitHubとPyPIの状態を意識せずに一致させることができ、開発の効率化につながると考えました。

利用ツール

  • パッケージ管理: uv
  • Lintツール: ruff, mypy
  • フォーマットツール: ruff
  • テストツール: pytest, bats, act
  • タスク管理: taskipy
  • ビルドツール: hatchling, hatch-vcs

使い方

GitHub Actionsでの実行

手順概要

  1. .githubディレクトリとその中身をGitHubリポジトリのデフォルトブランチにアップロードします。
  2. GitHubのSecretsにTEST_PYPI_TOKENPYPI_TOKENを登録します。
  3. GitHub > Setting > Actions > General > Workflow Permissionでread and write permissionsを選択
  4. GitHub > Actionsから該当のworkflowを自動実行します。

python-check.yaml

  • .pyファイルに対して、LintとFormatを実施します。
  • mainブランチへのプルリクエストをトリガーとします。

publish-to-testpypi.yaml

  • バージョン更新とTestPyPIへの公開を行います。
  • GitHub Actionsから手動で実行します。
  • 実行時に以下のオプションを指定できます(すべて任意):
    • バージョン番号: vで始まるセマンティックバージョニング形式の番号。空欄の場合、vで始まる最新のタグが使用されます。
    • Recreate Tag: チェックすると、指定されたバージョン番号が既に存在する場合、タグを作り直します。
    • Dry Run: チェックすると、リモートへのタグのプッシュやTestPyPIへの公開など、Workflow外に影響を残す処理を行いません。

publish-to-pypi.yaml

このファイルは、バージョンを更新し、PyPIにパッケージを公開するためのものです。
実行方法や指定可能なオプションは、publish-to-testpypi.yamlと同じです。

ローカルでの実行

環境構築

以下はM1 macOSでの手順です。他のOSを使用している場合は、適宜読み替えてください。

uv

# uvのインストール
curl -LsSf https://astral.sh/uv/install.sh | sh

dockerまたはdocker desktop

actを実行するために必要です。商用利用する際は、利用規約に注意してください。

act

このツールは、ローカル環境でGitHub Actionsを実行するために使用します。
Dockerコンテナ内でアクションを実行し、コンテナのサイズは3種類から選べます。ここではMediumサイズを選択します。

brew install act
act --container-architecture linux/amd64
# コンテナのサイズを聞かれたらMediumを選択

bats

bashのテストツールです。

# batsのインストール。ローカルでシェルのテストをしたい場合のみ必要
brew install bats

単体実行

テスト

uv経由でpytestを実行できます。

uv run task test

update_version.sh

workflowでのバージョン更新に用いるシェルスクリプトです。

sh .github/scripts/update_version.sh [-v version] [-i increment_type] [-n] [-d]

詳細は以下を御覧ください。
https://gist.github.com/jiroshimaya/5f4524ca296357e1c5347f1674217529

workflow

actでworkflowのテストを実行できます。

act [trigger] -j [jobname] -W [workflow yaml filepath] -e [event file path]

テスト

トリガーまたはjobを指定して実行します。

# triggerとしてpull_requestを指定
act pull_request -W .github/workflows/python-check.yaml
# jobを指定
act -j test -W .github/workflows/python-check.yaml

publish

原則として、dry-runで実行してください。テスト中に実際にpublishされると、管理が複雑になるためです。
workflow_dispatchがトリガーとなるジョブの場合は、eventファイルで必要な入力を指定します。

tests/workflow/event.json
{"inputs": {"version": "", "recreate": "true", "dry_run": "true"}}
act -j publish -W .github/workflows/publish-to-testpypi.yaml -e tests/workflow/event.json

複数のeventに対してテストしたい場合はスクリプトを使用してください。

uv run task test-workflow # batsで実行
uv run task test-workflow-py # pytestで実行

検討メモ

上記の形に落ち着くまでに検討したことのメモです。

バージョン管理の方法

バージョンをgit tagとpyproject.tomlのどちらで管理するかを検討しました。pyproject.tomlで管理する場合、sedコマンドで動的に更新し、git tagはその情報に基づいて作成されます。しかし、pyproject.tomlの書き換えによりコミット履歴が増えることが懸念されたため、git tagでの管理を選びました。

publishワークフローの設定

バージョンを手動で入力する代わりに、現在のタグに基づいて自動でインクリメントする方法も考えましたが、試しに使ったところ、次のタグが何になるかわからないことにストレスを感じたため、手動入力にしました。GitHub ActionsのUIから現在のタグは簡単に確認でき、バージョンアップの頻度も低いため、手動での記載が問題にならないと判断しました。また、rc(リリース候補)などの特殊なタグにも対応できる利点があります。

TestPyPIとPyPIに異なるタイミングでpublishする必要があるため、バージョンを空欄にして最新タグでのpublishを可能にしました。TestPyPIでのバグ修正後、同じバージョンをPyPIに上げやすくするため、recreateフラグで現在のタグを最新コミットに付け直すこともできます。

ビルドツールの選択

tagの作成やリモートへのpushはシェルスクリプトで行っていますが、自動インクリメントのためにhatchやbump-my-versionの使用も検討しました。しかし、uvとの相性問題のためか、エラーが発生し、解決に時間がかかりそうだったため、採用を見送りました。

ビルドバージョン決定ツールの選定

gitのtagに基づいてバージョンを決定するツールは複数ありますが、uvのデフォルトビルドバックエンドがhatchlingであるため、相性の良さそうなhatch-vcsを使用することにしました。

ワークフローの独立性

バージョンアップデートを独立したワークフローにすることも考えましたが、バージョンアップデートとpublishが2ステップになることが実際に試してみると煩わしかったため、独立させないことにしました。

GitHub Actionsのローカルテスト

GitHub Actionsのローカルテストには、pytestbatsのどちらを使うべきか検討中です。以下にそれぞれの利点と欠点をまとめます。

pytest

  • 利点: 追加のパッケージが不要で、Pythonでテストケースを記述できるため、Pythonに慣れている人には使いやすいです。
  • 欠点: シェルスクリプトのテストにPythonを使うのは、少し非効率に感じることがあります。また、実行に時間がかかるため、通常のpyファイルとは別に実行できるようにする必要があります。そのため、マーカーの管理が必要になります。

bats

  • 利点: シェルスクリプトのテストには自然な選択肢です。
  • 欠点: 構文に慣れる必要があり、batsのインストールが必要です。uvでのインストールが可能であれば手間は少ないですが、手元ではエラーが発生しました(パッケージ自体は存在しているようです)。

プルリクのマージによるタグの自動更新

mainブランチへのプルリクがマージされたときにtagを自動更新したほうが便利な可能性もあると思いました。ただ、minor、majorバージョンのインクリメントをどう運用するか悩みそうだったのと、複数のPRをたばねたアップデートを作りたいときもあるかと思い、採用しませんでした。ただ、PRのマージとパッチバージョンの更新を厳密に対応させる運用もありだと思いますし、必要に応じてやっても良いとは思います。

参考資料

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?