Search code examples
jenkinsjenkins-pipeline

Jenkins pipeline: Run all steps in stage, even if the first one fails


I have a series of steps in a stage that I want to run even if the first one fails. I want the stage result to fail and the build to get aborted, but only after all steps have run. For example,

pipeline {
    agent any
    stages {
        stage('Run Test') {
            steps {
                sh "echo running unit-tests"
                sh "echo running linting && false"  // failure
                sh "echo generating report"  // This should still run (It currently doesn't)
                publishCoverage adapters: [coberturaAdapter("coverage.xml")]  // This should still run (It currently doesn't)
                junit 'unit-test.xml'  // This should still run (It currently doesn't)
            }
        }
        stage('Deploy') {
            steps {
                echo "deploying"  // This should NOT run
            }
        }
    }
}

The result should be a failed build where the "Run Test" stage failed and the "Deploy" stage did not run. Is this possible?

P.S.

I am NOT asking for the same behavior as in Continue Jenkins pipeline past failed stage. I want to run the steps following the failure, but not any of the stages afterwards. I tried to enclose each of the test steps with catchError (buildResult: 'FAILURE', stageResult: 'FAILURE'), but the "Deploy" stage still runs.

EDIT:

I cannot combine all the steps into one big sh step and capture its return code because some of the steps are not shell commands, but instead jenkins steps like junit and publishCoverage.


Solution

  • I found a slightly hacky way to get the behavior I want. The other answers didn't work for me, either because they need all the steps to be sh steps, or they don't stop the deploy stage from running. I used catchError to set the build and stage result. But to prevent the next stage from running, I needed to an explicit call to error if the stage failed.

    pipeline {
        agent any
        stages {
            stage('Run Test') {
                steps {
                    script {
                        // catchError sets the stageResult to FAILED, but does not stop next stages from running
                        catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') {
                            sh "echo running unit-tests"
                        }
                        catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') {
                            sh "echo running linting && false"  // failure
                        }
                        catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') {
                            sh "echo generating report"  // This still runs
                        }
                        publishCoverage adapters: [coberturaAdapter("coverage.xml")]  // This still runs
                        junit 'unit-test.xml'  // This still runs
    
                        if (currentBuild.result == "FAILURE") {  // This is needed to stop the next stage from running
                            error("Stage Failed")
                        }
                    }
                }
            }
            stage('Deploy') {
                steps {
                    echo "deploying"  // This should NOT run
                }
            }
        }
    }