Github の Pull Request のレビュー後、APPROVED の数に応じてラベルをつける運用を自動化します。APPROVED 後にコミットがあった場合、自動的に APPROVED が取り消される運用(画像) での運用を想定しています。*1
任意の数の APPROVED を取得した PR の集合を A とし、releasable ラベルが付与されている PR の集合を B とした場合、動作は以下になります。
- 差集合 A - B に対して releasable ラベルを付ける
- 差集合 B - A に対して releasable ラベルを剥がす
差集合 B -A は主に APPROVED 後にコミットすることで発生します ((Github のブランチ設定で Dismiss stale pull request approvals when new commits are pushed 設定をしている場合)))
レポジトリ
https://github.com/kyagi/shamshir
実行
$ node shamshir.js --owner kyagi --repo awesome-project --label releasable --quorum 2
ログ
$ cat combined.log {"level":"info","message":"Shamshir started.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:22"} {"level":"info","message":"Shamshir got pulls: 2602,2598,2596,2575,2573,2557,2553,2551,2540,2539,2481,2478,2295,2281,1981,1951,1685","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:22"} {"level":"info","message":"Shamshir added releasable label to pull/2598.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:24"} {"level":"info","message":"Shamshir added releasable label to pull/2596.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:24"} {"level":"info","message":"Shamshir added releasable label to pull/2575.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:25"} {"level":"info","message":"Shamshir removed releasable label from pull/2573.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:26"} {"level":"info","message":"Shamshir added releasable label to pull/2551.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:28"} {"level":"info","message":"Shamshir added releasable label to pull/2540.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:29"} {"level":"info","message":"Shamshir added releasable label to pull/2539.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:30"} {"level":"info","message":"Shamshir added releasable label to pull/2478.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:31"} {"level":"info","message":"Shamshir added releasable label to pull/2295.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:32"} {"level":"info","message":"Shamshir added releasable label to pull/1951.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:34"} {"level":"info","message":"Shamshir finished.","mode":"live","owner":"kyagi","repo":"awesome-project","service":"shamshir","timestamp":"2022-01-31 00:54:34"}
Github API (REST API) について
Github API では Issue と Pull Request でエンドポイントを共有しています("shared" actions for both features)。API Reference の Issue ページにはラベル処理がありますが Pulls ページにはラベル処理がありません。だからといって Pull Request にラベルをつけられないというわけではなく、Issue API のエンドポイントを使い key として pull_request を使用することで(shared) Pull Request に対してもラベル処理が可能です。
Note: GitHub's REST API v3 considers every pull request an issue, but not every issue is a pull request. For this reason, "Issues" endpoints may return both issues and pull requests in the response. You can identify pull requests by the pull_request key. Be aware that the id of a pull request returned from "Issues" endpoints will be an issue id. To find out the pull request id, use the "List pull requests" endpoint.
https://docs.github.com/en/rest/reference/issues
Every pull request is an issue, but not every issue is a pull request. For this reason, "shared" actions for both features, like manipulating assignees, labels and milestones, are provided within the Issues API. https://docs.github.com/en/rest/reference/pulls
トップの画像では集合の図を載せていますが、実装で集合演算は使用していません。JavaScript に組み込みの集合演算がないのと、1 ページ 30 個 程度の Pull Request が処理対象の場合、集合演算よりループで処理した方が簡単だからです。
運用方法について
EC2 や ECS で動かすスタンドアローン的な運用と Github Actions で動かす運用の 2 つを考えています(Github Actions は将来サポート予定)。それぞれの長所/短所を以下に挙げます。
スタンドアローン | Github Actions | |
---|---|---|
設計/実装 | 制約がなく自由度が高い | Github Actions の方法に則る必要があり workflow/action 内でできることに制約がある |
コスト | 走らせるためのリソース(EC2 or ECS) にコストがかかる | 条件内の実行時間とストレージ容量であればコストは無料 |
認証/認可 | Personal Access Token が必要 | 入力として GITHUB_TOKEN が使える |
参考情報
Github API Reference(REST API): https://docs.github.com/en/rest/reference/pulls
octokit/core.js: https://github.com/octokit/core.js/
*1 Dismiss stale pull request approvals when new commits are pushed 設定をしている場合