GitHub Actions の `post: action` で、ジョブの成功時・失敗時で挙動を変える方法
tl;dr
- Action の
input
(with
) として${{ job.status }}
を渡す - その
input
値を元に処理を分岐させる
post: action
とは
GitHub Actions で Action の action.yml
または action.yaml
において、runs.post
で指定する、ジョブの完了時に実行される処理です。
ドキュメント上そのように表記されていたので、この記事においてもそれに倣います。
これは主に Action のクリーンアップ処理として使われるもので、例えば actions/checkout においては Git の設定ファイルから認証トークンの削除などを行なっているようです。
やりたいこと、その具体例
今回やりたいのは、Job の中である Action を呼び出し、Job 全体の成功・失敗によって post: action
の挙動を変える、というものです。
「Job 全体」の成功・失敗なので、その Action 自体の失敗だけではなく、後続の Step に何か失敗があったかどうか、も関わります。
ただし、post: action
を実行している時点では Job の最終的なステータスは確定していません。その post: action
自体が結果的に失敗することもありますし、さらに後続の別の post: action
が失敗することもあり得るためです。
ここでは「少なくともその post: action
を実行している時点で失敗状態になっていないか」をチェックします。
これで具体的に何をやりたいかというと、CI/CD ジョブの状態をなんらかのデータストア (例: DynamoDB) に保存しておくためです。
これにより、CI/CD ジョブの再実行が必要かどうかを判定したりするのに使いたい、というのが私の本来のモチベーションでした。
うまくいった方法
Action の input
(with
) として ${{ job.status }}
を渡すことでうまくできました。
例えば以下のような感じです。
steps:
- uses: yuya-takeyama/some-action
with:
job-status: ${{ job.status }}
または、action.yml
inputs
の default
に指定しても良いです。
inputs:
job-status:
required: true
default: ${{ job.status }}
JavaScript Action の中では普通に job-status
の input を使って処理を書くだけです。 (コード例は割愛)
ポイントとしては以下です。
-
post: action
にもwith
で指定した input 値は渡される - かつ、コンテキスト値 (ここでは
job
) の評価はpost: action
実行のタイミングで行われる (らしい)
後者については観察した結果の推測であって、厳密に正しいかはわかりません。
ですが、少なくとも「元の main: action
を実行する時に inputs
を保存しておいて、post: action
の実行時にも再び渡している」といった実装ではなさそうです。
前者についてはもともと把握していたことで、何となくそのような実装を想像していましたが、実際に試したら違った、というものです。
うまくいかなかった方法
runs.post-if
を指定する
これは post: action
を実行するかどうかを判定する式を指定するのに使います。
「失敗した時だけ実行したい」であれば post-if: failure()
とすれば良いのですが、今回やりたいことは「成功・失敗に関わらず実行はして、その上で挙動を分岐させたい」なので、そもそもやりたいこととは違うことがわかります。
job
コンテキストを参照する
JavaScript Action 内で Workflow の YAML の中であれば、job
コンテキストの中にある status
を参照することで "success"
, "failure"
, "cancelled"
のいずれかの値が取得できます。
ですが、この値は Workflow の YAML の中 (それも一部) で参照できるもので、JavaScript アクションからは参照できません。
JavaScript Action 内で Job の実行状態を API から取得する
Get a job for a workflow run
API を使うというものです。
Action 自身が実行されている Job の状態を API から取得すればいけるのでは、と考えて試行錯誤しましたが、色々あって難しそうでした。
- まず実行している Action 自身が属する Job ID を取得するのが難しい
-
github.job_id
で取得できるのは、この Job ID ではなく、Workflow の YAML の中で指定する Job の名前だった
-
- 仮に List jobs for a workflow run attempt を駆使して Job ID を取得できたとしても、API から取得する Job の状態は若干遅延しているの、直前の Step で失敗していた場合も成功状態として取得してしまうことがありそう
- 実際は Matrix Build の場合などは、Job ID を正確に取得するのはかなり難しそうだった。特に Workflow 側で Job の
name
を指定している場合なども考慮した場合 (正確に説明するのが難しい)
- 実際は Matrix Build の場合などは、Job ID を正確に取得するのはかなり難しそうだった。特に Workflow 側で Job の
Discussion