Reputation: 1661
I want to run a notification job that lets me know that my workflow failed, is there a way to do that without having to needs
every job and checking the status of each one?
This is how I would have to do it now but it gets cumbersome if I have a ton of jobs:
jobs:
first-job:
runs-on: ubuntu-20.04
steps:
- exit 0
second-job:
runs-on: ubuntu-20.04
steps:
- exit 1
notify-job:
runs-on: ubuntu-20.04
needs: [first-job, second-job]
if: ${{ always() && (needs.first-job.result == 'failure' || needs.second-job.result == 'failure') }}
steps:
- ./notify.sh
I want to simply check if the workflow failed in any capacity at the end, i.e. if any job failed, is that possible?
I see this documentation to check if the triggering workflow failed (https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-a-workflow-based-on-the-conclusion-of-another-workflow).
Is there a way to run a finally
or ensure
status check at the end of the current workflow?
Upvotes: 13
Views: 18443
Reputation: 736
I found this less verbose syntax:
if: ${{ always() && contains(needs.*.result, 'failure') }}
Meaning, if any of the jobs listed in needs
return "failure" then run this job...
Source: https://docs.github.com/en/actions/learn-github-actions/expressions#contains
Upvotes: 23
Reputation: 22890
Github partner brightran stated in this post:
By default, once a step in a running job fails, all the subsequent steps in this job will be skipped and this job will be marked as failed. If you want the subsequent steps still execute, you can add the if conditional (if: always()) in each subsequent step.
Add 2 extra steps at the end of the job1 and job2, and set the 2 steps always execute (if: always()). The first one is used to create a text file and write the job status into it, and the second one is used to upload this text file as an artifact. In job3, you also need to add the steps to download the artifacts and read the statuses of jo1 and jo2.
Using this workflow as demo:
jobs:
JOB_01:
name: Job 01
. . .
steps:
- name: Some steps of job 01
. . .
- name: Create file status_job01.txt and write the job status into it
if: always()
run: |
echo ${{ job.status }} > status_job01.txt
- name: Upload file status_job01.txt as an artifact
if: always()
uses: actions/upload-artifact@v1
with:
name: pass_status_job01
path: status_job01.txt
JOB_02:
name: Job 02
. . .
steps:
- name: Some steps of job 02
. . .
- name: Create file status_job02.txt and write the job status into it
if: always()
run: |
echo ${{ job.status }} > status_job02.txt
- name: Upload file status_job02.txt as an artifact
if: always()
uses: actions/upload-artifact@v1
with:
name: pass_status_job02
path: status_job02.txt
JOB_03:
needs: [JOB_01, JOB_02]
if: always()
name: Job 03
. . .
steps:
- name: Download artifact pass_status_job01
uses: actions/download-artifact@v1
with:
name: pass_status_job01
- name: Download artifact pass_status_job02
uses: actions/download-artifact@v1
with:
name: pass_status_job02
- name: Set the statuses of Job 01 and Job 02 as output parameters
id: set_outputs
run: |
echo "::set-output name=status_job01::$(<pass_status_job01/status_job01.txt)"
echo "::set-output name=status_job02::$(<pass_status_job02/status_job02.txt)"
- name: Show the values of the outputs
run: |
# using the syntax steps.<step_id>.outputs.<output_name> to access the output parameters
echo "status_job01 = ${{ steps.set_outputs.outputs.status_job01 }}"
echo "status_job02 = ${{ steps.set_outputs.outputs.status_job02 }}"
- name: Some other steps of job 03
. . .
In your case, you could eventually use those status job
outputs to execute or not a job according to their value in an if condition like your suggested in your question (it would probably be in a 4th job after setting them as job3 outputs).
It isn't a nice solution (as it's quite verbose), but it works.
Upvotes: 4