ブランチ名によるマイルストーン管理の自動化 [GitHub Actions]
概要
プロジェクトをマイルストーンで管理している場合にブランチ名を milestone/v1
や release/v1
のようにすることがあるかと思います。
手動でマイルストーンを編集するのは手間なので自動化します。
ワークフロー
マイルストーンブランチが作成/削除されたときにマイルストーンを作成/クローズします。
また PR のマージ先がマイルストーンブランチだった場合にマイルストーンをセットします。
name: Milestone
on:
create:
delete:
pull_request:
types: [ opened, edited ]
branches:
- milestone/**
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
jobs:
create-milestone:
if: github.event_name == 'create' && startsWith(github.event.ref, 'milestone/')
runs-on: ubuntu-20.04
timeout-minutes: 2
env:
BRANCH: ${{ github.event.ref }}
steps:
- name: Create a milestone
run: |
set -x
milestones=$(gh api -X GET /repos/${GITHUB_REPOSITORY}/milestones -f state=all)
if ! $(echo "${milestones}" | jq ". | any(.title == \"${BRANCH#milestone/}\")"); then
gh api -X POST repos/${GITHUB_REPOSITORY}/milestones -f title=${BRANCH#milestone/}
elif $(echo "${milestones}" | jq ". | any(.title == \"${BRANCH#milestone/}\" and .state == \"closed\")"); then
milestone_number=$(echo "${milestones}" | jq ". | map(select(.title == \"${BRANCH#milestone/}\")) | first | .number")
gh api -X PATCH repos/${GITHUB_REPOSITORY}/milestones/${milestone_number} -f state=open
fi
close-milestone:
if: github.event_name == 'delete' && startsWith(github.event.ref, 'milestone/')
runs-on: ubuntu-20.04
timeout-minutes: 2
env:
BRANCH: ${{ github.event.ref }}
steps:
- name: Close a milestone
run: |
set -x
milestone_number=$(gh api -X GET /repos/${GITHUB_REPOSITORY}/milestones --jq ". | map(select(.title == \"${BRANCH#milestone/}\")) | first | .number")
gh api -X PATCH repos/${GITHUB_REPOSITORY}/milestones/${milestone_number} -f state=closed
set-milestone:
if: github.event_name == 'pull_request'
runs-on: ubuntu-20.04
timeout-minutes: 2
env:
PR_NUMBER: ${{ github.event.number }}
steps:
- name: Set a milestone
run: gh pr edit ${PR_NUMBER} --milestone ${GITHUB_BASE_REF#milestone/}
マイルストーンブランチが作成されたとき
マイルストーンを新規作成します。
既にクローズ済みのマイルストーンがある場合は再オープンします。
再オープンするときはマイルストーン番号が必要なのでリストから取得します。
ブランチやタグの作成 (create
) かつマイルストーンブランチのときだけ実行します。
${BRANCH#milestone/}
でブランチ名からマイルストーン名を抽出します。
マイルストーンブランチが削除されたとき
マイルストーンをクローズします。
削除してしまうと完全になかったことになってしまうのでログを残す目的でクローズしています。
マイルストーンの削除
何かしらのフローで削除が必要な場合は以下のコマンドで削除できます。
gh api -X DELETE repos/${GITHUB_REPOSITORY}/milestones/${milestone_number}
ブランチやタグの作成 (delete
) かつマイルストーンブランチのときだけ実行します。
PR にマイルストーンをセットする
PR のマージ先がマイルストーンブランチの場合にマイルストーンをセットします。
pull_request
がオープンまたは(マージ先が)変更されたときかつマイルストーンブランチのときだけ実行します。
逆マージについて
逆マージを PR ベースでやるとブランチの自動削除ができなくなるのであまりやらないと思いますが、もしやる場合はフィルターにヘッドブランチの判定を追加した方がいいかもしれません。
if: >-
github.event_name == 'pull_request' &&
!startsWith(github.head_ref, 'milestone/') &&
github.head_ref != 'main'
余談:マイルストーンの編集をトリガーにするには?
ブランチをトリガーにした場合のワークフローを紹介しましたが、逆にマイルストーン (milestone
) をトリガーにすることを考えてみます。
マイルストーンが作成されたとき
ブランチをどこから切るかは人間が判断するしかないので自動化は難しそうです。
もちろん明確なルールがあれば可能だと思います。
マイルストーンがクローズされたとき
マイルストーンが削除またはクローズされたときにトリガーします。
ブランチがどこにも取り込まれていない場合でもそのまま削除されてしまうので注意が必要です。
クローズされたときにトリガーするコード例です。
name: Milestone
on:
milestone:
types: [ closed ]
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
jobs:
delete-branch:
if: github.event_name == 'milestone'
runs-on: ubuntu-20.04
timeout-minutes: 2
steps:
- run: gh api -X DELETE repos/${GITHUB_REPOSITORY}/git/refs/heads/milestone/${MILESTONE}
env:
MILESTONE: ${{ github.event.milestone.title }}
結論
マイルストーンの編集をトリガーにブランチを操作するのは運用が難しそう。
どこかへ通知するくらいがいいのかもしれません。
Discussion