GitHub で  CI をパスしたら自動的にマージさせたい。特定のファイル変更のみ限定にしたい。[Mergify.IO]

> GitHub で PR 後、[CI](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) のテストをパスしたら自動的にマージさせたい。**ただし条件付きで**。
> 
> 例えば、特定のファイルが変更された場合のみ自動マージさせるように限定するなど。

例えばリポジトリが、下記の構成だとします。

```shell-session:リポジトリ内のファイル
$ ls
my-script.sh    data1.json    data2.json    run-test-data.sh
```

このリポジトリに PR（Pull Request）があった場合、テストをパスしても**データ・ファイルが変更された場合のみ自動マージさせたい**のです。この場合 `*.json` のデータファイルです。

逆に言えば、CircleCI のテストをパスしてもデータファイル以外、つまり `my-script.sh` や `run-test-data.sh` などに変更があった場合は自動マージさせないで、レビューさせたいのです。

## TL; DR（Automated Merging with Mergify.IO）

> 自動マージには、マージ処理に特化した GitHub アプリ「[Mergify.IO](https://mergify.io/)」を利用すると楽。
>
> ただし条件設定に、一工夫が必要。

Mergify.IO の PR 時の条件設定 `pull_request_rules` で「変更されたファイル名とファイル数が条件にマッチした」場合にマージさせる設定にします。

1. `files` 属性に対象となるファイル名を指定
2. `"#files=1"` と個数の設定にファイル数を限定

ポイントは、この時に「`FILE_A` `OR` `FILE_B`」と「`FILE_A` `AND` `FILE_B`」の２種類の記述を追加することです。

- `OR` 処理（`FILE_A OR FILE B`）
    - 変更を許可したいファイルごとにルールセットを作成します。
- `AND` 処理（`FILE_A NAD FILE_B`）
    - 変更を許可したいファイル名すべてを記載したルールセットを作成します。

```yaml:OR処理
pull_request_rules:
  - name: automatic merge on CircleCI success if data1.json was changed
    conditions:
      - "status-success=ci/circleci: build"
      - base=master
      - files=data1.json
      - "#files=1"
    actions:
      merge:
        method: merge
        strict: true

  - name: automatic merge on CircleCI success if data2.json was changed
    conditions:
      - "status-success=ci/circleci: build"
      - base=master
      - files=data2.json
      - "#files=1"
    actions:
      merge:
        method: merge
        strict: true
```
```yaml:AND処理
pull_request_rules:
  - name: automatic merge on CircleCI success if data1.json and data2.json was changed
    conditions:
      - "status-success=ci/circleci: build"
      - base=master
      - files=data1.json
      - files=data2.json
      - "#files=2"
    actions:
      merge:
        method: merge
        strict: true
```

## TS; DR

### Mergify.IOとは

- Mergify.IO オフィシャルサイト
    - [https://mergify.io/](https://mergify.io/)

**Mergify.IO とは PR 時のマージ操作に特化した [CI](https://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E7%9A%84%E3%82%A4%E3%83%B3%E3%83%86%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3) の１種**です。[GitHub App として提供されており GitHub Marketplace から追加できます](https://github.com/marketplace/mergify)。オープンソースの場合は無料で利用できます。

PR があった場合に「CI のテストをパスし、コードレビューで n 件の承認（[Approve](https://qiita.com/YumaInaura/items/8223add6d8335a2eda7f)）が付いたら自動的にマージさせ、作業ブランチを削除する」といった自動化ができます。

基本的な仕組みはシンプルです。

1. PR 時の他のサービスやユーザーの操作から付いたコメントを解析
2. コメントが指定された文字列を含んだ場合にトリガー（発動）する

そのため、CI は CircleCI に限らず TravisCI や自作 GitHub App でも条件に追加できます。

少人数で開発されており、まだ若いサービスなので細かいところでドキュメントの情報が足りないのですが、2019/06/11現在、[本体エンジン](https://github.com/Mergifyio/mergify-engine)は[精力的に開発](https://github.com/Mergifyio/mergify-engine/graphs/code-frequency)されています。

### Mergify.IO の使い方

1. アカウント作成（GitHub アカウントで OAuth ログイン）
2. GitHub 上のリポジトリに `.mergify.yml` をアップロード（コミットしてプッシュ）
3. 別途何か PR をして動作を確かめる

一般的な GitHub App の追加同様、[GitHub Marketplace](https://github.com/marketplace/mergify) を開き、GitHub アカウントでログイン後、リポジトリに紐づけます。

次に、Mergify.IO の設定ファイルである `.mergify.yml` ファイルをリポジトリのルートに置き、一度監視対象のブランチ（`master` など）に反映させると、以降の PR で、その設定ファイルにそったマージ操作を行えます。

- [`Mergify.IO` の Qiita 記事](https://www.google.com/search?q=site:qiita.com+mergify.io) @ Google検索

### Mergify.IO の使い道

なんでも無条件でマージするのは危険です。悪意あるスクリプトを埋め込まれる可能性もあるからです。

しかし、クリティカルでなく `Linter` によるチェックや CI のテストでパスすれば問題がないファイルで、マージ権限のあるメンバーの手をわずらわせたくない場合に重宝します。例えば `README.md` の typo だったり、単純なデータの追加などです。

もしくは、レビュー権限のあるユーザーの承認を過半数得た場合にはマージさせるといった具合です。

### サンプルを触ってみる

Qiita ユーザとして個人的に興味あるニュース・フィードを集めたリポジトリを用意しました。JSON 形式です。

- リポジトリ： https://github.com/Qithub-BOT/News-Feeds @ GitHub
- ニュース・フィード一覧： [list_url_feeds_nice.json](https://qithub-bot.github.io/News-Feeds/list_url_feeds_nice.json)

気になる未登録のフィードを見つけたら、このリポジトリを `clone` → 追加 → PR をかけてみてください。以下の条件を網羅した場合、自動的にマージされるようにしました。[追加できるフィードの趣旨](https://github.com/Qithub-BOT/News-Feeds#%E8%BF%BD%E5%8A%A0%E3%81%A7%E3%81%8D%E3%82%8B%E3%83%95%E3%82%A3%E3%83%BC%E3%83%89%E3%81%AE%E7%A8%AE%E9%A1%9E)に同意できるならお触り自由です。

1. `*.json` ファイルのみが変更されている。
2. 以下の CI のテストをパスした。（[validate_json.sh](https://github.com/Qithub-BOT/News-Feeds/blob/master/tests/validate_json.sh)）
    1. 有効な JSON である。（JSON 構文にミスがない）
    2. フィードの URL が重複していない。
    3. 各フィードの登録（要素）の並び順が URL の ABC 順である。
    4. URL 先のフィードが解析可能な状態である。
        - 404 エラーでない。（URL 先が有効である）
        - XML/Atom として有効な構文である。
        - 非可視文字が含まれていない。

> <sup>🐒なお、URL 先のフィード（XML/Atom）の構文チェックには、[URL を指定すると JSON フォーマットに変換するコマンドを作った](https://github.com/KEINOS/gofeed-cli)ので、正常に JSON 形式で取得できたら `OK` としています。:point_right: [GoFeed-CLI](https://github.com/KEINOS/gofeed-cli) @ GitHub</sup>

このリポジトリのポイントは、やはり CircleCI をパスしたら自動マージされる点です。

`- files=<FILE NAME>` と対象ファイルを限定し、`- "#files=n"` で変更されたファイル数を指定する組み合わせで、特定のファイルのみの変更の条件を作れます。

複数のファイルを指定したい場合、`- files=["FILE1", "FILE2"]` といった形式には対応していないので、 **`- files=<FILE NAME>` を複数個指定します**。

また、[同じ条件（`condition`）内での `or` には対応していない](https://github.com/Mergifyio/mergify-engine/issues/430#issuecomment-500423552)のですが、ルールを追加（別々の `condition`に）することで `or` 対応できます。

この方法がわからず、Issue で聞いたら親切に教えてもらったので記事にしてみました。

- [Can't merge when "files" condition list is set](https://github.com/Mergifyio/mergify-engine/issues/430) | #Issue 430 | @ GitHub