GitHub Actions の `post: action` で、ジョブの成功時・失敗時で挙動を変える方法

2025/01/05に公開

tl;dr

  • Action の input (with) として ${{ job.status }} を渡す
  • その input 値を元に処理を分岐させる

post: action とは

GitHub Actions で Action の action.yml または action.yaml において、runs.post で指定する、ジョブの完了時に実行される処理です。

ドキュメント上そのように表記されていたので、この記事においてもそれに倣います。

これは主に Action のクリーンアップ処理として使われるもので、例えば actions/checkout においては Git の設定ファイルから認証トークンの削除などを行なっているようです。

https://github.com/actions/checkout/blob/v4.2.2/src/git-source-provider.ts#L290-L332

やりたいこと、その具体例

今回やりたいのは、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 inputsdefault に指定しても良いです。

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() とすれば良いのですが、今回やりたいことは「成功・失敗に関わらず実行はして、その上で挙動を分岐させたい」なので、そもそもやりたいこととは違うことがわかります。

JavaScript Action 内で job コンテキストを参照する

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 を指定している場合なども考慮した場合 (正確に説明するのが難しい)

Discussion