GitFeatureFlowをlambdaを使って改善した話

## はじめに
[Leverages Advent Calendar 2019](https://qiita.com/advent-calendar/2019/leverages)の15日目を担当させていただきます@TOC8です。
弊社アドベントカレンダーへの投稿は2年ぶり2回目になります。
[前回](https://qiita.com/TOC8/items/585c7bef9f277cbbbfa7)は業務とは全く関係ない記事を書いたのですが、今回は現チームにおける開発フローについて最近行ったことを書きたいと思います。
この記事では以下の2点について紹介いたします。

- GitFeatureFlowの懸念点解消方法
- lambdaとGithub APIを用いたPRの自動化

GitFeatureFlowについては下記記事を参考にさせていただきました。
[GitFlowをやめて本番リリースが楽になった話](https://qiita.com/koyopro/items/b4569285efc22c6397c6)

参考記事内でも色々議論がなされていますが、現状のGitFeatureFlowについてlambda等を利用することで運用をもう少ししやすくする方法を紹介するために今回記事にしてみようと思いました。

## 背景
最近私がいる事業部ではエンジニアの人数も増えてきて、私が入ったときと比べて4倍くらいの人数になりました。
それに伴い、色んな機能の開発プロジェクトを同時並行で進められるようになったのですが、一つの機能の確認に時間がかかっているために、もう一つの機能がリリースできず、ユーザーに価値を届けるまでに時間がかかる、という事象が発生するようになりました。

現状のチームではリリース頻度も2日に1回くらいでPull Request(以下PR)の数でいうと5~8個ほどマージ+リリースされます。全てスムーズに確認が取れればいいのですが、確認者の時間が取れなかったり、休みが続いて(最近風邪がビビるくらい流行ってますね...)確認が終わらないものも出てきます。

状況としては[参考記事](https://qiita.com/koyopro/items/b4569285efc22c6397c6)と同じで、development環境での滞留が発生していました。

#### 通常フロー
<img width="845" alt="スクリーンショット 2019-12-10 11.54.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122892/fd50bc2a-f1ca-1d92-0cee-5b915b0f1560.png">

#### 滞留が起きた場合
<img width="846" alt="スクリーンショット 2019-12-10 11.55.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122892/b81fbd47-bb3e-4946-ff15-413d678c2e49.png">

- master：本番ブランチ
- development：検証用ブランチ(ステージング環境)
- feature/xx：機能開発用ブランチ

上記の記事を参考に、この開発フローを下記のようにdevelopmentブランチからではなく、機能ごとのブランチからmasterにPRを投げることで、一つの機能の確認時間がかかっていても、確認が終わった機能からリリースできるようにしようという話になりました。

#### 新フロー
<img width="861" alt="スクリーンショット 2019-12-10 11.55.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122892/c608be69-69ec-d3ec-4b09-959265ffa9c5.png">


しかし、上記の記事でも説明しているように、この方法には下記のような懸念点がありました(他にもありますが、それについては最後に触れます)。

#### 1. PRの管理について個人依存が強くなる
developmentで検証してからmasterにPRを投げるため、例えば「developmentで検証中にそのまま開発で何か変更して、検証後気づかずmasterにPR+マージで意図しないものが本番にリリースされる」というようなことが起こる可能性がでてきます。参考記事には、この問題の解決策として「developmentにPRすると同時にmasterにも同じものをPRする」というTipsが書いてありましたが、そうすると次の事象が生じます。

#### 2. PRの管理が大変
developmentとmasterそれぞれにPRを出すため、単純にPRの数が倍になります。そのため、PRの数が非常に多くなり管理しづらくなります。

これらの問題をlambdaとGithub APIを用いて、developmentにマージをしたら自動的にmasterへのPRを作成することで解決を試みました。

## 実際にやってみた
※この記事では細かい設定方法については参考になる記事があるので省略し、自身で設定した部分を中心に説明します。

### Githubとlambdaの連携
Githubとlambdaの連携については下記記事を参考にさせていただきました。
[GitHubのWebhookでプルリクエストをマージした際にツイートできるようしてみた](https://qiita.com/turmericN/items/f6267a75be45c51eaed7)
こちらの記事の

- lambdaとAPI Gatewayの設定
- Github webhookの設定

を参考にすればGithubとlambdaの連携ができます。

### lambdaの設定
では肝心のlambdaの設定部分です。
参考記事でもpythonを用いており、情報も多かったのでpythonを用いて実装しました。
また、APIは[GitHub-REST API v3のCreate a pull request](https://developer.github.com/v3/pulls/)を利用します。

```lambda_function.py
import json
import datetime
import requests

def lambda_handler(event, context):
    # プルリクの情報を抽出
    dumps = json.dumps(event)
    body = json.loads(dumps)

    # actionのキーがなければ終了
    if "action" not in body:
        return {"statusCode": 200, "body": "exit" }

    # プルリクがクローズかつマージでなければ終了
    if body['action'] != "closed" or body['pull_request']['merged_at'] is None:
        return {"statusCode": 200, "body": "exit" }
    
    # developmentへのマージのみ適用
    if body['pull_request']['base']['ref'] != "development":
        return {"statusCode": 200, "body": "exit" }
    
    # 適宜自身のリポジトリに変更してください
    url = "https://api.github.com/repos/:owner/:repo/pulls"
    session = requests.Session()
    session.auth = ('自身のGithubアカウント名', 'APIトークン')
    
    # 作成するPRの設定
    item_data = {
        'title': '[PRO]' + "{0:%Y/%m/%d}".format(datetime.date.today()) + '(' + body['pull_request']['title'] + ')',
        'body': body['pull_request']['title'],
        'head': body['pull_request']['head']['label'],
        'base': 'master',
        'draft': True
    }
    
    result = session.post(url, json.dumps(item_data), headers={'Accept': 'application/vnd.github.shadow-cat-preview+json'})

    return {"statusCode": 200, "body": "success" }


```

developmentブランチへのマージのみ適用するなど、自チームの状況特有の設定などもありますが、こちらの設定でdevelopmentブランチへマージしたときに自動的にmasterへのPRが作成されます。

自動作成された場合、以下のようになります。
![_PRO_2019_11_20__1234_テスト__by_ToshiyaTanaka_·_Pull_Request__22_·_ToshiyaTanaka_hc-levsta.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122892/02d5bdcc-908d-41ea-3a00-efd30cd749ea.png)

### ちょっと工夫した点
#### PRタイトルに元PRのタイトルを記載
個別でmasterにPRを送るため、どのPRからのものなのかリリース担当が一目でわかるようにPRタイトルに元のPRのタイトルを含めています。このときチーム内で「タイトルにイシュー番号を含めるようにする」というルールを新たに設定しました。タイトルをPRのbodyにも記載してあるので、そこから関連イシューにも移動できるようになります。
#### masterへのPRは一旦draftで作成
masterへのPRは一旦draftで作成するように設定しました。PRを作成する際に
```'draft': True```
というオプションをつければdraftとして作成されます。
チームとしてはdvelopment環境での検証に問題なければdraftを外してもらうようにして、リリース担当がリリース準備が整ったPRを把握できるようにしました。

## 実際に運用してみて良かったこと

###  developmentとmasterの差分が出づらい
developmentにマージしたら、機能ブランチから自動的にmasterへPRがあがるため、developmentでの確認時に余計なものが混ざっていないかを見ることでdevelopmentとmasterに差分が出づらい状態になっています。
(ただ、masterとdevelopmentを合わせるのは定期的に行ったほうが良さそうなので、こちらも自動化を検討しています。)

### PRが一回のみで済む
developmentにマージ後、自動でPRが作成されるため開発者はPRを1回あげるだけで済みます。また、PR倍問題も解消されました。

運用してから約1ヶ月経ちますが、現状大きな問題はなく運用できています。
一つの機能が確認中でも、他の機能がリリースできるため、リリースまでの時間短縮につながっているかと思います。
ただルールに則った開発フローを踏まないとdevelopmentとmasterでの差分が出てきそうなので、都度問題点が出てきたらブラッシュアップしていこうと思います。

## まとめ
今回はlambdaとGithub APIを用いたPRの自動化をすることで開発フローを改善したことについて話しました。

GitFeatureFlowについては、そもそも検証されてないもの(or検証してNGだったもの)が残っているのが問題じゃない？共存してたら本当の意味で検証になってなくない？という意見があります。
これはもう本当にごもっともな話なのですが、コスト面やチーム状況からGitFeatureFlowを用いてる場合、上記方法によって運用が少しでも楽になれば嬉しいです。
また、実装するときにlambdaとGithub APIを用いたPR作成の自動化はあまり記事を見かけなかったので、今回のケースに当てはまらなくても、何かしら開発フローの改善について役に立つ点があれば幸いです。

## 参考記事
[GAS から Github に Pull Request を出してみた](https://tech.libinc.co.jp/entry/2019/09/06/140000)
[GitHubのWebhookでプルリクエストをマージした際にツイートできるようしてみた](https://qiita.com/turmericN/items/f6267a75be45c51eaed7)
[GitFlowをやめて本番リリースが楽になった話](https://qiita.com/koyopro/items/b4569285efc22c6397c6)
[GitFlowは使わない！シンプルな「GitFeatureFlow」を紹介します](https://developers.gnavi.co.jp/entry/GitFeatureFlow/koyama)