CIを待って自動でPRをマージするbotを作ると便利だった

GitHubを使っている場合「Pull Requestが作られたら自動でCIを実行し、グリーンになることを確認してからマージする」というのは割と広く採用されている開発のフローだと思います。PRごとにCIすることを確実にすることで、うっかりビルドを壊すようなPRをマージしてしまうことを防ぎ、いつの間にかmasterが壊れることを防ぎます。*1「CIが通っていないPRをマージしない」というのは、GitHubでそういう制約を設けることもできますし、そこまでやらずにチーム内の約束として共有しても良いでしょう。(ユビレジでは後者を採用しています。)

問題は、CIは一瞬では終わらないことです。ユビレジの場合、RailsのWeb appのCIには15分ほどかかりますし、iPad appのCIは30分かかります。CIのためのリソースにも限りがあるので、状況によっては既に15個CIのジョブが溜まっていて、完了までに1時間かかるなんてこともあります。もちろんこれは仕方がないことで、丁寧にコードレビューしてからPRをマージするような場合には問題にはなりません。どうせレビューするのに時間がかかるので、CI待ちの時間は相対的に小さなものとなります。しかし、ちょっとしたtypoの修正とか、コードレビューでokが出てからrebaseしたような場合だと、結構辛い。typoの修正は30秒くらいでレビューが終わったりしてすぐにマージしたくなるものですし、rebaseしただけのようなものも何十分もCIを待つのは苦痛です。CIを待たずにマージすることもできるようにはなっていますが、これはCIが動かないとか本当に急いでデプロイしたい場合の最後の手段なので、CIを待つのがダルい程度の場合にやっちゃうのは避けたい(避けるように訓練しています)。CIが完了するまでの間に他の作業を始めてしまったりすると、今度はマージするのを忘れたりするわけです。これはこれで辛くて、Webサイトのtypoの修正であれば早くデプロイした方が良いですし、下手をすると別のPRがマージされて再度rebaseしなくてはいけなくなったりして、とても辛い。

問題は、CIが完了すればマージして良いPRがあったら、CIが完了するまでそのことを覚えておいて、CI後に確実にマージしなくてはいけないことです。どう考えても、これは人類がやるべき仕事ではなくて、コンピュータにやらせるべき仕事です。つまり「CIが終わったらPRを自動でマージしてくれるbot」が必要です。必要だったので作りました。何ヶ月か動かしていますが、良い感じです。

f:id:soutaro:20160308113820p:plain

  • CI後に自動でPRをマージするには、ShipItというLabelを付けます
    • やっぱりこれはまずいな、と思ったら、Labelを取れば良い
    • 不安な場合は、コメントを付ければSlackに通知が行くので、どうしても止めたい人がそれを見たら反応します
  • GitHubのHookでHubotにCIの完了が通知されたら、PRを探して、ShipItラベルが付いていたらマージします

これが便利に使えるための暗黙の背景としては、

  • 開発チームは誰でもPRをマージできる(基本的には、PRを作った人が覚悟を決めてマージボタンを押す)
  • マージされるとWeb appはProduction環境に自動でデプロイされる
  • うっかり間違ったバージョンをデプロイしてしまっても、Herokuの機能で簡単にロールバックできる

などがあると思います。*2

とても便利なので、皆さんも簡単に実装できるようnpm packageにしました。

github.com

*1:とは言っても、複数のPRが同時にopenされる状況では、masterが壊れることを確実に防げるわけではありませんが。

*2:「開発チームは誰でもPRをマージできる」というのは、実は過去に問題になったこともあるのですが、それでも他の色々な条件を考えてポリシーとして受け入れています。