GitHubActionsを使って別リポジトリのYMLを自動更新する

# 前置き
- Aリポジトリ
    - アプリケーションのソースを管理しているリポジトリ 
- Bリポジトリ
    - 各環境のマニフェストファイルを管理しているリポジトリ
   

# やりかた
[Repository Dispatch](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#repository_dispatch)の仕組みを使ってAリポジトリのイメージ作成をトリガーにBリポジトリにイベントを飛ばす。

# やってみる
## Aリポジトリ

```yml
on:
  push:
    branches:
      - 'dev-*'
      - 'stg-*'
      - 'pilot-*'
```
環境はdev（開発用）、stg（ステージング用）、pilot（パイロットテスト用）があるとします。
ブランチ名に命名規則に則った特定のブランチ名を付けてPUSHしたタイミングでワークフローが走るようにします。

```yml
- name: Repository Dispatch
  uses: peter-evans/repository-dispatch@v1
  with:
    token: ${{ secrets.REPO_ACCESS_TOKEN }}
    repository: <user_name>/<Bリポジトリ名>
    event-type: update-yml
    client-payload: '{"ref": "${{ env.GITHUB_REF }}"}'
```
ワークフローのトリガーには[peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch)のActionsを使用します。

- token：
    - [`${{ secrets.GITHUB_TOKEN }}` を使用することができない](https://github.com/peter-evans/repository-dispatch#token)ので、repo権限があるpersonal access token を用意してください。（手順は[後述](#パーソナルアクセストークンの設定方法)します）
- repositroy：
    - Bリポジトリを指定します
- event-type：
    - イベント識別する任意の文字列を指定します。
- client-payload：
    - BリポジトリにJSON形式で文字列など必要な情報を渡すことができます。（詳しくは[こちら](https://github.com/peter-evans/repository-dispatch#client-payload)）
    - プロパティは10個まで指定が可能になっていてそれ以上を指定するとエラーが発生します。
    - 今回はイメージタグになるブランチ名を渡すようにしています。

その他もろもろを追加して最終的なymlがこちら

```yml:repository_dispatch.yml
name: Repository Dispatch

on:
  push:
    branches:
      - 'dev-*'
      - 'stg-*'
      - 'pilot-*'

jobs:
  dispatch:
    name: Repository Dispatch
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set Env
        run: |
          echo "GITHUB_REF=${{ github.ref_name }}" >> $GITHUB_ENV
      - name: Repository Dispatch
        uses: peter-evans/repository-dispatch@v1
        with:
          token: ${{ secrets.REPO_ACCESS_TOKEN }}
          repository: <user_name>/<Bリポジトリ名>
          event-type: update-yml
          client-payload: '{"ref": "${{ env.GITHUB_REF }}"}'
```

## Bリポジトリ

### 今回更新したいマニフェストファイル 

```yml:deployment.yml
containers:
  - name: dev
    image: 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/<ECR リポジトリ名>:v.1.0.0
```

### ワークフロー
```yaml
on:
  repository_dispatch:
    types:
      - update-yml
```
repository-dispatchで特定のイベントを受け取ったらワークフローが動作するようにします。
ここでは先ほどAブランチのrepository_dispatch.ymlで指定したevent-typeの`update-yml`を指定します。

```yml
- name: Set Env
  run: |
    echo GITHUB_REF"=${{ github.event.client_payload.ref }}" >> $GITHUB_ENV
```
repository_dispatch.ymlで指定したclient-payloadを上記で取得します。

```yml
- name: Update dev Yml
  if: startsWith(env.GITHUB_REF, 'dev-')
  uses: mikefarah/yq@master
  with:
    cmd: IMAGE_TAG=' 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/<ECR リポジトリ名>:${{ env.GITHUB_REF }}' yq eval '.containers[].image = env(IMAGE_TAG)' -i k8s/dev/development.yml
```
GithubActionsからymlファイルの更新には今回は[yq](https://github.com/mikefarah/yq)というjqのyaml版を使用します。
公式ドキュメント：https://mikefarah.gitbook.io/yq/
環境ごとに更新するファイルが異なるので`if`でブランチ名の先頭文字列で判定をしています。
変数`IMAGE_TAG`に置き換えたい文字列を生成します。

```yml
'.containers[].image = env(IMAGE_TAG)'
```
ここで前述したマニフェストファイルの書き換えたい部分を指定して`IMAGE_TAG`で更新しています。

その他諸々を追加して最終的なymlがこちら

```yml:update_image.yml
name: Update Yml

on:
  repository_dispatch:
    types:
      - update-yml

jobs:
  update-yml:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set Env
        run: |
          echo GITHUB_REF"=${{ github.event.client_payload.ref }}" >> $GITHUB_ENV

      - name: Update dev Yml
        if: startsWith(env.GITHUB_REF, 'dev-')
        uses: mikefarah/yq@master
        with:
          cmd: IMAGE_TAG=' 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/<ECR リポジトリ名>:${{ env.GITHUB_REF }}' yq eval '.containers[].image = env(IMAGE_TAG)' -i k8s/dev/development.yml

      - name: Update stg Yml
        if: startsWith(env.GITHUB_REF, 'stg-')
        uses: mikefarah/yq@master
        with:
          cmd: IMAGE_TAG=' 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/<ECR リポジトリ名>:${{ env.GITHUB_REF }}' yq eval '.containers[].image = env(IMAGE_TAG)' -i k8s/stg/development.yml

      - name: Update pilot Yml
        if: startsWith(env.GITHUB_REF, 'pilot-')
        uses: mikefarah/yq@master
        with:
          cmd: IMAGE_TAG=' 0000000000.dkr.ecr.ap-northeast-1.amazonaws.com/<ECR リポジトリ名>:${{ env.GITHUB_REF }}' yq eval '.containers[].image = env(IMAGE_TAG)' -i k8s/pilot/development.yml

      - name: commit & push
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          BRANCH_NAME="ブランチ名"
          git config user.name <ユーザ名>
          git config user.email <メールアドレス>
          git checkout -b "$BRANCH_NAME"
          git add -A
          git commit -m "$BRANCH_NAME"
          git push origin "$BRANCH_NAME"

```

## パーソナルアクセストークンの設定方法
### パーソナルアクセストークンの発行
https://github.com/settings/tokens の`Generate new token`ボタンからトークンを発行します。

![スクリーンショット 2021-12-20 162613.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439703/f2f1c27c-5a11-a0df-78b8-e642b8a61189.png)
repo権限をつけます。
他にも必要な権限があれば適宜つけてください。

![スクリーンショット 2021-12-20 163816.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439703/ad8993d3-36b9-9e7e-12a6-882891219db2.png)
トークンを発行したら、このように表示されるので文字列をコピーします。

これでパーソナルアクセストークンの発行は完了です。

### リポジトリのシークレットを追加する
リポジトリのSettingsページからシークレットの追加をします。
GithubのリポジトリのページのSettings > Secretsにある`New repository secret`ボタンを押すと追加ができます。
Valueにさきほどパーソナルアクセストークンを発行したときにコピーした文字列を入力して`Add secret`ボタンを押すと完了します。
![スクリーンショット 2021-12-20 165038.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439703/4358c502-76df-1463-1fe7-7b821319a733.png)

これでパーソナルアクセストークンの発行＆シークレットの追加が完了したので、`${{ secrets.REPO_ACCESS_TOKEN }}`が使用できるようになります。
`REPO_ACCESS_TOKEN`の部分はシークレットを追加したときのNameになります。

# 実際に動かしてみる
Aリポジトリで`dev-39`という名前でブランチを作成。
![スクリーンショット 2021-12-20 165927.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439703/459d18d6-d069-c218-a4de-8649d6b90956.png)
SUCCESSになっていてちゃんとイベントが飛んでいそう。

BリポジトリのActionsを見てみる
![スクリーンショット 2021-12-20 170056.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439703/4a5b75ae-60cb-d22e-f045-c9a11b1047ca.png)
自動でワークフローが動いてSUCCESSになっている。
ちゃんとdevのマニフェストファイルを更新していそう。

イメージタグの更新がPUSHされているか確認する。
![スクリーンショット 2021-12-20 170323.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439703/280052e6-4c3b-a8b8-381c-40ed6c15ca54.png)
狙い通りブランチ名でイメージタグが更新されていた。