Scalahansolo
Scalahansolo

Reputation: 3065

Github action job fire when previous job skipped

While setting up my GitHub action to build and deploy my apps, I'm running into the following issue.

I want to deploy my web app under the following conditions below. However, whenever deploy-api and deploy-sync skip deploy-web is also skipped. I figured that my if condition would catch that case and still run deploy-web but it isn't. Feels like I'm missing something obvious but can't identify it.

deploy-web:
  name: Deploy Web
  runs-on: ubuntu-latest
  needs: [build-and-publish-web, deploy-api, deploy-sync]
  if: |
    needs.build-and-publish-web.result == 'success' &&
    (needs.deploy-api.result == 'success' || needs.deploy-api.result == 'skipped') &&
    (needs.deploy-sync.result == 'success' || needs.deploy-sync.result == 'skipped')

Upvotes: 36

Views: 24198

Answers (2)

rh0x
rh0x

Reputation: 1473

I prefer a more concise condition, but if your conditions are complex you may need a more complex solution as in the accepted answer:

needs: [compute_version_tag, bump_version]
if: ${{ always() && !failure() && !cancelled() }} # when none of the needed jobs fail or are cancelled (skipped or successful jobs are ok).

Beware that !cancelled() is required to be able to cancel jobs having always() in the if condition.

Upvotes: 35

Krzysztof Madej
Krzysztof Madej

Reputation: 40939

It seems like you encounter this issue - Job-level "if" condition not evaluated correctly if job in "needs" property is skipped.

Please try with always expression:

deploy-web:
  name: Deploy Web
  runs-on: ubuntu-latest
  needs: [build-and-publish-web, deploy-api, deploy-sync]
  if: |
    always() &&
    needs.build-and-publish-web.result == 'success' &&
    (needs.deploy-api.result == 'success' || needs.deploy-api.result == 'skipped') &&
    (needs.deploy-sync.result == 'success' || needs.deploy-sync.result == 'skipped')

Not specific to the original question but if all you care about is making sure there are no failures, needs.*.result provides wildcard behavior that prevents you from having to manually check each step:

  if: |
    always() &&
    !contains(needs.*.result, 'failure') &&
    !contains(needs.*.result, 'cancelled')

Upvotes: 61

Related Questions