手動以上、Merge Queue未満
おはようございます。waturaです。最近、GitHubでMerge Queueという機能が広く使えるようになったそうです。
ただし、この機能はPublic RepositoryとPrivate Repository(Github Enterprise Cloudのみ)に対象が限定されているようです。私はGitHub Merge Queueにアクセスできなかったので、代わりのMerge Queueを作りました。
Merge Queueとは
Merge Queueは、Pull Requestをキューに入れ、順番にマージするためのツールです。キューは先頭に追加されたPRが最初に取り扱われるデータ構造です。イメージとしては、遊園地のアトラクション待ち行列のようなもので、先に並んだ人から順番にアトラクションを体験できると思ってください。
なぜMerge Queueが必要なのか
Pull RequestでApprove/LGTMをもらったらすぐにマージすれば、キューは必要ないと考えるかもしれませんが、以下のようなルールを設定している場合は別です。
- 最新のmainを取り込む必要がある
- mainにマージできるのはテストが通ったPull Requestのみ
例えば、PR-Aがマージされたら、PR-BはPR-Aがマージされた後のmainをmerge/rebaseしてくる必要があります。PR-Bがmainをmerge/rebaseした後に再度テストを通し、その後にmainにマージします。
もし、PR-Bがmainを取り込む前にPR-Cが最新のmainから作成され、PR-Bより先にテストが完了し、mainにマージされた場合、PR-Bは再びmainを取り込んでテストしなければなりません。このような状況では、PR-Bがいつまで経ってもマージできないという問題が生じます。以下に雑な図を添付しました。
アプリのビルドとテストは時間がかかるため、CIでは20分以上の時間がかかっています。私たちのiOSアプリチームは少人数ですが、5〜6件のPRが溜まることがあります。
では、20分かかる作業を5〜6件同時に行って、うまくタイミングを合わせながらマージを続けることは可能でしょうか?
それは難しいですよね。このような状況でMerge Queueが必要となります。
ただし、残念なことにGitHubのMerge QueueはPublic Repositoryか高価なプランの契約者のみ利用できます。
幸いにも、Merge Queueの機能を提供している他のサービスもあります。Aviatorがその一つです。
ただし、そこまで高機能なものである必要はありません。mainブランチに自動的に追従してマージされるだけで十分です。そこで、mainにPushがあった際に自動的にブランチを更新するGitHub Actionを作成しました。
3つのファイルをつくっていまして、
- 更新処理を行う keep_update.sh
- master が更新されたら更新処理をおこなう Github Actions
- Review のステータスがかわって、かつ、Approved だったら更新する
このGitHub Actionと自動マージを有効にすれば、効果的なマージが行われるようになります。
なお、複数のPRが存在する場合に、マージできないにも関わらず無駄にアップデートが続くという問題もありますが、PRの数がまだ多くない上にCIの利用量に余裕があるため、現時点では問題としては考えていません。