Alternative Architecture DOJO

オルターブースのクラウドネイティブ特化型ブログです。

GitHub Create workflow dispatch event APIのお供

この投稿は、オルターブース Advent Calendar 2023の8日目の投稿になります。

adventar.org

こんにちは。オルターブースエンジニアのみっつーです。 本日はAzure Static Web Appsへのデプロイを例に、 GitHub ActionsをGitHub APIで発火させるときに設定しておくと嬉しいパラメータ についてお話したいと思います。

デフォルトワークフローを見てみる

まず今回メインで登場する、皆さん既にお馴染みのAzure Static Web Appsに対するGitHub Actionsワークフローの公式テンプレートは下記の通りです。

name: Azure Static Web Apps CI/CD

on:
  push:
    branches:
      - main
  pull_request:
    types: [opened, synchronize, reopened, closed]
    branches:
      - main

jobs:
  build_and_deploy_job:
    if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: true
      - name: Build And Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (i.e. PR comments)
          action: "upload"
          ###### Repository/Build Configurations ######
          app_location: "src" # App source code path relative to repository root
          api_location: "api" # Api source code path relative to repository root - optional
          output_location: "public" # Built app content directory, relative to app_location - optional
          ###### End of Repository/Build Configurations ######

  close_pull_request_job:
    if: github.event_name == 'pull_request' && github.event.action == 'closed'
    runs-on: ubuntu-latest
    name: Close Pull Request Job
    steps:
      - name: Close Pull Request
        id: closepullrequest
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          action: "close"

learn.microsoft.com

これは、pull_requestイベントをトリガーにプレビュー環境を更新/削除する機能も持っています。
Azure Static Web Appsのプレビュー環境についてはこちら

learn.microsoft.com

今回はこのワークフローをベースに、workflow_dispatchイベントや周辺定義を追加していきます。
用途の一例として、 GitHub Actionsを使って「HeadlessCMSのバックエンドを元にSSGでビルドした成果物をAzure Static Web Appsにデプロイする」 場面を想定します。

つまりこう。

workflow_dispatchを使う

HeadlessCMS x SSGの組み合わせの場合、 「HeadlessCMS上での投稿更新をトリガーに、自動でAzure Static Web Appsにホストしている静的サイトも更新したいなあ」 と考えるかと思います。 このとき、(HeadlessCMSでの投稿更新イベントはWebhook等で別途検知するとして、検知した後に)GitHub Actionsを発火するために workflow_dispatch イベントが使用可能です。
流れとしてはこうですね。

workflow_dispatchイベントは手動発火する用途で使うものですが、外部からGitHub API経由で発火する用途にも使用できます。
イベント定義は on: 配下に足します。

on:
  workflow_dispatch:

Azure Static Web Appsのワークフローテンプレートはイベント名で条件分岐しているので、workflow_dispatchも忘れずに条件に追加します。

jobs:
  build_and_deploy_job:
    if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    runs-on: ubuntu-latest

APIの叩き方は何でも良いですが、ここではcurlでGitHub APIを叩いてみます。
参考までに、公式ドキュメントに載ってあるスニペットは下記です(但しinputsはこの時点では不要)。

curl -L \
  -X POST \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW_ID/dispatches \
  -d '{"ref":"topic-branch","inputs":{"name":"Mona the Octocat","home":"San Francisco, CA"}}'

docs.github.com

無事発火されたことが確認できました。
但し今のワークフロー定義だと、workflow_dispatchによる発火時は常にnameで定義してある値(今回は「Azure Static Web Apps CI/CD」)が使用されるため、実行する度にワークフロー実行名が被ってしまいます。

run-nameを使う

HeadlessCMSを使用して更新する場合は、 どの投稿の更新がトリガーになったのか知りたい 場合が多いと思います。
そんな時に、 inputsrun-name を組み合わせて使用することが可能です。

以下のように定義すると、例えばGitHub APIからworkflow_dispatchを発火させる際、リクエストパラメータとしてrun-nameに設定したい文字列を渡すことが可能になります。

run-name: '${{ inputs.workflow_run_name }}'

on:
  workflow_dispatch:
    inputs:
      workflow_run_name:
        description: 'workflow run-name from HeadlessCMS event'
        default: ''
        required: false
        type: string

再度curlで叩いてみます。
先ほどのcurlコマンドをベースに、例えば、inputsを下記のように指定してみてください。

-d '{"ref":"main","inputs":{"workflow_run_name":"curlで叩いた"}}'

実行名が上書きされることが確認できました。
例えばHeadlessCMSの場合は 投稿更新イベントで投稿のIDやタイトルが取れる ことが多いので、それをrun-nameに渡すことでどの投稿の更新を起点にワークフローが発火したかを知ることが可能になります。

ちなみに、run-name定義を書いている場合でも、 run-nameに空文字が渡された場合は、元の文言が使用されます。 (特に、workflow_dispatch以外のイベントで発火した場合は今まで通りの実行名(プルリクなんちゃらマージ など)が使用されます。)

docs.github.com

concurrencyを使う

HeadlessCMS上で投稿作成→すぐ更新とする場合や複数投稿を行う場合に、 ワークフローを無駄に複数回トリガーしてしまう ことも往々にしてあるかと思います。
ワークフローが複数回同時実行されることは、予期せぬエラーのもとになったりリソースを余計に食ってしまったりとあまり良くないことが発生する原因になりかねません。

この時、 concurrency 定義を入れておくと、同時発火を避けることができます。
古いものから順次実行することもできれば、新しい発火があれば古いものはキャンセルして最新の一件のみ回すといったことも可能です。
例えば、イベント名とブランチ名の両方が被ったものを同時実行させないようなconcurrency定義は下記のとおりです。

jobs:
  build_and_deploy_job:
    if: github.event_name == 'workflow_dispatch' || github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
    concurrency: ${{ github.event_name }}-${{ github.base_ref || github.ref }} # {イベント名}-{ブランチ名}
    runs-on: ubuntu-latest
    name: Build and Deploy Job

このconcurrency定義を追加した状態で、curl連打してみます。

新しいものが順番待ちになることが確認できました。

上記いずれもちょっとしたカスタマイズですが、GitHub API経由でワークフロー発火する際には割とあった方が便利な機能かと思います。
まだ気にしたこともなかったような機能があれば、これを機に試してみていただければと思います。

一応今回検証に使ったGatsbyでのサンプルコードを貼っておきます。
※皆さんお気づきかと思いますがHeadlessCMS側のソースコードは尺の都合上登場しておりません。またどこかで。

github.com

おわりに

今回はHeadlessCMSとSSGの連携を例に挙げさせていただきましたがそれに限らず、HTTPリクエスト起点で自動化したい処理はちょいちょい出てくると思います。
そういった意味では、今回の内容が似たような目的の際に少しでも参考になれば幸いです。

以上、GitHub Create workflow dispatch event APIのお供 feat. Azure Static Web Appsをお届けさせていただきました。
オルターブース Advent Calender 2023を引き続きお楽しみください!


サービス一覧 www.alterbooth.com cloudpointer.tech www.alterbooth.com