Reputation: 13345
I'm trying to follow an example Github has for testing my build with github actions, and then compressing the test results and uploading them as an artifact. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/persisting-workflow-data-using-artifacts#uploading-build-and-test-artifacts
I'm having trouble with what to do when my tests fail though. This is my action. When my tests pass everything works great, my results are zipped an exported as an artifact, but if my tests fail, it stops the rest of the steps in the job, so my results never get published.
I tried adding the continue-on-error: true https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepscontinue-on-error
This makes it continue after it fails and uploads my test results. but then the job is marked as passed, even though my test step failed. Is there some way to have it upload my artifact even if a step fails, while still marking the overall job as failed?
name: CI
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Test App
run: ./gradlew test
- name: Archive Rest Results
uses: actions/upload-artifact@v1
with:
name: test-results
path: app/build/reports/tests
Upvotes: 386
Views: 275405
Reputation: 2128
Other way, you can add continue-on-error: true
.
Look like
- name: Job fail
continue-on-error: true
run: |
exit 1
- name: Next job
run: |
echo Hello
Read more in here.
Note: exit 1
statement used within run
marks the job as failed while continue-on-error
is used so the next tasks are still executed. Together the two would result in a failed job while also executing the following tasks.
Upvotes: 101
Reputation: 8519
The .status property does not work for me, I now use the new API to access the outcome of a step. The new approach allows you to handle step failures more effectively.
To achieve this, you can use the if
conditional statement along with the failure()
expression. Here's an example of how you can run a subsequent step even if the previous step fails:
jobs:
my-job:
runs-on: ubuntu-latest
steps:
- name: Step 1
id: demo
run: echo "This step will fail" && exit 1
- name: Step 2
if: ${{ failure() && steps.demo.conclusion == 'failure' }}
run: echo "This step will run even if the previous step fails"
In the above example, Step 2 will execute regardless of the success or failure of Step 1. The if: ${{ failure() }}
condition checks if the previous step failed and allows Step 2 to proceed.
You can refer to the GitHub Actions documentation for more details on using conditions to handle step failures.
Upvotes: 5
Reputation: 13345
You can add
if: always()
to your step to have it run even if a previous step fails https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions
so for a single step it would look like this:
steps:
- name: Build App
run: ./build.sh
- name: Archive Test Results
if: always()
uses: actions/upload-artifact@v1
with:
name: test-results
path: app/build
Or you can add it to a job:
jobs:
job1:
job2:
needs: job1
job3:
if: always()
needs: [job1, job2]
Additionally, as pointed out below, putting always()
will cause the function to run even if the build is canceled. If you don't want the function to run when you manually cancel a job, you can instead put:
if: success() || failure()
or
if: '!cancelled()'
(Quotes are needed so that !cancelled()
is not interpreted as a YAML tag.)
Likewise, if you want to run a function ONLY when something has failed, you can put:
if: failure()
Also, as mentioned in the comments, if a status check function is not used in if
, like
if: true
the result will (perhaps confusingly) behave like
if: success() && true
This is documented in Expressions - GitHub Docs:
Status check functions
You can use the following status check functions as expressions in if conditionals. A default status check of
success()
is applied unless you include one of these functions.
Upvotes: 539
Reputation: 28751
Instead of
if: success() || failure()
I suggest to use
if: ${{ ! cancelled() }}
to run a step "always, except when the CI run was cancelled". My version is more concise and in my view less awkward.
Reference: https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions
Upvotes: 8
Reputation: 2850
In case anyone is wondering, you can combine always()
with another condition to perform the step if that condition holds true even if there is a failure before that step is processed.
steps:
- name: Exit with error
run: |
echo "Erroring"
exit 1
- name: Output report 1
if: true
run: |
echo "Report 1"
- name: Output report 2
if: always() && true
run: |
echo "Report 2"
Upvotes: 4
Reputation: 7174
The other answers here are great and work, but you might want a little more granularity.
For instance, ./upload
only if ./test
ran, even if it failed.
However, if something else failed and prevented the tests from running, don't upload.
# ... Other steps
- run: ./test
id: test
- run: ./upload
if: success() || steps.test.conclusion == 'failure'
steps.*.conclusion
will be success
, failure
, cancelled
, or skipped
.
success
or failure
indicate the step ran. cancelled
or skipped
means it didn't.
Note there is an important caveat that you must test at least one success()
or failure()
in if
.
if: steps.test.conclusion == 'success' || steps.test.conclusion == 'failure'
won't work as expected.
Upvotes: 29
Reputation: 7714
run a github-actions step, even if the previous step fails
If you only need to execute the step if it succeeds or fails, then:
steps:
- name: Build App
run: ./build.sh
- name: Archive Test Results
if: success() || failure()
uses: actions/upload-artifact@v1
with:
name: test-results
path: app/build
Why use success() || failure()
instead of always()
?
Reading the Status check functions documentation on Github:
always
Causes the step to always execute, and returns true, even when canceled. A job or step will not run when a critical failure prevents the task from running. For example, if getting sources failed.
Which means the job will run even when it gets cancelled, if that's what you want, then go ahead. Otherwise, success() || failure()
would be more suitable.
Note - The documentation made clear thanks to Vladimir Panteleev in which he submitted the following PR: Github Docs PR #8411
Upvotes: 34
Reputation: 67
you can add || true to your command. example:
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Test App
run: ./gradlew test || true
Upvotes: -2
Reputation: 456
Addon: if you have following sitution. 2 steps i.e. build > deploy
and in some cases i.e. workflow_dispatch
with input parameters you might want to skip build
and proceed with deploy
. At the same time you might want deploy
to be skipped, when build
failed.
Logically that would be something like skipped or not failed
as deploy
conditional.
if: always()
will not work, cause it will always trigger deploy
, even if build
failed.
Solution is pretty simple:
if: ${{ !failure() }}
Mind that you cannot skip brackets when negating in if:
, cause it reports syntax error.
Upvotes: 13