ぺろぺろ - Github pull request bot framework -
名古屋Ruby会議03で発表した。
発表資料
関連記事
原稿
導入
自己紹介
こんにちは、mzpです。
大須はたまにくるので、この大須演芸場も気になってはいたんですが、なかなか入る機会がありませんでした。 まさかこっち側に立つのが最初だとは思っていませんでした。
よろしくお願いします。
会社紹介
仕事では、Misocaという会社でMisocaというWebサービスを作っています。この名古屋Ruby会議のスポンサーでもあるそうです。すごいですね。
Github
会社としてのMisocaはおいといて、サービスとしてのMisocaはGithubのプライベートレポジトリ上で開発を進めています。そのためGithubが開発の中心になります。
プルリクエスト
さらに言えばプルリクエストが中心になります。そのためプルリクエストにまつわるさまざまなルールや運用が生まれます。例えば「コンフリクトに気付いたら声をかけてあげようね」ですとか「githubでコメントしたらSlackでも教えてあげよう」などなどなどです。 最初はこれでもよいのですが、だんだんと面倒になっていきますよね。
bot
そこでbotを作り、こういった運用を自動化しました。
このbotは機能を固定したものでなく、gemによって拡張できるbot frameworkとして作りました。 今日はそのbot frameworkを紹介したいと思います。
使い方
まずは簡単に使い方を話します。
Deploy to heroku
レポジトリに deploy to herokuボタンがあるので、押せばherokuにデプロイできます。
Webhookの設定
あとはGithubでWebhookの設定をすれば動きます。
カスタマイズ
デプロイされたgitレポジトリをcloneしてきてGemfileを更新すれば挙動を拡張できます。 例えば、コンフリクトしているプルリクエストにラベルを自動でつけるようにしたい場合は、Gemfileに gem ‘prpr-conflict_label’ と追記してpushすればOKです。
既存プラグインの紹介
次は各gemでできることを紹介していきます。
prpr-checklist
各プルリクエストに自動でチェックリストを投稿するgemです。
機能を更新したけどヘルプを更新するのを忘れた、とか、バリデーションルールを追加したら既存データと矛盾するようになってしまった、みたいな単純な失敗をしてしまうことありますよね。 そういうときは古来よりチェックリストを使うとよいと言われているので、それです。
チェックリストの内容
チェックリストの内容は、レポジトリ上にあるCHECKLIST.mdという名前のファイルを使うようにしているので、変更も容易ですし、バージョン管理もできます。
余談: これを作ったときにはなかったんですが、今のGithubにはプルリクエスト テンプレートがあるので、そっちつかってもいいかもしれませんね。
prpr-mention_comment
コメント中に「@xxx 」といった文字列が含まれていた場合は、そのままSlackに転送するgemです。
Githubの通知をSlackに流している方も多いと思うんですが、GithubコメントでメンションしてもSlackではメンションにはならないんですよね。 これだとなかなか気づけませんし、気付いてもらえません。
Slackの通知は気付いてくれる人が多いので、これで解決です。
アカウント名の対応
工夫ポイントとしては、Slackのユーザ名とGithubのユーザ名が違う人もいるので、ユーザ名の変換もやっていることです。 これはレポジトリのルートに以下のようなファイルを置くことでカスタマイズできるようになっています。
prpr-gemfile
gemGemfile.lockのdiffを確認して、メジャーバージョンアップとマイナーバージョンアップをしている箇所にコメントをいれるgemです。
定期的にbundle updateをしてプルリクエストを送るbotを飼っているんですが、毎回Gemfile.lockの差分を見ながら「ふむふむこれはbugfixだけだし、いれていいでしょ」「う、こっちはメジャーバージョンがあがってる。ちゃんと調べなきゃ」というのをやるのは面倒なので自動化しています。
prpr-conflict_label
何本もプルリクエストが並行して動いてる状況だと、ちょいちょいコンフリクトが発生します。ただ、Githubのプルリクエスト一覧ではどれがコンフリクトしているかがわからず、個別のプルリクエスト画面をひらいて初めてコンフリクトしていることがわかります。
マージイベントが発生するたびに全プルリクエストを確認し、コンフリクトラベルのつけはずしをするようにしましたgemです。
これで一覧をみるだけでどれがコンフリクトしているかが分かるようになります。
まとめ
以上が、標準的なprprのgemです。 たぶんだいたいのシチュエーションで便利だと思います。 ボクも自分のプライベートプロジェクトで使っていたりします。
Misoca開発フローとの統合
これらとは別にMisocaでの開発フローにあわせて作ったgemもあります。 次はこういったgemについて紹介していきたいと思います。
開発フロー
まずは、我々の開発スタイルについて簡単に説明します。
- 各開発者がプルリクエストを作る。このときはまだWIP(work in progress; 作業中)というラベルをつけておき、まだレビューしなくてもいいよ、ということを明示します。
- プルリクエストが完成したら、レビューを依頼する。 指摘がついたら対応する。
- 最低1人、できれば2人がOKを出したあとでマージする。
- いくつかマージされたプルリクエストがたまってきたらデプロイする。
その他の特徴
補足情報としては、
- レビュー担当者などは特に固定せず、互いにプルリクエストレビューを行なう
- 基本的にはSlackを使ってやりとりする
といった特徴もあります。
prpr-review_label
レビュー依頼部分を支援するgemです。 このgemはREVIEWというラベルがついた場合は、Slackに「レビュー待ちにしました」という通知を流します。
この通知にはラベルをつけた人の名前とアイコンを使うようにしているので、誰が依頼をしたかがすぐ分かるようになっています。
prpr-lgtm
次は「マージする」という部分を支援するgemです。最初は雰囲気でやっていたのですが、
そこで、 * OKの数をラベルとして表現する * 二人がOKをした場合は、プルリクエストにassignされている人にメンションを飛ばす というbotを作りました。
一覧をみるだけで何人がOKをだしているかがわかる、二人がOKを出いた瞬間に気づけるようになり、テンポよくマージしていけるようになりました。
自己
余談ですが、このgemを作る過程でうっかり暴走させてしまい、同僚に大量のメンションを飛してしまい、たいへん申し分けない感じになりました。ごめん。 これは自分のコメントに反応してさらにコメントをつけてしまい、それに反応して…という図です。
prpr-merged
「マージする」という部分を支援するgemはもう一つあります。
「マージする」という行為は影響が大きいので、できるだけみんなに把握しておいてほしいです。 そのため、マージが発生するとslackに通知されるgemを作りました。
もちろんslackのgithub連携機能でも同じ情報は流れてきますが、よりマージを目立たせるという効果があります。
デプロイ
最後はデプロイの支援です。
Misocaのデプロイはチャット経由でできるようになっています。
- チャットで「@bot デプロイしたい」と発言する
- botがデプロイ用の内容をまとめたプルリクエストを作る。 これはマージ先がmasterではなくリリース用ブランチになっています。
- デプロイ用のプルリクエストをマージすると、デプロイプロセスがはじまる
- デプロイされる
という流れです。
このうち、3の「デプロイ用のプルリクエストをマージすると、デプロイプロセスがはじまる」の部分はprprがやっています。
prpr-code_deploy
Misocaのデプロイ作業はAWSのCodedeployを使っています。 codedeployにコミットIDを送ると、デプロイしてくれます。
そこで、デプロイ用のブランチにマージされた場合は、AWS codedeployにそのコミットIDを送り、デプロイプロセスがはじまるようにしています。
まとめ
以上がMisoca開発におけるprprの使い方です。
あとはこのprprを作ったときの話をしていきたいと思います。
先行事例
作るときに参考ににしたものや、あとから見つけたやつなどがあるのでそれを紹介します。
クックパッド
チェックリストの投稿などはクックパッド開発ブログで紹介されています。 ただこれは自分たちで作っていこうな、という趣旨の記事なので、汎用のbotがあるわけではありません。
trailing space bot
Github上で動作するbotというのもいくつかあります。 たとえば、末尾のスペース(trainling space)を検知して修正するプルリクエストを作成するbotもいます。
これはそいつが送ってくるプルリクエストです。
しかしこれは挙動が固定されているため自分たちにあわせて機能を追加・削除していくのは困難です。
拡張可能なbot
プラグインで挙動を拡張できるbotは多数存在しており、開発関係だとhubotやrubotyなどが有名な気がします。
ただこれはチャット経由でなにかする、というものがほとんどで、プルリクエストに反応して何かをするものは見付けれませんでした。
設計
目標
自由に拡張できるgithubのbotフレームワークはないことがわかったので、自分で作ることにしました。 作成時に標榜した目標は以下の通りです。
gemにより挙動を拡張できる。 コア部分と、自分たちの開発を便利にするための機能を切り離す。
botの設定変更は誰でもできるようにする。 これは先ほど紹介したチェックリスト投稿が分かりやすいと思うんですが、チェックリストの内容変更は管理者だけができる、ということになると、チェックリストへの追加作業のハードルがあがってしまいます。そこで、レポジトリ上のファイルが設定ファイルになるようにし、レポジトリにコッミトできる人間なら誰でも設定変更できるようにしました。 設定変更もgitで履歴管理されるようになるのもメリットです。
herokuで動く。 自分でちゃんとデプロイするの大変ですしね。
すばやく作る。 とりあえず日々の運用を楽にするのが先決なので、わりとさっさと作りたかったです。
構成
構成としては以下のようになっています。
- どのイベントに反応するかを決めるHandler
- 挙動を決めるAction
- 環境変数やレポジトリ上のファイルから設定を読み込むsettings
- Slack等に通知するpublisher
といった部分で構成されています。 またイベントを受け取る部分は通常のwebhookの他にテスト用のCLIもあります。
各プラグインがやるのがhandler/actionあたりです。
例: Handler
マージ通知をするgemを例に、もうちょっとだけ具体的に説明します。
マージだけに反応するればいいので、handlerは以下のようになっておりプルリクエストのcloseに反応するようになっています。
例: Action(½)
Actionはこのようになっております。
- 本当にマージされたかどうかの判定
- publisher経由で通知する
例: Action(2/2)
送信するメッセージは、このように環境変数から読むようになっています。
やらなかったこと
prprは最初のバージョンを早めに出して、プルリクエストにまつわる運用を楽にしたかったので、割り切って作った部分もいくつかあります。
WebUIを作らない。 設定画面等をつけようかとも思ったんですが、認証とかを考えると面倒そうだったのと、Webhook受け取るだけでとりあえず動くだろ、ということでWebUIをつけるのはやめました。
Bitbucketのことは忘れる。 最初はGithubとbitbucketの両対応をしようかと思ったんですが、抽象レイヤーを作るのが面倒そうだったのと、bitbucketを使う予定がないので忘れることにしました。
命名
次は名前の話ですね。
コードを書きはじめる前に名前を決める派なので、けっこう初期からこの名前でした。 プルリクエスト=PRに反応するbotつくりたいけどなにがいいかなー?って相談しました。 よくみると夜中の12時くらいに決めてるので、まあそういうことだよなって気持ちになりました。
ヲタクっぽくて気にいっています。
よかったところ
あとは感想です。
- gem化したのでどこでからがプラグインかが明確になって、クラス設計等がしやくなった
- CLIでテストできるようにしたのでデバッグが楽
- 外部のAPIを叩く部分をすべてプラグインにしたので、本体のspecでモックを作るのが簡単だった。
苦労したところ
- githubの新機能(Approve/Project/…)などの機能がなかなかAPIにおりてこない。 ReviewのApproveのAPIがくるまで一ヶ月ほど待ちました。
- PreviewAPIはoctokitにはいってこないので、わりと無理矢理呼ぶことになる。 こんな感じです。
- gemに分割したのでgemspecを書いたり、レポジトリを大量に作るのが面倒だった。
まとめ
まとめます。
今朝書いたシェルスクリプト
こんなシェルスクリプトをいくつか書いてレポジトリにコミットした。
./bin/docker/bundle
#!/bin/sh docker-compose run --rm app bundle "$@"
./bin/docker/rails
#!/bin/sh docker-compose run --rm app bundle exec rails "$@"
できること
./bin/docker/bundle install
とか
./bin/docker/rails db:migrate
とかができるようになって便利。
今までは docker-compose run app bash
してその中で実行していたが、履歴が残らず不便だったのが解消された。 docker-compose run app ....
を毎回打ってもいいんだけど、長くてダルい。
全部
⛄️飛騨・高山旅行
雪と合唱造りの組合せが見たかったので行ってきた。
道中
向う途中でひるがの高原に寄ったが、冗談みたいな量の雪が積もっていた。
古い町並み(昼)
高山市内の古い町並みは予想通りいい感じだった。
謎の器具で雪を落している。
寿司はうまい。
団子もうまい。
牛串も当然うまい。
古い町並み(夜)
夜になるとさらにいい感じになる。
⛄️
ものすごく寒いのでうっかりラーメンを食べる。めっちゃうまい。
合掌造り
本当は白川郷に行くつもりが雪が怖くて断念した。かわりに、高山駅近くの飛騨の里に行った。
立ち入り禁止の札が埋まってて迫力がある。
日が落ちるとライトアップがはじまる。
めちゃくちゃ寒いので火に集まる。
氷菓 舞台巡り
氷菓の舞台巡りをしたが「劇中だとこんなに雪が降ってなかったよな?」という疑問がついて回った。
いろいろな箇所に貼ってあったポスター。
図書館。
劇中で二人で閉じ込められていた神社。ここに放置されたら死ぬのでは?
君の名は 舞台巡り
君の名はの舞台になった飛騨古川も見てきた。
アピールしている。
「君の名はを見て来ました」と言ったら、伝票に書かれた。
近くの美術館で君の名は展をやっていたので見てきた。
等身大パネルより背景の雪の量が気になる。
感想
- 雪が大量にあってたのしい
- 寒い。痛いくらい寒い。
- 日がたつにつれどんどん体調が悪化していき、帰ってきてから風邪を引いた
🙆prpr-lgtm
会社ではPull Requestに対して2人がApproveしたのちにマージするという運用をしているので、これを補助するbotを作った。 2人がApproveしたときに、Assigneeに対してメンションが飛ばす。
bot
prprへのプラグインとして実装した: https://github.com/mzp/prpr-lgtm。
解決したい問題
Pull Requestに対して2人がApproveしたのちにマージするという運用には以下の2つの問題点があった。
- Approveした人数がPullRequest一覧では分からない。
- Approveした人数が2人に達したことに担当者が気付きづらい。
prpr-lgtm
ラベルによるApprove件数の表示
Approveの件数にあわせてラベルの追加・削除を行なう。
LGTM:1
: 1人がApproveしているLGTM:2+
: 1人以上がApproveしている
メンション
2人がApproveしたときに、Assigneeに対してメンションが飛ばす。 このとき本文にしている「Let's Get This Merged」は Rebuild: Aftershow 133: Let's Get This Merged (gfx) が由来。
余談
Pull Request Review CommentのAPIがでるまでは「LGTM」というコメントに反応するようにしていた。 そのせいで「LGTMではないです」といったコメントにも反応してちょっと大変だった。
また、開発中には自分のコメントにも反応して、だいぶ面倒なことになった。
LGTMが2つ以上ついたよ、ってのを通知するbotを書いてたら、暴走してちょっと申し分けない感じになった。 pic.twitter.com/3PVQBCYVRp
— mzp (@mzp) 2016年7月13日
2016年
1月
Tumblrを書くアプリを書いてた(💫Tumblotte 0.1.0 - みずぴー日記)。これを使って2016年は日記を書くぞ、と意気込んでいたけど、わりと無理だった。 タスクリストにも「日記を書く」というのが残り続けている。
2月
ゆゆ式を無限に楽しみたかった話 〜 ゆゆ式 Advent Calendar 2014 20日目 〜 - non117's diaryを参考にNEW GAME!の各コマにアノテーションをつけた(NEW GAME! のコマ検索 - みずぴー日記)。
寒くてテンションが低く、ひたすら単純作業をしたい時期だった。
3月
手動でアノテーションつけるのがつらくなったので、TensorFlowを使って半自動化した(4コマ漫画の画像管理✨ - みずぴー日記)。
4月
NL名古屋でSKKのLisp辞書について話した(SKK-JISYO.lisp - みずぴー日記)。 この過程で他のSKK実装がどうなっているかも調べた(SKK辞書の闇への対応状況 - みずぴー日記)。
5月
GWに日光に遊びにいったので、🍓 橘ありす分類器 - みずぴー日記を作った。
iTerm2にAquaSKK対応のコードがはいった。長い戦いだった(iTerm2 + AquaSKK - みずぴー日記)。
6月
WWDCを日本から視聴してた。 ほぼすべてのセッションが中継されてたので、生活のリズムが破綻する以外は特に支障はなかった。
ICSE勉強会に参加するために論文リストを確認していたらおもしろい論文があったので読んだ (論文紹介: The Evolution of C Programming Practices: A Study of the Unix Operating System 1973–2015 - みずぴー日記)。
7月〜8月
ファミコンエミュレータを書いてた(ファミコン エミュレータ - みずぴー日記)。 スーパーマリオブラザーズのオープニング画面が表示できたときは感動だった。
9月
デレステ SKK辞書が製作されるのを応援していた。
10月
あまり活動できていない。
11月
MacBookProが届いたので寿司を流して遊んでたら、めっちゃRTされてびっくりした。 こんなに反響あるとは思ってなかった。
sushiが流れる様子です pic.twitter.com/Dp7OpyXFRt
— mzp (@mzp) 2016年11月19日
これでTouchBarの使い方が分かったので、LoveLiverにTouchBar対応を追加した(Support TouchBar by mzp · Pull Request #13 · mzp/LoveLiver · GitHub)。
12月
NGK2016Bでライブフォトの話をした(Love💕LivePhotos - みずぴー日記)。 同じ日に id:banjun がアイマスハッカソンで別視点の話をしてて、宣伝効果が高そうだった。
Github contribution
参加したイベント
その他
- 沖縄の離島に遊びにいこうとしたら、風が強くて船便が欠航していた。
- iPhoneの画面を2回割った。
- 富山に旅行に行ったときに借りた宿がすごくよくて、Airbnbのすごさを感じた(きときと - みずぴー日記)。
🍣絵文字キーの実現
要約
入力メソッドの拡張とキーボードのファームウェア変更により🍣キーを実現した。
ErgoDoxで実現できないキー
ErgoDox EZ等のキー配列を自由に変更できるキーボードがある。 ただし、通常のキーボードにないキーを作ることはできない。
例えば、絵文字を直接入力するキーを作ることはできない。
ファームウェアの制限
ErgoDox EZ等で利用できるファームウェアであるqmk_firmwareにはUnicodeサポート機能がある。しかし実現方法がOSごとに違うため、OSに依存した制限がある。
macOSではUnicode Hex Inputを利用しているが、Unicode Hex Inputは4桁のコードポイントしか受け付けない。そのため4桁を越えるU+1F363
(🍣)を入力するキーは作れない。
絵文字キーの実現
入力メソッドの拡張
4桁を越えるコードポイントを入力できるようAquaSKKを拡張した。(codepoint_inputブランチ)
Ctrl
と Option
を押しながらコードポイントを入力し、最後に u
を入力することで、任意のコードポイントを入力できるようにした。 例えば、 🍣(U+1F363
)を入力したい場合は、 Ctrl
と Option
を押しながら 1
F
3
6
3
U
を押すと🍣が入力できる。
ErgoDoxでの入力
ErgoDox EZのファームウェアを変更し、拡張した入力方法を用いるマクロを作成する。 これにより絵文字キーを実現できる。
// M(1)とM(2)に絵文字を割り当てる const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { switch(id) { case 1: if (record->event.pressed) { // 🍣(U+1F363) return MACRO( D(LALT), D(LCTL), T(1), T(F), T(3), T(6), T(3), T(U), U(LCTL), U(LALT), END ); } break; case 2: if (record->event.pressed) { // 🍺(U+1F374) return MACRO( D(LALT), D(LCTL), T(1), T(F), T(3), T(7), T(A), T(U), U(LCTL), U(LALT), END ); } break; } return MACRO_NONE; };
別解1: サロゲートペア
@mzp U+D83C U+DF63 でも
— ばんじゅん🍓 (@banjun) 2016年12月24日
別解2: TouchBar
TouchBarには絵文字入力補助があって便利!
🎄AquaSKK 4.4.5: 旧かな入力の対応・数値変換の不具合修正
いくつかのプルリクエストをもらったので、それらを取り込んだAquaSKK 4.4.5をリリースした。
ダウンロード
https://github.com/codefirst/aquaskk/releases/tag/4.4.5
変更内容
旧かな変換ルールの追加
「ゐ」「ゑ」に対応するローマ字が、AquaSKKとL辞書でずれていてうまく変換できなかったため、L辞書のほうに統一した。(#71)
さらに設定画面から有効・無効を切り替えれるようにしたり、「くゎ」や「ぐゎ」を入力できるようにした。(#73)
不具合修正
いくつかの不具合を修正した。