notebook

都内でWEB系エンジニアやってます。

GitHubActionsのrepository_dispatchを使い特定ブランチでWorkflowを実行する

背景

任意のタイミング、ブランチでworkflowを実行したい

push時にも同じworkflowを実行したい

repository_dispatch

GitHubActionsを使って任意のタイミングでworkflowを実行するためにはrepository_dispatcheventを指定すればよい

Events that trigger workflows - GitHub Help

help.github.com

event_typeによる実行対象のフィルタリング

ヘルプを見るとtypes指定は出来なそうに見えるがAPIをたたくときにevent_typeを指定すればよしなにフィルタリングしてくれるよう

  • workflow.yml
on:
  repository_dispatch:
    types: [hoge]
  • curl
curl -X POST -H  -H "Authorization: token $TOKEN" -H "Accept: application/vnd.github.everest-preview+json" --data '{"event_type": "hoge"}' https://api.github.com/repos/:user/:repo/dispatches

上記であればevent_typehoge以外を指定した場合はworkflowが実行されない

なので複数のworkflowファイルにそれぞれrepository_dispatchを指定してもテストのときはこっちのyml、デプロイのときはこっちのymlといった具合に使い分けができる

特定のブランチでworkflowを実行したい

これだけだと常にworkflowの実行はmasterブランチなので特定ブランチで何かさせたいときに対応出来ない

フォーラムにも同様のスレッドが立ってたりしていた

How to trigger repository_dispatch event for non-d... - GitHub Community Forum

github.community

client_payloadを用いてjson payloadを渡す

Repositories | GitHub Developer Guide

developer.github.com

repository dispatch eventのAPIはevent_typeのほかにclient_payloadで任意のjsonを渡すことができる

この中身にブランチを指定してあげればあとはGitHubActions側でよしなにできる

ちなみにこのclient_payload

jsonを渡さないと駄目らしい

--data '{"event_type": "hoge", "client_payload": "aaa"}'
{
  "message": "Invalid request.\n\nFor 'properties/client_payload', \"aaa\" is not an object.",
  "documentation_url": "https://developer.github.com/v3"
}

pushとrepository_dispatchのevent内容の違い

任意のタイミングでも実行したいが、通常(push)時にはpushされたブランチで実行したいので分岐をさせる必要がある

差分を確認するためにevnetの内容を確認する

  • 確認用設定
name: sample
on: [push, repository_dispatch]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: cat $GITHUB_EVENT_PATH
  • push時のevent
{
  "after": ".....",
  "base_ref": null,
  "before": ".....",
  "commits": [
  • dispatch apiをcurlでたたいたときの--dataの中身
--data '{"event_type": "hoge", "client_payload": {"ref": "feature/branch-a"}}'
  • repository_dispatch時のevent
{
  "action": "hoge",
  "branch": "master",
  "client_payload": {
    "ref": "feature/branch-a"
  },
  "repository": {

中身が全然違う

ということで今回はclient_payloadがあるかで分岐すればよさそう

特定のブランチをcheckoutする

actions/checkout: Action for checking out a repo

github.com

checkout時に特定のブランチを指定したい場合はREADMEにあるとおり

steps:
  - uses: actions/checkout@master
    with:
      ref: branch

で切り替えることができる

branchはdispatchイベントで受け取ったjsonから取得すればOK

ドキュメントは下記

GitHub Actions のコンテキストおよび式の構文 - GitHub ヘルプ

help.github.com

  • workflow.yml
on:
  push:
  repository_dispatch:
    types: [hoge]
jobs:
  hoge:
    runs-on: ubuntu-latest
    name: hoge
    steps:
      - uses: actions/checkout@master
      - if: github.event.client_payload
        uses: actions/checkout@master
        with:
          ref: ${{ github.event.client_payload.ref }}

github.event.client_payloadがあればrepository_dispatchイベント経由と判断しclient_payload.refの値を使うようにする

当たり前だが存在しないブランチをrefに指定してPOSTするとエラーとなる

このケースだとAPI実行時は次のような感じで実行できるようになる

curl -X POST -H "Authorization: token $TOKEN" -H "Accept: application/vnd.github.everest-preview+json" --data '{"event_type": "hoge", "client_payload": {"ref": "feature/branch-a"}}' https://api.github.com/repos/:user/:repo/dispatches

pushイベントのときは分岐を通らないのでpushされたブランチで実行される

まとめ

特定のブランチをチェックアウトしてからworkflowを実行できるようになった

やったことの流れ

  • Actions: on.repository_dispatchで任意のworkflowをAPI経由で実行可能にする
  • API: event_typeで実行対象のworkflowを指定する
  • API: event_payloadで任意のjsonを渡す
  • Actions: client_payloadのjsonを元に特定ブランチをcheckoutする
  • Actions: checkoutしたブランチでworkflowを実行する

若干無理やり実現しているため次の点で微妙なところが残ってしまった

  • Jobごとに分岐を入れてcheckoutする必要が出てしまう
  • Actions上ではmasterで実行している扱いになってしまう

ただ、応用すれば「特定のブランチで確認用の環境立ち上げる」みたいなこともできそう

GitHubActions楽しい