GitHubでのプルリクエスト運用を加速するためにプルリくんというBotを作った話

[DMM.com #1 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm) 12日目の記事です。前日の記事は@sssinsiさんの[ElasticbeanstalkのMulti-container Dockerを使ったら便利だった話](https://qiita.com/sssinsi/items/e602b7cdc4e240eea7cd)でした。

**カレンダーのURLはコチラ**
[DMM.com #1 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm)
[DMM.com #2 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/dmm2)

こんにちは。DMM.comラボでログインやアカウント登録などの会員基盤の開発を担当している入社2年目の@kentaro-mです。

本日は私が所属するチームで活躍しているプルリクエスト運用Botについてお話したいと思います。

---
## プルリクエスト運用Botを開発した経緯
プルリクエスト運用Bot開発に至った経緯は一言で言うと、**プルリクエストのレビューが日常的に滞ることがあり、それを解決したい** と考えたからです。

<img width="1024" alt="pull_request_review_flow_001.png" src="https://qiita-image-store.s3.amazonaws.com/0/38478/f6354484-cbc8-b832-5afd-e9692ed65100.png">

チームでは上図のようにプルリクエスト運用を行っています。Bot導入前にネックになっていたのはレビューを依頼してから承認されるまでの部分です。

### レビューが同時進行で行われ、マージまでの時間がかかる

レビュー依頼は実装者がプルリクエストのタイトルとURLを付けて、Slackでチームメンバーに依頼しています。また、レビューは実装者以外のチームメンバーが行い、2人以上の承認が付けばマージできる方針でした。

チームでは毎日5〜10ほどのプルリクエストが作成され、レビューが同時進行で行われておりレビュアーはどのプルリクエストをレビューしたか分からなくなったり、レビュイーは作成したプルリクエストのレビューが進まないことに気をもんでいたりしました。

### レビューする時間を明示的にとってみる

そこで毎朝30分間チームメンバー全員でレビューの時間を取ることにしました。これにより、1日の始めに昨日作成されたプルリクエストはほとんどマージされるようになりました。しかしながら、この方法では一度に多くのプルリクエストをレビューすることになり、レビュアーの負担が増える結果となったのです。

この結果を受けて、プルリクエストが作成されたタイミングでレビューを行う運用にすることがレビュアーとレビュイーにとって良いのではないかと考えました。それを実現するためにプルリクエスト運用を手助けするBot「プルリくん」の開発に着手しました。

## プルリくんが提供している機能
プルリくんは以下の機能を提供しています。

* レビュアー・レビュイーへのSlack DM通知
    * プルリクエスト作成時のレビュー依頼通知（レビュアー向け）
    * メンションコメントの確認依頼通知（レビュアー・レビュイー向け）
    * プルリクエストマージ可能時の通知（レビュイー向け）
* レビュアーとアサイニー欄の自動アサイン機能

基本的にはレビュアーとレビュイーに対応して欲しいタイミングでのSlack通知がメインの機能です。それに加えて、毎回のプルリクエスト作成で必要なレビュアーのアサインの自動化もあわせて可能にしました。

### プルリクエスト作成時のレビュー依頼通知
![assign_to_reviewer.gif](https://qiita-image-store.s3.amazonaws.com/0/38478/e81c84a0-a3e8-68ca-c795-8bc3378c8359.gif)

<img width="562" alt="request_review.png" src="https://qiita-image-store.s3.amazonaws.com/0/38478/1b0e6cf8-90b4-a8f5-b8af-5cfcd0d40045.png">

プルリクエストが作成されるとレビュアーにはDMでSlackに通知がきます。

### メンションコメントの確認通知
![check_review_comment.gif](https://qiita-image-store.s3.amazonaws.com/0/38478/fca9e01d-afbb-ced2-7c74-b4073d2566be.gif)

<img width="558" alt="check_comment.png" src="https://qiita-image-store.s3.amazonaws.com/0/38478/b62e22a7-0a17-2ea6-07c5-cc8b5f8a6743.png">

メンション付きのレビューコメントが追加されると、レビュイーまたはレビュアーにDMでSlackに通知がきます。

### プルリクエストマージ可能時の通知
![able_to_merge.gif](https://qiita-image-store.s3.amazonaws.com/0/38478/c0c7b0bd-fd6e-6a02-d17d-3899d6579c0d.gif)

<img width="562" alt="able_to_merge.png" src="https://qiita-image-store.s3.amazonaws.com/0/38478/07e5caed-478b-1b7e-e00f-328a78a2c7d0.png">

プルリクエストにApproveコメントが指定人数以上ついたときにレビュイーに通知します。チームでは2人以上の承認で通知するようにしています。

### レビュアーとアサイニー欄の自動アサイン機能
![auto_assign.gif](https://qiita-image-store.s3.amazonaws.com/0/38478/5aedf696-2fd6-c9a8-5f39-0f6652a2b969.gif)

毎回プルリクエストを作成する度にポチポチとボタンを押して、同じメンバーをレビュアーとアサイニーに追加する必要があったのでプルリクエスト作成で自動追加するようにしました。

## プルリくんが動作する仕組み
![lambda_pr_notify_bot.png](https://qiita-image-store.s3.amazonaws.com/0/38478/46bef361-efed-86ee-3e88-af5dd68e29da.png)


プルリくんはAWS環境で運用する想定で作られています。なぜAWSにしたかというと、チームの開発環境がAWSで構築されており相乗りしたかったこと、会社の福利厚生で月100ドルまでAWSが自由に利用できて学習する際の個人的負担が必要なかったことが挙げられます。

参考：[エンジニアサポート制度「AWS実弾演習場」とは？実際の利用者に話を聞いてみました！ - DMM inside](https://inside.dmm.com/entry/2017/08/09/Whats-AWS-real-bullet-practice-field)

さて、本題の動作の仕組みですが、プルリクエストの作成やレビューコメントの送信などのイベントをトリガーにWebhook URLとして設定されたAPI Gatewayのエンドポイントがたたかれることで処理が開始します。

API Gatewayは受信したデータをLambdaに流し、Lambda上ではGitHub APIから情報を受け取ってSlack通知が必要な状態であるのかを判断し、必要に応じてSlack APIを使用してメッセージを送信しています。

```json:default.json
{
  "host": "", // GHEで使うときはexample.githubenterprise.comのように任意のホストを入れる
  "pathPrefix": "", // GHEで使うときは/api/v3
  "reviewers": [ // レビュアー一覧（GitHubのユーザー名）
    "matsushita-kentaro"
  ],
  "approveComments": [ // PRを承認するときのレビューコメント（Approveコメントを使用する場合必要なし）
    "+1",
    "LGTM"
  ],
  "numApprovers": 2, // マージ可能な承認数
  "slackUsers": { // GitHubユーザー名とSlackユーザー名を対応させる（キー：GitHubユーザー名、バリュー：Slackユーザー名）
    "matsushita-kentaro": "matsushita_kentaro"
  },
  "message": { // Slackに通知する際に付与するコメント
    "requestReview": "レビューお願いします。",
    "ableToMerge": "マージできます。",
    "mentionComment": "コメント確認お願いします。"
  },
  "assignReviewers": true, // 各機能を有効にするか
  "requestReview": true,
  "ableToMerge": true,
  "mentionComment": true
}
```
実際に利用する際の各機能の有効・無効やSlackメッセージ送信のためのGitHubとSlackのユーザー名の対応はJSON形式で設定できます。

## プルリくんを開発するときの考慮点

### LambdaをVPC上で配置して社内システムのGitHub Enterpriseで動作可能に
![lambda_pr_notify_bot_on_vpc.png](https://qiita-image-store.s3.amazonaws.com/0/38478/01cae8ae-268c-3e70-b7ed-060c8a031516.png)


DMMでは今年からGitHub Enterpriseが導入され、社内システムとして構築されています。社内システムであるということは当然ながらアクセスできる環境が制限され、GitHub APIへのリクエスト等の社外からのアクセスはアクセス元IPを許可してもらう必要がありました。

しかし、Lambdaはデフォルトではインターネット上に配置されているためにIPを固定することができません。この問題を解決するためにLambdaをVPCのプライベートサブネット上に配置し、Elastic IPを付与したNat Gatewayで通信の出入り口を作成しました。

参考：[Lambdaから固定IPアドレスでkintoneと連携する方法 | kintoneを便利に使う方法を紹介するブログ](https://www.joyzo.co.jp/blog/2325)

### AWS SAMを使用して構成をコード化し再利用可能に
Botを開発し始めたときはまず自チームで動作するものを作りたいという思いでしたが、実装していくにつれて他チームに展開できたら良いのではないかと考えました。

そこで簡単に他チームでも導入できる方法を実現するために辿り着いた答えが構成のコード化でした。API GatewayやLambdaで構成されるアプリケーションは[Serverless Framework](https://serverless.com/)や[AWS SAM](https://github.com/awslabs/serverless-application-model/blob/master/HOWTO.md)を使用することでコード化し容易にデプロイできます。私はCloudFormationの使用経験があったので後者でBotの構成のコード化に取り組みました。

```bash
$ git clone https://github.com/kentaro-m/lambda-pr-notify-bot.git
$ cd lambda-pr-notify-bot
$ npm install
$ npm run package
$ aws cloudformation package --template-file template.yml --s3-bucket <Your bucket name> --output-template .sam/packaged.yml
$ aws cloudformation deploy --template-file ./.sam/packaged.yml --stack-name <Your stack name> --capabilities CAPABILITY_IAM
```
コマンドを数回打つだけでAWS上にアプリケーションがデプロイされます。

## プルリくんを導入した結果
<img width="1024" alt="pull_request_review_flow_002.png" src="https://qiita-image-store.s3.amazonaws.com/0/38478/578f5f2c-0892-0c91-f186-23f36c5196ae.png">

プルリくん導入した結果、レビュー依頼からマージまでのネックとなっていたコミュニケーションの部分が解消されてレビューがうまく回るようになりました。具体的に良かったことは以下が挙げられます。

### レビュアーのプルリクエストへの反応が良くなった
プルリくんを導入してからレビュアーの初動対応が早くなったことを感じました。以前は各々タスクの空き時間でレビューをしていましたが、導入後は通知をきっかけに動き出すことが増えて結果としてレビューが早く回るようになりました。

### Slack上でのレビュー依頼が減った
以前はプルリクエストを作成後に開発者がSlackでレビュー依頼をしていました。日によって依頼メッセージでチャンネルが埋め尽くされることもありましたが、プルリくん導入後は依頼メッセージが減り、タスク進行する上での相談のコミュニケーションが増えました。

## さいごに
チームに配属されて約1年半プルリクエスト運用を経験して日々感じていた課題を解決するためにBot開発に挑戦したことを紹介しました。

今回はプルリクエストレビューで発生するコミュニケーションの改善にフォーカスを当てました。チームでは他にもユニットテストや静的解析ツールをCIで実行することでコードレビューにおけるレビュアーへの負担を減らす取り組みも行っています。

アプリケーションの品質を向上させるためにプルリクエストレビューは重要な作業の一つだと思うのでこれからもどういった運用が良いのかを考えていきたいと思います。

明日は@canacelさんの記事です。

## リポジトリ
[kentaro-m/lambda-pr-notify-bot: A slackbot that reminds reviewers to review their pull requests on AWS.](https://github.com/kentaro-m/lambda-pr-notify-bot)