7 versioning with GitHub Actions
Case 1: Poetry-managed Packageにおけるgit tag releaseの紹介
パッケージ開発をしているGitHub repositoryにおいて,mainへのPull Requestがmergedされたタイミングでgit tagを作成するためのワークフローを紹介します.
workflow descriptions
今回設定するworkflow gittag-release.yml は以下のような内容とします
- トリガータイミング:
mainへのPull RequestがmergedされたタイミングでGitHub Actionsがキックする
- git tagの参照先:
pyproject.tomlのversionフィールドに記載されたsemantic versionをベースにgit tagを作成- すでに同一のgit tagが作成されている場合は,
Tag v$PYPROJECT_VERSION already exists. No release needed.というメッセージがGitHub Actions logに表示される mainへのPull Request作成時点でpyproject.tomlのversionフィールドはアップデートされているとする
- Release note:
- PRの内容をベースにリリースノートを作成する
workflow file
上記の動作条件を満たすGitHub Actions workflow設定例として以下です.
gittag-release.yml
name: Git tag release of poetry-managed package
on:
pull_request:
branches:
- main
types:
- closed
jobs:
release:
if: >
github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- name: Checkout main branch
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: Install poetry
uses: abatilo/actions-poetry@v2
- name: Get Poetry version
run: poetry --version
# Made use of $GITHUB_ENV to pass the variable cleanly to subsequent steps.
- name: Fetch version info from pyproject.toml
run: |
PYPROJECT_VERSION=$(poetry version --short)
echo "PYPROJECT_VERSION=$PYPROJECT_VERSION" >> $GITHUB_ENV
echo "The current pyproject version is v$PYPROJECT_VERSION"
- name: Create Git Tag and GitHub release
run: |
TAG=$(git describe HEAD --tags --abbrev=0 2>/dev/null || echo "none")
if [[ "$TAG" != "v$PYPROJECT_VERSION" ]]; then
echo "Creating a new release with tag v$PYPROJECT_VERSION..."
gh release create "v"$PYPROJECT_VERSION --generate-notes
else
echo "Tag v$PYPROJECT_VERSION already exists. No release needed."
fi
env:
GH_TOKEN: ${{ github.token }}gittag-release.ymlの解説
▶ on セクション
on:
pull_request:
branches:
- main
types:
- closedで使用されているonはworkflowが開始するタイミングを記述するセクションとなります.push時のみというシングルイベントの場合は
on: pushと記述しますが,forkとpushという2つのタイミングでキックしたい場合は
on: [push, fork]と指定できます.今回は,
mainへのPull RequestがmergedされたタイミングでGitHub Actionsがキックする
というキック条件にしたいので,
| 条件 | 設定内容 |
|---|---|
pushではなく,pull request eventのタイミングでキック |
on: pull_requestと設定 |
branchはmainのみ |
branches:でmainのみを指定 |
PRがclosedかつmergeされたタイミングでキックされる |
types: closedを指定 |
pull_requestやpushといったeventに応じて設定できるtypesは異なってきます.eventに応じた指定可能typesは GitHub Actions > Events that trigger workflowsを参照してください.
▶ Pull Request Mergedタイミングへの限定
workflowのキックタイミングは on: pull_requestsとtypes: closedで指定しましたが,これではPRがmergedされないでclosedされた場合も動いてしまいます.
PRがclosedかつmergeされたタイミングでキックされる
ことを確保するためには,jobsセクションで条件を絞る必要があります.その設定箇所が以下となります.
jobs:
release:
if: >
github.event.pull_request.merged == trueif セクションでjobsが実行される条件をより細かく指定することができます.今回はPR mergedのみとしたいので github.event.pull_request.merged == trueと設定します,
if: >は改行を許容する形での記述のため(=今回は可読性のため)に使用したSyntaxとなりますが,実質的には
jobs
release:
if: github.event.pull_request.merged == trueでも同じ動作をします.
▶ fetch-depthの設定
fetch-depthはGitHub Actions workflowsがfetchするcommit logの数を指定する項目です. すべてのcommit logをfetchした上でjobが動作する必要がある場合には,featch-depth: 0と設定します.
基本的には,featch-depth: 1で十分ですが,過去のcommitを殺傷してchangelogを作成したい場合はfeatch-depth: 0と設定したりします. 今回は,gh release create --generate-notesコマンドを用いて,last releaseから最新のreleaseまでの差分commitをベースにリリースノートを作成したいので featch-depth: 0と設定します.
▶ pyproject.tomlから最新のsemantic versionを取得
poetry version --shortコマンドはpyproject.tomlのversion fieldを参照してsemantic versionを返すコマンドです. このコマンドを使用するため,jobsでpoetry setupを実行する必要があります.その設定箇所が以下です:
- name: Install poetry
uses: abatilo/actions-poetry@v2その後,poetry version --short)を実行します.このとき,以下のように echo "PYPROJECT_VERSION=$PYPROJECT_VERSION" >> $GITHUB_ENVを忘れずに設定してください.
# Made use of $GITHUB_ENV to pass the variable cleanly to subsequent steps.
- name: Fetch version info from pyproject.toml
run: |
PYPROJECT_VERSION=$(poetry version --short)
echo "PYPROJECT_VERSION=$PYPROJECT_VERSION" >> $GITHUB_ENV
echo "The current pyproject version is v$PYPROJECT_VERSION"ワークフロージョブ内で環境変数を後続のステップで利用可能にするには,その環境変数を定義し,その値をGITHUB_ENV環境ファイルに書き込む必要があります. 注意点として,デフォルトの環境変数である GITHUB_* や RUNNER_* の値を上書きすることはできません.
▶ git tagの作成
GitHub CLIコマンドのgh release create <git-tag-version>を用いることで
<git-tag-version>のgit tag作成 & GitHub上でのRelease--generate-notesオプションを利用することで,最後のreleaseからのcommitをベースにrelease noteを作成してくれます
このとき,GitHub repositoryへ直接git tagをpushする関係上,同一ステップ内部で
env:
GH_TOKEN: ${{ github.token }}を設定する必要があります.github.tokenはデフォルトで設定されているpropertyで,リポジトリにインストールされた GitHub App の代わりに認証を受けるためのトークンです. デフォルト設定のまま実行してしまうとResource not accessible by integration errorに直面してしまいますが,こちらのノートの設定に従って 該当レポジトリのWorkflow permissionsにて,
Read and write permissions
のレベルを選択する必要がある点に注意してください.