🛠️
GitHub ActionsのJobスキップの仕様
以下のようなワークフローを実行したらどのようになるでしょうか?
name: Dispatch Workflow
on:
workflow_dispatch:
jobs:
first_job:
name: First Job
runs-on: ubuntu-latest
if: false
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
second_job:
name: Second Job
runs-on: ubuntu-latest
needs: first_job
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
third_job:
name: Third Job
runs-on: ubuntu-latest
needs: second_job
if: success() || failure()
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
third_job
の発動条件はneeds: second_job
とif: success() || failure()
なので、second_job
の終了を待ってから、second_job
が成功するか失敗したら発動しそうに見えます。
しかし、実際にはスキップされてしまいます。
つまりJobスコープでのif: success()
などの条件は一つ前のJobの結果を見ているのではなく、ワークフロー全体を見ているようです。
では、needs.second_job.result == 'success'
のように一つ前のJobの結果を直接見るようにしたらどうでしょうか?
name: Dispatch Workflow
on:
workflow_dispatch:
jobs:
first_job:
name: First Job
runs-on: ubuntu-latest
if: false
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
second_job:
name: Second Job
runs-on: ubuntu-latest
needs: first_job
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
third_job:
name: Third Job
runs-on: ubuntu-latest
needs: second_job
if: needs.second_job.result == 'success' || needs.second_job.result == 'failure'
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
やはりスキップされてしまいました。
全体でスキップされているJobがある場合、そもそもif
の条件に入る前にスキップ判定になってしまうようです。なので、always()
の条件もつけます。
name: Dispatch Workflow
on:
workflow_dispatch:
jobs:
first_job:
name: First Job
runs-on: ubuntu-latest
if: false
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
second_job:
name: Second Job
runs-on: ubuntu-latest
needs: first_job
if: always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
third_job:
name: Third Job
runs-on: ubuntu-latest
needs: second_job
if: always() && (needs.second_job.result == 'success' || needs.second_job.result == 'failure')
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Run Shell
run: echo "Hello World"
すると、ようやくスキップされずに実行されました。
Jobの発動条件は注意深く指定しないといけませんね。
Discussion
always()の挙動について、参考にさせていただきました。ありがとうございます。
ただ、以下の文言については、正確ではないと思われる箇所がありましたので、投稿させていただきます。
↑上記文言について、正しくは「間接依存も含めたneedsに含まれているjobの中で、でスキップされているJobがある場合」が正しいかと思います。
全体の一部であっても、needsの間接依存にないものに関しては、skipされようが関係ないと思われます。