Search code examples
mavenjenkinsjenkins-declarative-pipeline

withMaven UNSTABLE build result is not preserved in Jenkins declarative pipeline


I want to set a build's result to UNSTABLE when a maven build step exits because of test failures. I'm using the withMaven build step which provides special treatment of maven test results: In case of failing tests, it sets the build result to UNSTABLE before failing the step.

This works perfectly when using a scripted pipeline. In case of a declarative pipeline, however, the build result is set to FAILURE.

This is illustrated by the following code samples.

Edit: Please note that the the try/catch and post blocks are not required for the example to work. They are only present so that the value of currentBuild.result can be examined right after the invocation of withMaven.

Declarative

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                withMaven() {
                    sh 'mvn clean verify' // -> Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
                }
            }

            post {
                always {
                    echo "CurrentResult: $currentBuild.currentResult" // -> FAILURE
                    echo "Result: $currentBuild.result"               // -> FAILURE
                                                                      // overall build result -> FAILURE
                }
            }
        }
    }
}

Scripted

node() {
    stage('Build') {
        try {
            withMaven() {
                sh 'mvn clean verify'  // -> Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
            }
        } catch (e) {
            echo "CurrentResult: $currentBuild.currentResult" // -> UNSTABLE
            echo "Result: $currentBuild.result"               // -> UNSTABLE
                                                              // overall build result -> UNSTABLE
        }
    }
}

How can i preserve the build result of UNSTABLE from a maven build step in a declarative pipeline?

Versions used: Jenkins 2.204.1, Pipeline Maven Integration Plugin 3.8.2, Maven 3.6.3 (installed on the build agent), AdoptOpenJDK 1.8.0_222.


Solution

  • As fredericrous pointed out, the difference is the caught exception. If the exception is not caught in the Jenkinsfile, then the result will be set to FAILED.

    I am not an expert, but i came up with a pure declarative approach which solve this problem in exchange of a more cluttered Jenkinsfile.

    pipeline {
        agent any
    
        stages {
            stage('Build') {
                steps {
                    catchError(buildResult: null, catchInterruptions: false) {
                        withMaven() {
                            sh 'mvn clean verify' // -> Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
                        }
                    }
                }
    
                post {
                    always {
                        echo "CurrentResult: $currentBuild.currentResult" // -> UNSTABLE
                        echo "Result: $currentBuild.result"               // -> UNSTABLE
                    }
                }
            }
    
            stage('Deploy') {
                when {
                    expression {
                        currentBuild.result == "SUCCESS"
                    }
                }
                steps {
                    echo 'Deploy'
                }
            }
        }
    }
    

    Explanation

    catchError(buildResult: null, catchInterruptions: false)

    buildResult: null which is equivalent to buildResult: 'SUCCESS', prevents catchError to set the buildResult to FAILURE, regardless of the value before.

    catchInterruptions: false tells catchError to not catch, respectively rethrow, certain types of exceptions that are used to interrupt the flow of execution for Pipelines.

    The "drawback" of catching the exception is that the current, and all following, stages are executed. To skip a stage in regard of the result, a when declarative can be added to the stages.

    This is how it looks from the stage view

    Stage View