GitHub Actions - Workflowを連鎖させてみる
GitHub Actionsで、Workflow内から他のWorkflowを呼び出したり、Workflowの開始・終了をEventとすることができるようになった。
なので、具体的にどのようにWorkflowを連鎖させられるのか整理してみようと思う。
on:workflow_call
Workflowのトリガー対象とするEvent
に、workflow_call
を指定すると、他のWorkflowから呼び出すことを許可できる。
同一リポジトリ内であれば、次のように呼び出せる。
name: call
on:
workflow_call:
jobs:
myjob:
runs-on: ubuntu-20.04
steps:
- run: echo "HELLO CALL"
name: main
on:
push:
jobs:
myjob:
runs-on: ubuntu-20.04
steps:
- run: echo "HELLO MAIN"
call-workflow:
needs: [myjob]
uses: ./.github/workflows/call.yml
実行されたWorkflowのSummaryを見ると、次のようになっている。
このとき、呼び出されたWorkflow(call.yml
)は、呼び出したWorkflow(main.yml
)の一部であるかのような扱いになっている。
たとえば、呼び出された側のgithub context
は、呼び出した側の値と同じになっていたり、secrets
を渡さないと使えなかったりする。
なので、呼び出された時を考えずに、github context
の値を参照したりすると、意図しない動作になってしまう場合がある。
たとえば、両方のWorkflowにconcurrency: ${{ github.workflow }}
を設定すると、呼び出された側の判定がconcurrency: main
となり、永遠に待ち状態になってしまう。
また、呼び出されたWorkflowから、他のWorkflowを呼び出すことはできない。
なので、末端のJob
をWorkflowとして切り出し共通利用する、ぐらいの用途に制限されてしまう感じがする。
機能は随時アップデートされているので、そのうち改善されることと期待したい。
on:workflow_run
明示的に呼び出すのではなく、Workflowの開始・終了Event
に応じて、Workflowをトリガーするにはworkflow_run
が使える。
基本的な使い方は、↓で確認済み。
name: main
on:
push:
jobs:
myjob:
runs-on: ubuntu-20.04
steps:
- run: echo "HELLO MAIN"
name: run
on:
workflow_run:
workflows: [main]
types: [completed]
jobs:
myjob:
runs-on: ubuntu-20.04
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- run: echo "HELLO RUN"
この場合は、複数のWorkflowを連鎖させることができる。(3回まで)
また、独立したWorkflowとして起動するため、github context
も、それぞれ独立した値となる。
ただし、Workflow間の繋がりを可視化する仕組みが用意されていないので、連鎖の状況は確認しづらい感じがある。
まとめ
連鎖の繋がりや状態を可視化できるので、workflow_call
を優先して使いたい感じがある。
ただし、github context
の扱いに注意が必要だったり、呼び出された側でworkflow_call
を使えなかったり、といった制約を考慮して構成を考える必要がある。
なので、パイプライン全体を制御するWorkflow、と、再利用する各Workflow、に分ける感じだろうか。
name: main
on:
push:
workflow_dispatch:
jobs:
myjob1:
concurrency: main
runs-on: ubuntu-20.04
steps:
- run: echo "HELLO MAIN"
myjob2:
needs: [myjob1]
uses: ./.github/workflows/call.yml
myjob3:
needs: [myjob1]
uses: ./.github/workflows/call.yml
myjob4:
needs: [myjob2, myjob3]
uses: ./.github/workflows/call.yml
myjob5:
needs: [myjob1]
uses: ./.github/workflows/call.yml
myjob6:
needs: [myjob1]
uses: ./.github/workflows/call.yml
myjob7:
needs: [myjob5, myjob6]
uses: ./.github/workflows/call.yml
myjob8:
needs: [myjob4, myjob7]
concurrency: last
uses: ./.github/workflows/call.yml
そうすることで、↓のようなパイプラインを組むことができつつ、他パイプラインで共通して呼び出すWorkflowの再利用も実現できる。
また、パイプライン全体を制御するWorkflow側で、Concurrency
やgithub context
依存の値生成・判定を行えば、いい感じに同時実行を制御したりできそうな感じがする。
で、Workflowの開始・終了に応じた通知を、workflow_run
でトリガーするようにすると、パイプラインのロジックから本質的でない通知処理を排除することができそう。
再利用する必要なければ、Jobの中にStepを書いていけばよいし、目立ったデメリットはなさそうな感じがする。
Discussion