【GitHub Actions】ブランチ間に差分が有った時に同期pull requestを発行する（baseブランチは新しく作成する）

## やること
`GitHub Actions`で、`qa`ブランチに変更が有った時に、`develop`ブランチへの同期PRを発行します。
この記事で紹介する方法では`base`ブランチが新しく作成されるため、主要なブランチが保護されるという利点が有ります。

`base`ブランチの新規作成が不要な場合、`sync-branches`アクションを利用する方が簡単です（この場合`CONTENT_COMPARISON = true`での運用がおすすめです）。

https://github.com/TreTuna/sync-branches

### `base`ブランチを作成する理由
態々WFを複雑化させてまで`base`ブランチを作成するやり方を採用したのは、`qa`ブランチへの意図せぬ変更を防ぐためです。

今回紹介するWFを利用しているプロジェクトでは、基本的に`develop`ブランチ（デフォルト）で検証したものを`qa`ブランチに反映し、特別な場合だけ`qa` -> `develop`の反映を行う運用をしています。
ここで、不用意に[Update branch](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/keeping-your-pull-request-in-sync-with-the-base-branch#:~:text=Click%20Update%20branch%20to%20perform%20a%20traditional%20merge.)してしまった結果、未検証の内容が`qa`ブランチに混入する事故がありました。

そこで、`base`ブランチを作成することで、誤操作が有っても`qa`ブランチに被害が出ないようにしています。

## サンプルコード
WFのサンプルは以下の通りです。
`name` ~ `env`のセクションを適切に書き換え、リポジトリの権限設定を行えば、コピペで動きます。
注意点として、このWFは`qa`ブランチへPRでのマージが1件以上行われていなければ失敗する（= 直コミットしたような場合に非対応の）ようでした。

```yaml
name: "qa -> dev"
on:
  push:
    branches:
      - qa

env:
  FROM_BRANCH: qa
  TO_BRANCH: develop
  SYNC_BRANCH: sync/qa2dev # ブランチが更新された時に影響させない & update branchボタンによる事故を避けるためにFROM_BRANCHから作成するブランチの名前

jobs:
  sync-branches:
    runs-on: ubuntu-latest
    permissions:
      # ブランチを作成するので write 権限が必要
      contents: write
      pull-requests: write
    steps:
      # セットアップ
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
          ref: ${{ env.FROM_BRANCH }}
      # Originの差分をチェック（後続で値を参照し、0 = 差分無しなら実行しない）
      - name: Count changes
        id: count-changes
        run: echo "count=$(git diff origin/${{ env.TO_BRANCH }}...origin/${{ env.FROM_BRANCH }} --name-only | wc -l)" >> $GITHUB_OUTPUT
      # ブランチ作成
      - name: Create sync branch
        id: create-sync-branch
        if: steps.count-changes.outputs.count > 0
        run: |
          git config user.email "actions@github.com"
          git config user.name "Github Actions"
          branch=${{ env.SYNC_BRANCH }}
          git switch -C $branch
          git push origin $branch
      # PR作成
      - name: Create sync pull request
        id: create-sync-pull-request
        if: steps.count-changes.outputs.count > 0
        uses: bakunyo/git-pr-release-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GIT_PR_RELEASE_BRANCH_STAGING: ${{ env.SYNC_BRANCH }}
          GIT_PR_RELEASE_BRANCH_PRODUCTION: ${{ env.TO_BRANCH }}
          TZ: Asia/Tokyo
```

実行すると以下のようなPRが発行されます。
![スクリーンショット 2023-05-17 23.47.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/71dd0391-4519-0f7c-d3a7-878e519b80bb.png)

## 解説
### `Count changes`
このステップでは、ブランチ間の差分をカウントしています。
コメントの通り、これが0より大きい（= 差分が有る）場合のみPRを発行しています。

これをやっている理由は、`develop` -> `qa`のマージを行う都度、差分が無いのにPRが発行されることを防ぐためです。

一応同じようなことができるアクションも有るようでしたが、サンプルでは内部的な実績の有ったこの方法を利用しています。

### `Create sync branch`
このステップでは、単純な`git`操作でブランチ作成とプッシュを行なっています。
ここで、サンプルでは`-C`（`--force-create`）オプションを利用しているため、既にブランチが存在する場合更新する挙動になります。

https://git-scm.com/docs/git-switch#Documentation/git-switch.txt--Cltnew-branchgt

### `Create sync pull request`
最後がPR発行部です。
ここでは`git-pr-release-action`を利用しています。

https://github.com/bakunyo/git-pr-release-action