`workflow_dispatch` でジョブが発火するには、そのワークフローファイルがデフォルトブランチにマージされている必要がある。ただし、発火の条件が「ワークフローファイルがデフォルトブランチにマージされている」というだけで、実際に使用するブランチは指定することができる。

# 目的
`workflow_dispatch` でジョブが発火するときの条件や挙動を理解する。

# 結論
`workflow_dispatch` でジョブが発火するには、そのワークフローファイルがデフォルトブランチにマージされている必要がある。
ただし、発火の条件が「ワークフローファイルがデフォルトブランチにマージされている」というだけで、実際に、使用するブランチは指定することができる。

# 説明
## (0)
もちろん、ターミナルから、GitHub API にリクエストを飛ばすことができるが、今回は、PRにpushしたときに発火するワークフロー(`.github/workflows/trigger_dispatch.yml`)から、dispatch したいワークフロー(`.github/workflows/target-workflow.yml`)を発火させることにする。

## (1)

試しに、下記のファイルを作成して、PRを新しく作る。
※ 下記では、ブランチ名は`20241016-github-api-dispatch-pra-fourth`となっていますが、PRのブランチ名に変更してください
そうすると、PR 作成と同時に、dispatch する側のワークフロー(`.github/workflows/trigger_dispatch.yml`)が発火する。
しかし、dispatch される側のワークフロー(`.github/workflows/target-workflow.yml`)は、デフォルトブランチにマージされていないので、dispatch に失敗する。

``` .github/workflows/target-workflow.yml
name: Target Workflow

on:
  workflow_dispatch:

jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - name: Run some task
        run: echo "Target workflow triggered! CCCCCCCCCC_246856"
```

``` .github/workflows/trigger_dispatch.yml
name: Trigger Dispatch

on:
  pull_request:
    branches:
      - develop

jobs:
  trigger-workflow-dispatch-by-shell-script:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger another workflow via shell script
        run: |
          curl -L --fail-with-body \
          -X POST \
          -H "Accept: application/vnd.github+json" \
          -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
          -H "X-GitHub-Api-Version: 2022-11-28" \
          https://api.github.com/repos/${{ github.repository }}/actions/workflows/target-workflow.yml/dispatches \
          -d '{"ref":"20241016-github-api-dispatch-pra-fourth"}'
        shell: bash

```

## (2)

先ほどのPRをマージする。
そして、新しくブランチを切って、`README.txt` を変更するなりして無理やり差分を作って、新しくPRを作成してみる。
※ ワークフローファイル(`.github/workflows/trigger_dispatch.yml`)のブランチ名を、新しく作成したPRのブランチ名に変更してください。
そうすると、PR 作成と同時に、dispatch する側のワークフロー(`.github/workflows/trigger_dispatch.yml`)が発火する。
先ほどは、dispatch される側のワークフロー(`.github/workflows/target-workflow.yml`)のdispatchは失敗したが、今度は成功する。ワークフローファイル(`.github/workflows/target-workflow.yml`)がデフォルトブランチにマージされているからである。

## (3)
次に、例えば、`echo "Target workflow triggered! CCCCCCCCCC_246856"` の部分を、`echo "Target workflow triggered! AAAAAAAAAA_565677"` のような文字列に変更して、このPRにpushする。
dispatch されたジョブのログを見に行くと、文字列の変更が適用されていることがわかる。

## (4)

まとめると、`workflow_dispatch` は特定のブランチに存在するジョブを発火させることができるが、そのジョブ自体は、デフォルトブランチにマージされている必要があるということである。

# ついで
## `github-script`アクション
dispatch する側のワークフロー(`.github/workflows/trigger_dispatch.yml`)は、`github-script` を使って下記のように書くこともできる。

``` .github/workflows/trigger_dispatch.yml
name: Trigger Dispatch

on:
  pull_request:
    branches:
      - develop

jobs:
  trigger-workflow-dispatch:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger another workflow
        uses: actions/github-script@v6
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            const owner = context.repo.owner;
            const repo = context.repo.repo;
            const workflow_id = 'target-workflow.yml';
            const ref = '20241016-github-api-dispatch-pra-fourth';
            
            await github.rest.actions.createWorkflowDispatch({
              owner: owner,
              repo: repo,
              workflow_id: workflow_id,
              ref: ref
            });
```

## curl の `--fail-with-body` 
curl は通常、404 が返ってきたとしても、`exit 0`で終了するので、ワークフローが正常終了してしまう。
このオプションによって、404 が返ってきたときに、レスポンスメッセージを表示させつつ、`exit 0`以外で終了することが可能になる。
`--fail`オプションは、`exit 0`以外で終了するが、レスポンスメッセージが表示されないので、`--fail-with-body`オプションがよい。

## `${{ github.repository }}`
curl のリクエスト先のURLにおいて、`${{ github.repository }}` は、`{レポジトリのオーナー}/{レポジトリ名}` となっているので、`${{ github.repository_owner }}/${{ github.repository }}` とする必要がない。

## `shell: bash`
ワークフローで、`shell: bash`を明示的に指定すると、下記のようにシェルスクリプトの起動時オプションが変化する。
※ 今回は`shell: bash`を使っているが、該当箇所は curl 特有のエラーの話なので、使っても使わなくてもどちらでも変わらない。

```
# `shell: bash`がない場合
$ bash -e {0}

# `shell: bash`がある場合
$ bash --noprofile --norc -e -o pipefail {0}
```

- `--noprofile`: 起動時に、`~/.profile`を読み込まない
- `--norc`: 起動時に、`~/.bashrc`を読み込まない
- `-e`: エラーが起きたら強制終了
- `-o pipefail`: パイプエラーを捕捉する。通常、パイプでつながれた場合、最後のコマンドのみによって、`exit 0`(成功)かそれ以外かを決定するが、このオプションによって、パイプの途中でもエラーが起きれば、非ゼロ(`exit 0`以外)で終了する。
- `{0}`: ここに実行されるメインのシェルスクリプトが来る。

# 参考

https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event

https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_dispatch

https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_dispatch

https://github.com/actions/github-script?tab=readme-ov-file

https://octokit.github.io/rest.js/v21/

https://dev.classmethod.jp/articles/github-actions-running-a-workflow-for-a-workflowdispatch-trigger-that-is-not-on-the-default-branch/

https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/manually-running-a-workflow

https://superuser.com/questions/590099/can-i-make-curl-fail-with-an-exitcode-different-than-0-if-the-http-status-code-i