リリース当初は git push など GitHub 上のイベントしかトリガーにできなかった GitHub Actionsですが、
workflow_dispatch イベント の登場により手動実行ができるようになりました。
社内でもこの機能を利用してワークフローの手動実行をしていたのですが、人間とは欲深いもので「毎回ワークフローを選択してポチポチするのだるい」という声があがってきました。 そういうわけで、Pull Request のコメントをトリガーにしてワークフローを実行する簡単なボットを作ってみました。
方針
workflow_dispatch と issue_comment をトリガーにしたワークフローを作ればいいだけの気もしますが、
以下のような理由からワークフローからワークフローを呼び出す形にしました。
- workflow_dispatchを使った既存のワークフローがあるので、それを流用したい- トリガーが複数あると、イベントの種類に応じてペイロードの形式が異なるので、地味に処理が大変
- issue_commentは全部のコメントに反応するので、本当に見たいログが埋もれてしまう
 
- コメントを投稿した Pull Request のHEADでワークフローを実行して欲しい
- issue_commentはイベントの発生元として、デフォルトブランチのHEADが渡ってきます
- イベントのペイロードには、プルリクエストへのリンクが入っているだけで、HEADの情報はわからない
 
実装
jfurudo1 がサードパーティのアクションを使ってゴニョゴニョやっていたものの、 あんまりうまく行ってなさそうだったので、bash script でエイヤッと書き直しました。
「build」 とコメントすると、.github/workflows/build.yml のワークフローを実行するサンプルです。
name: comment hook
on:
  issue_comment:
    types: [created]
jobs:
  distribute:
    runs-on: ubuntu-latest
    steps:
      - name: dispatch workflow
        run: |
          # イベントに関する詳細情報を取ってくる
          PAYLOAD=$(cat "$GITHUB_EVENT_PATH")
          NUMBER=$(echo "$PAYLOAD" | jq -c '.issue.number')
          # Issue と Pull Request のコメントが混ざってくるので、Issueは無視する
          if [[ "$(echo "$PAYLOAD" | jq -c '.issue.pull_request')" = "null" ]]; then
            echo "It's not pull request. Skip it."
            exit 0
          fi
          # 前述の通り $PAYLOAD にはプルリクエストの詳細が入っていないので、GitHub CLIを使って詳細を取得
          PULL_REQUEST=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$NUMBER")
          # jq でコメントの内容を取り出し、正規表現マッチ
          if [[ "$(echo "$PAYLOAD" | jq -c '.comment.body | test("build"; "i")')" = "true" ]]; then
            # レスポンスを返してあげる
            gh api "repos/$GITHUB_REPOSITORY/issues/$NUMBER/comments" -F "body=ビルドを実行します :rocket:"
            # ワークフロー呼び出し
            # Pull Request の .head.ref を渡してあげているのがポイント
            gh api "repos/$GITHUB_REPOSITORY/actions/workflows/build.yml/dispatches" -F "ref=$( echo "$PULL_REQUEST" | jq -r '.head.ref')"
          fi          
        env:
          # 標準で渡ってくる secrets.GITHUB_TOKEN は他のワークフローを呼び出せないので、
          # コメント専用にトークンを発行する
          GITHUB_TOKEN: ${{ secrets.USERS_GITHUB_TOKEN }}
GitHub CLI がGAになり 程なくして GitHub Actions にも Pre Install されるようになったのでこれを使っています。
残念ながらIssueへの書き込み等は対応しておらず gh api を使ってほぼ生のAPIを叩くことになります。
しかし認証ヘッダーを環境変数から読み取ってくれる分 curl で頑張るよりは少し楽になりました。
ちなみに gh api "repos/:owner/:repo" のようにレポジトリ名を表すプレースホルダーが使えるのですが、上のワークフローでは使っていません。
代わりに GITHUB_REPOSITORY 環境変数を使っています。
なぜかというとレポジトリをクローンせずにYAMLファイルの中で完結しているので、GitHub CLI がレポジトリを特定できないんですね。
プレースホルダーを使ったほうが短くかけるし、手元でのデバッグもやりやすいので、使えると良かったんですけどね。
まとめ
やはり頼れるのは jq と curl。あとついでに GitHub CLI