GitHub Branch ProtectionをGitHub APIで設定

#GitHub Branch Protection
GitHubのBranch Protectionという機能は以下のような機能が実現でき、GitHub運用のルールを強制的に守らせることができるので便利です。

* `master`ブランチへの直接の`push`の禁止
* プルリクをマージする時、コードレビューを経ないとマージできないようにする
* CIが正常終了しないとマージできないようにする

#手動設定
Branch ProtectionはGitHubのWebサイトから手動で設定することができます。
[Your Repository] => [Settings] => [Branches]
と遷移していくと、設定画面にたどり着きます。

<img width="1022" alt="screen0.png" src="https://qiita-image-store.s3.amazonaws.com/0/30931/e5f0c409-8290-e563-048b-dc2a3081223c.png">
<img width="1017" alt="screen1.png" src="https://qiita-image-store.s3.amazonaws.com/0/30931/9734b1f8-ed5c-3778-e26d-ae1ecfe98a5e.png">
<img width="991" alt="screen2.png" src="https://qiita-image-store.s3.amazonaws.com/0/30931/37ca686f-e5ae-a5f0-f845-a65acde71661.png">

各項目の意味は [https://dev.classmethod.jp/tool/github/protect-branch/](https://dev.classmethod.jp/tool/github/protect-branch/) などを参考にしてください。

#GitHub APIによる設定
ただ、新しいプロジェクトを作るたびにポチポチ設定するのってダサいですよね。
GitHub APIを使って、自動設定しましょう。

自動設定スクリプト( `protect.sh` )とBranch Protectionの設定ファイル( `protections.json`　)を下記にように配置して、

```
.
└── .github
    ├── protect.sh
    └── protections.json
```
下記のコマンドを実行すると、設定ができるようにします。

```
$ bash .github/protect.sh
```

# 自動設定スクリプト

スクリプトを実行するために下記のコマンドが必要なので入れてください。

* [hub](https://github.com/github/hub) : GitHub APIクライアント
* [jq](https://stedolan.github.io/jq/) : jsonをパースするコマンド

macの場合、下記コマンドで入ります。

```
$ brew install hub
$ brew install jq
```

スクリプトのコードは下記です。
基本、これをそのままコピペすれば動くはずです。

```sh:protect.sh
#!/bin/bash

DIR=$(cd $(dirname $0); pwd)

hub api user
echo -e "\nLogged in.\n\n"
TOKEN=`cat ~/.config/hub | grep oauth_token | sed "s/ //g" | sed "s/oauth_token://g"`

REPO=`git config --get remote.origin.url | sed s/git@github.com://g | sed s/.git$//g`

RES=`cat "${DIR}/protections.json" | jq -r 'to_entries[] | "\(.key)__DELIMITER__\(.value)"'`
for line in ${RES}; do
   BRANCH=`echo ${line} | sed -e "s/__DELIMITER__.*$//g"`
   BODY=`echo ${line} | sed -e "s/^.*__DELIMITER__//g"`
   curl \
     -X PUT \
     -H "Accept: application/vnd.github.luke-cage-preview+json" \
     -H "Authorization: token ${TOKEN}" \
     "https://api.github.com/repos/${REPO}/branches/${BRANCH}/protection" \
     -d ${BODY}
done
```

5行目の

```
hup api user
```
の箇所で　`GitHub API`の`token`を未取得であれば、id, passwordを聞いてくるので、入力すると、`token`を取得して設定ファイルに保存しています。


# 設定ファイル

設定ファイル(`protections.json`)は例えば、下記のように設定します。

```json:protections.json
{
  "dev": {
    "required_status_checks": {
      "strict": true,
      "contexts": [
        "ci/circleci"
      ]
    },
    "required_pull_request_reviews": {
      "dismiss_stale_reviews": true,
      "require_code_owner_reviews": false,
      "required_approving_review_count": 1
    },
    "enforce_admins": true,
    "restrictions": null
  },
  "master": {
    "required_status_checks": {
      "strict": true,
      "contexts": [
        "ci/circleci"
      ]
    },
    "required_pull_request_reviews": {
      "dismiss_stale_reviews": true,
      "require_code_owner_reviews": false,
      "required_approving_review_count": 1
    },
    "enforce_admins": true,
    "restrictions": null
  }
}
```

これは

```json-doc
{
   "ブランチ名1": { /* Branch Protectionの設定 */ },
   "ブランチ名2": { /* Branch Protectionの設定 */ },...
}
```
という構造になっていて、Branch Protectionの設定の部分は
https://developer.github.com/v3/repos/branches/#update-branch-protection
にそれぞれのパラメータの詳細が載っています。

今回の例では`master`ブランチと`dev`ブランチに対して、マージを行う時、1人以上のレビューを必須にし、CircleCIが正常終了していないとマージできないようにしています。

#  終わりに
今回のソースは[https://github.com/Arahabica/GitHubProtectionSample](https://github.com/Arahabica/GitHubProtectionSample)にも置いています。