GitHub Actions の repository_dispatch イベントを使ってリポジトリ間でリリースイベントを伝播させる

タイトルの通りですが最近は GitHub Actions をいじる機会が多く、リポジトリ間でリリースイベントを伝播してワークフローを実行するなどしたかったので備忘録です。

# repository_dispatch を使う

`repository_dispatch` は GitHub の外部のイベントを検知するために用意されている機能です。GitHub API に用意されてるエンドポイントからワークフローをトリガーすることができます。https://docs.github.com/en/actions/reference/events-that-trigger-workflows#repository_dispatch

なお、 `repository_dispatch` イベントが実行されるのはワークフローが master もしくはデフォルトブランチにあるときのみとなります。

# repository_dispatch API 実行によるワークフローのトリガー

### repository_dispatch API について

ワークフローが配置されてるリポジトリに対してAPIを実行することでワークフローを実行することができます。
APIの実行の際には認証がかかるので[パーソナルアクセストークン](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)を指定する必要があります。

また、リクエストボディには下記のフィールドの指定が必要となります。

| Field| Description |
|:---:|:---|
|event_type|文字列を指定します。トリガーされたワークフローにて event payload における action として扱われます|
|client_payload|トリガーするイベントに伝播する情報をJSONオブジェクトとして自由に設定できます|

curl で叩くときは以下のような感じになります。

```sh
curl -X POST https://api.github.com/repos/:owner/:repo/dispatches \
  -H 'Accept: application/vnd.github.everest-preview+json' \
  -u $your_user:$your_personal_access_token \
  --data '{"event_type": "$your_event", "client_payload": { "customField": "customValue" }}'
```

### APIを叩いてワークフローを実行する

以下はサンプルのワークフローです。`on`に`repository_dispatch`を指定します。
※繰り返しとなりますがmasterかデフォルトブランチしかトリガーされません。

```yaml:test.yml
name: Repository Dispatch Sample

on: repository_dispatch

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Event Information
        run: |
          echo "Event is '${{ github.event.action }}'" 
          echo "Message is '${{ github.event.client_payload.message }}'"
```

実際にAPIを叩いてみるとワークフローが実行されます。

![スクリーンショット 2020-08-31 23.18.55.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142263/07b741ff-1c4f-14a8-bdda-dbdf4584889c.jpeg)

![スクリーンショット 2020-08-31 23.27.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142263/0f853566-4ad8-8e38-88f1-ab63cd50acac.png)

# リポジトリ間でリリースイベントを伝播させるワークフローを作る

`repository_dispatch` を使うことでAPIを通じてワークフローを起動できることから、ワークフロー内部でAPIを叩くことができればワークフローからワークフローをトリガーできることがわかります。

これを応用して、リポジトリ間でリリースイベントを伝播するワークフローを構築しました。

### リリースイベントの伝播元となるワークフロー

リリースを `Publish` するとワークフローが起動し、タグなどのリリース関連の情報を`client_payload`に詰めてAPIを実行します。curlコマンドの`-u`オプションに指定するユーザー名およびパーソナルアクセストークンおよびユーザー名は`secrets`から読み込みます。

```yml:release.yml
name: Release

on:
  release:
    types: published
    tags: v*.*.*

jobs:
  Release:
    runs-on: ubuntu-latest
    steps:
      - name: Set var of release version 
        run: |
          echo ::set-env name=RELEASE_VERSION::${GITHUB_REF#refs/*/}

      - name: Set var of request header
        run: |
          echo ::set-env name=REQUEST_HEADER::"'"Accept:application/vnd.github.everest-preview+json"'"

      - name: Set var of request body
        run: |
          echo ::set-env name=REQUEST_BODY::'{"event_type": "release", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'", "tag_name": "'"$RELEASE_VERSION"'", "release_name": "Repository Dispatch Test"}}'

      - name: Repository dispatch
        run: |
          curl -X POST https://api.github.com/repos/:owner/:repo/dispatches \
          -H $REQUEST_HEADER \
          -u ${{ secrets.PERSONAL_ACCESS_TOKEN }} \
          --data "$REQUEST_BODY"
```

### 伝播先のワークフロー

受け取ったリリース関連情報を元にリリースを作成します。ワークフローからのリリースの作成には[create-release](https://github.com/actions/create-release)を使いました。

```yml:create_release.yml
name: Create Release

on: repository_dispatch

jobs:
  Create_Release:
    runs-on: ubuntu-latest
    steps:
      - name: Event Information
        run: |
          echo "Event '${{ github.event.action }}' received from '${{ github.event.client_payload.repository }}'"
      - name: Create Release
        if: github.event.action == 'release'
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.event.client_payload.tag_name }}
          release_name: ${{ github.event.client_payload.release_name  }}
          draft: false
          prerelease: false
```

### 動作確認

まずは伝播元のリポジトリでリリースを作成します。

![スクリーンショット 2020-09-01 0.26.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142263/f772a1e8-0361-d632-452a-935c85b2b305.png)

リリースが作成されたことを受けてワークフローが起動し、`Repository dispatch A`で伝播先のリポジトリに対して repository_dispatch の API を実行しているのがわかります。

![スクリーンショット 2020-09-01 0.26.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142263/bb6c511e-7061-e49d-dc27-03b46b092acc.png)

伝播先のリポジトリの挙動を確認します。

![スクリーンショット 2020-09-01 0.42.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142263/65806708-f849-d7f3-2f40-a0ed315ace3e.png)

![スクリーンショット 2020-09-01 0.47.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142263/cb57bfe9-8ec0-b310-0079-5f857ea861e1.png)

伝播先でもワークフローの実行とリリースの作成が確認できました。

# 参考

https://blog.marcnuri.com/triggering-github-actions-across-different-repositories/
https://stackoverflow.com/questions/58177786/get-the-current-pushed-tag-in-github-actions

# 終わり

おわりです。