Stimulator

機械学習とか好きな技術話とかエンジニア的な話とかを書く

poetryを利用した動的なバージョン管理とGitHub ActionsによるPyPIへのrelease

はじめに

この記事を読んで出来る事

  • poetryによる外部モジュールバージョン管理
  • poetry-dynamic-versioningによる動的なバージョン付与
  • GitHub Actionsを利用したPython周りの基本的なCI/CD設定
  • GitHubのReleaseタグ付与をTriggerとしたPyPIへのアップロード

今後私がPythonで何かライブラリ作ろうと思ったらこれを実施するぞというメモです

 

 

poetryによるモジュールバージョン管理

バージョンをGitHubのタグで管理したい事の方が多いはず。
setup.pyを利用する場合は、一般的にsetuptools_scmを使うが、poetryはsetup.pyのようにbuild時にスクリプトを組み込むのは基本できないので、poetryの実装にpatchを当てる形で動的にバージョンを取得する。そのためのライブラリが以下のpoetry-dynamic-versiong。patchを当てている箇所はここ
github.com

git repository以外にもsubversionに対応していたり、独自のバージョンフォーマットも扱えるので、基本的にはこちらで問題なさそう。

 
pyproject.tomlを書いていく。

[tool.poetry]
name = "module_name"
version = "0.0.0"  # using poetry-dynamic-versioning
description = "sample tool"
authors = ["vaaaaanquish <6syun9@gmail.com>"]
license = "MIT"
readme = "README.md"
homepage = "https://github.com/vaaaaanquish/module_nam"
repository = "https://github.com/vaaaaanquish/module_nam"
documentation = ""

[tool.poetry-dynamic-versioning]
enable = true
style = "pep440"

[tool.poetry.dependencies]
python = "^3.7"
pandas = "^0.25.0"
matplotlib = "*"

[tool.poetry.scripts]
my-script = 'module_name:main'

[build-system]
requires = ["poetry"]
build-backend = "poetry.masonry.api"

 
githubのrelease tagで 「v0.0.1」 というフォーマットを採用していれば、以下を追記するだけで良い

[tool.poetry-dynamic-versioning]
enable = true
style = "pep440"

tool.poetry配下のversionが残る事だけが気がかりだが、「0.0.0」のようにしておけば問題にはならなそう。現状外すとpoetry build時にエラーとなる。

「v0.0.0」以外のformatを使っている場合は、READMEのConfigurationを参考にpattern、もしくはformatを設定する。

tag v0.0.2が打たれたrelease
tag v0.0.2が打たれたrelease

 
poetry-dynamic-versiongを使う場合には、poetryのdependenciesとしてではなく、poetryと同じレイヤーのPythonでinstallする必要がある。

pip install poetry
pip install poetry-dynamic-versioning

# poetry install
poetry update
poetry build

出力は以下のようになり、github release tagと連動してmodule生成が出来ている事が確認できる。

Building module_name (0.0.2)
 - Building sdist
 - Built module_name-0.0.2.tar.gz

 - Building wheel
 - Built module_name-0.0.2.whl


 

PyPIへのアップロード

手元からPyPIにpushするにはpoetry publishを使う方法が一般的。
以下のような形でpublishすれば良い。

poetry publish --build --username {hoge} --password {piyo}

基本的にはあまり手元からやりたくないので、GitHubにmasterマージされたりしたタイミングで自動でPyPIにアップロードしてもらいたい。後述する。


 

GitHab Actionsを用いたCI/CD

GitHub Actionsの設定ファイルを書いて、release tagをトリガーにして動的にアップロードするようにする。

# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries

name: Upload Python Package

on:
  release:
    types: [created]

jobs:
  deploy:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python
      uses: actions/setup-python@v1
      with:
        python-version: '3.x'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install poetry poetry-dynamic-versioning twine
    - name: Build and publish
      env:
        TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
        TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
      run: |
        poetry publish --build --username $TWINE_USERNAME --password $TWINE_PASSWORD

releaseタグが打たれた事をトリガーにしてmasterのコードをPyPIにpushするやつ。.github/workflows/python_publish.ymlにしてrepositoryに含める。
repo内の Settings > Secrets からユーザ名とパスワードを追加する。

repo内の Settings &gt; Secrets からユーザ名とパスワードを追加する。
repo内の Settings > Secrets からユーザ名とパスワードを追加する。

 

その他GitHubでやること

flake8、yapfなりのフォーマッタのCIを別途作る。
Settings > Branch protection rule からCIの必須化とmasterにpushできない設定をしておく。

Branch protection rule
Branch protection rule


PRからGitHub Actionsのbuildタスクが通らないとmergeできない事を確認する。

PRからGitHub Actionsのbuildタスクを確認
PRからGitHub Actionsのbuildタスクを確認

これで一連の設定はおわり。

setup.cfgやsetup.py、pipfileで書いていたものがほぼ不要になるし、PyPIのREADMEが勝手にMarkdownレンダリングされたものに変わっていたり、本当にやることが減って何かと便利。pipenvより早い、PEP 518 で規格化されている。良い感じ。