Jenkins 管道:运行 阶段中的所有步骤,即使第一个失败

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

我在某个阶段有一系列步骤想 运行 即使第一个步骤失败了。我希望阶段结果失败并中止构建,但只有 之后所有步骤都有 运行。例如,

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
            }
        }
    }
}

结果应该是构建失败,其中“运行 测试”阶段失败而“部署”阶段没有 运行。这可能吗?

P.S.

要求与Continue Jenkins pipeline past failed stage中相同的行为。我想 运行 失败后的步骤,但不是之后的任何阶段。我试图用 catchError (buildResult: 'FAILURE', stageResult: 'FAILURE') 包含每个测试步骤,但“部署”阶段仍然 运行s.

编辑:

我无法将所有步骤组合成一个大 sh 步骤并捕获其 return 代码,因为有些步骤不是 shell 命令,而是 jenkins 步骤,例如 junitpublishCoverage.

理论上你应该可以使用 sh "<command>||true" 它会忽略命令上的错误并继续。但是,Jenkins 不会失败,因为它会忽略错误。

如果您不希望 Jenkins 忽略错误并希望它在阶段结束时停止,您可以执行以下操作:sh "<command>||$error=true" 然后根据 [=12= 使构建失败] 多变的。 (sh "$error" 可能就足够了,但我不确定,最后可能需要一个 if 语句。)它只会设置为 true iff command 失败。

具有非零退出代码的脚本将始终导致 jenkins 步骤失败。您可以将 returnStatus 用作 true,这样 jenkins 就不会失败。
另外考虑您的用例,您可以使用 post always 执行,以便始终执行这些步骤。

请参阅下面的参考示例:

stage('Run Test') {
            steps {
                def unit_test_result= sh returnStatus: true, script: 'echo "running unit-tests"'
                def lint_result= sh returnStatus: true, script: 'echo "running linting"'       
                if (unit_test_result!=0 || lint_result!=0 ) {
                   // If the unit_test_result or lint_result status is not 0 then mark this stage as unstable to continue ahead 
                   // and all later stages will be executed 
                   unstable ('Testing failed')
                   // You can also mark as failed as below and it will not conintue other stages:
                   // error ('Testing failed')
                   }
                
            }
           post {
                always {
                   // This block would always be executed inspite of failure
                    sh "echo generating report"
                publishCoverage adapters: [coberturaAdapter("coverage.xml")]
                junit 'unit-test.xml' 
                       }
                }
        }

另一种选择是将构建步骤包装在 try-catch 块中!如果有异常,即 return 构建代码不是 0,您可以捕获它,将构建标记为不稳定,然后管道的其余部分继续。

这是一个例子` 管道 {

agent {
    node {
        label 'linux'
    }
}

options {
    timestamps()
    disableConcurrentBuilds()
    buildDiscarder(logRotator(numToKeepStr: '3'))
}

tools {
    maven 'Maven 3.6.3'
    jdk 'jdk11'
}

stages {

    stage('CleanWS') {
        steps {
            cleanWs()
        }
    }

  

    stage('Build') {
        steps {
            withMaven(options: [artifactsPublisher(disabled: true)]) {
                sh "export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn -f pom.xml clean install -DskipTests -Pregression-test  -Dmaven.javadoc.skip=true"
            }
        }
    }

    stage('Test') {
        steps {
            script {
                try {
                    withMaven(options: [artifactsPublisher(disabled: true)]) {
                        sh "export MAVEN_OPTS=\"-Xmx2048m\" && export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn -B verify   -Dmaven.source.skip=true -Dmaven.javadoc.skip=true"
                    }

                } catch (exc) {
                    currentBuild.result = 'UNSTABLE'
                }
            }
        }
        post {
            always {
                script {
                    junit "**/surefire-reports/*.xml"
                }
            }
        }
    }

    stage('Sonar Analyse') {
        steps {
            script {
                withMaven(options: [artifactsPublisher(disabled: true)]) {
                    withSonarQubeEnv("SonarQube") {
                        sh "export MAVEN_OPTS=\"-Xmx2048m\" && export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn sonar:sonar"
                    }
                }
            }
        }
    }

    stage('Deploy to Nexus') {
        steps {
            sh "export NLS_LANG=GERMAN_GERMANY.WE8ISO8859P1 && mvn -f pom.xml -B clean deploy -DdeployAtEnd=true -DskipTests"
        }
    }

}

post {
    failure {
        script {
            emailext(
                    body: "Please go to ${env.BUILD_URL}/console for more details.",
                    to: emailextrecipients([developers(), requestor()]),
                    subject: "Nightly-Build-Pipeline Status is ${currentBuild.result}. ${env.BUILD_URL}"
            )
        }
    }
    unstable {
        script {
            emailext(
                    body: "Please go to ${env.BUILD_URL}/console for more details.",
                    to: emailextrecipients([developers(), requestor()]),
                    subject: "Nightly-Build-Pipeline Build Status is ${currentBuild.result}. ${env.BUILD_URL}"
            )
        }
    }
}

}`

我发现了一种获得我想要的行为的稍微有点老套的方法。其他答案对我不起作用,因为它们需要所有步骤都是 sh 个步骤,或者它们不会停止 运行 的 deploy 阶段。我使用 catchError 来设置构建和阶段结果。但是为了防止下一阶段 运行,我需要在阶段失败时显式调用 error

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
            }
        }
    }
}