🤖

PullRequestのマージ待ちの管理を自動化した

2025/02/13に公開

Renovateという自動ライブラリ更新botを利用し始めたのですが,マージの順番管理をする時間が増えてしまったので,その自動化をしました.

短く言うとこうです.

  • Renovate(またはDependabot)を利用していて
  • GitHubのマージ前にブランチを最新にするルールを利用していると
  • (Renovate以外の)PullRequestがなかなかマージできなくて困るので
  • マージ順を管理するGitHub ActionsであるMerge Masterを作りました
  • ついでに,Enable auto-mergeを押すだけでいい感じにマージされるようになって便利になりました

Renovateとは?

Renovateは,GitHubのホストするDependabotと同様に,リポジトリに含まれる依存関係のアップデートを自動で行ってくれるBotです.
導入すると,自動で古い依存パッケージを検出し,アップデートするPullRequestを作成してくれます.
作成されるPullRequestの例

また,Renovateではauto-mergeの設定ができます.例えば,PatchレベルとMinorレベルのアップデートなら,CIを通過次第自動でマージする,という設定ができます.
毎回手動でマージするのはかなり手間なので,便利です.

Renovateはマージ前にブランチを最新にするルールと相性が悪い

マージ前にブランチを最新にするルール

GitHubではBranch Protection Ruleという機能があり,PullRequestに対して色々なルールを設けることができます.
Require branches to be up to date before merging,つまりマージ前にブランチを最新にするというルールは,マージ先のブランチの変更を全て取り込んだブランチしかマージできないようにするルールです.
これによって,CI等で確認されたテスト結果が常に最新のマージ先の状態を反映していることを保証できます.

マージ先の変更を全て取り込んでいない時,PullRequest上にUpdate Branchというボタンが表示されます.
これを押すことで,最新の変更を取り込むことができます.

RenovateがPullRequestのマージを妨げてしまう

RenovateはUpdate Branch(正確にはRebase)を自動で行ってくれるのですが,これが人間の作ったPullRequestのマージを妨げてしまいます.
例えば,古くなったPullRequestでUpdate Branchボタンを押したとして,CIが終わる前に別のPullRequestがマージされると,また古くなってしまってマージができなくなってしまいます.
Renovateは分単位で古くなったことを検知してRebaseをしてくれるので,RenovateがRebaseを行う前の数分の間にUpdate Branchを押す必要が出てきてしまいます.

Renovateを利用していて,リポジトリが依存するライブラリが多く,またGroup[1]を設定しない場合では大量のPullRequestが同時に[2]作成されることになります.

Merge Masterを作った

この後に別解として挙げるMerge Queueを利用するのが一番良さそうだったのですが,OrganizationのPrivateリポジトリでは利用できませんでした.
なので,「Merge QueueってGitHub Actionsで自分たちで作れるんじゃない?」ということで,Merge Masterというものを作りました.

PullRequestがマージされたタイミングや,CIが終了したタイミングで,以下のように動きます.

  • OpenなPullRequestのうち,CIが成功していて,Enable auto-mergeされているPullRequestを列挙する
  • 最新の変更が取り込まれていて,CIが実行中のPullRequestがあれば,何もしない
  • なければ,人間のPullRequestを優先して,Update Branch(またはRenovateのPullRequestのrebase)を行う
    これによって,優先的に人間のPullRequestをマージしつつ,RenovateのPullRequestも自動でマージできます.

Merge Masterを利用するときは,Renovateの自動リベースを無効にすることをおすすめします.

また,副次効果として,PullRequestのマージを管理する必要がなくなり,Enable auto-mergeボタンを押すだけで,順番にCIを回しながらマージしてくれるので,かなり楽になりました.

別解

Merge Queue

Organizationの所有するパブリックリポジトリや,Github Enterprise CloudではMerge Queueという機能が利用できます.
その名の通り,PRにマージの順番待ちをさせることができる機能で,Renovateと人間のPullRequestの両方を順番にマージすることができます.

しかし,前述の通り,この機能はパブリックリポジトリまたはGithub Enterpriseでしか利用できません.
Organizationのプライベートリポジトリである私達のプロジェクトでは利用できませんでした.

Renovateのグループ機能を使う

大量にPullRequestが作成されるのが原因なので,Renovateのグループ機能を使ってそれらをまとめるという方法もあります.

ただし,グループを利用すると,万が一問題が起こったとき,

  • 同時にマージされた他のライブラリのアップデートもRevertすることになる
  • どのライブラリの更新が原因だったかの判別が困難になる
    というデメリットがあります.

人間の活動時間外にRenovateを動かす

RenovateはPullRequestの作成時間を指定することができます.
例えば,お昼の時間や業務時間外のみ動かすことで,人間があまりPullRequestを触らない時間にRenovateを動かせます.

デメリットとしては,以下があります.

  • 利用しているライブラリの数によっては業務時間外だけでは間に合わなくなる
  • トランクベース開発等で即時にリリースされる場合,バグが発生しても業務時間外で対応が遅れる
脚注
  1. ある条件に従って,複数のライブラリの更新を1つのPullRequestにまとめることができます. ↩︎

  2. 設定で1つに制限することも可能ですが,たまたまCIが落ちたり,人力でレビューが必要なものもあるので,複数同時に作成されるのが好ましいと思います.
    RenovateのPullRequestが落ち着くのを待っていると,場合によってはいつまで経ってもマージができなくなってしまいます. ↩︎

PrAha

Discussion