25

我想在 Jenkins 声明性管道语法中定义多个阶段,这些阶段可以继续通过其中任何一个失败。我找不到任何真正重复的现有问题,因为它们都假定或允许脚本语法。

pipeline {
    agent any
    stages {
        stage('stage 1') {
            steps {
                echo "I need to run every time"
            }
        }
        stage('stage 2') {
            steps {
                echo "I need to run every time, even if stage 1 fails"
            }
        }
        stage('stage 3') {
            steps {
                echo "Bonus points if the solution is robust enough to allow me to continue *or* be halted based on previous stage status"
            }
        }
    }
}

澄清一下,我不是在寻找如何在脚本语法中完成此操作。我试图了解这种流控制是否真的在声明性语法中得到支持和形式化。为此,我将尝试准确定义我正在寻找的内容:

必需的

  • 没有尝试/捕捉。我不想进入脚本模式,或者在另一个共享库或脚本块中“包装”我的声明性管道。
  • 没有post step恶作剧。我想要真正的多个阶段,而不是一个阶段post always包含我所有其他逻辑的步骤

可选的

  • 失败阶段应被认定为失败;我不希望失败的阶段显示为绿色,因为它被“跳过”或“继续”。
  • 任何阶段失败的构建都应标记为红色(或黄色,或任何非绿色)。

相关但不充分

4

4 回答 4

20

现在这是可能的:

pipeline {
    agent any
    stages {
        stage('1') {
            steps {
                sh 'exit 0'
            }
        }
        stage('2') {
            steps {
                catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') {
                    sh "exit 1"
                }
            }
        }
        stage('3') {
            steps {
                sh 'exit 0'
            }
        }
    }
}

在上面的示例中,所有阶段都将执行,管道将成功,但阶段 2 将显示为失败:

管道示例

正如您可能已经猜到的那样,您可以自由选择buildResultand stageResult,以防您希望它不稳定或其他任何东西。您甚至可以使构建失败并继续执行管道。

只需确保您的 Jenkins 是最新的,因为这是一个相当新的功能。

编辑:这是最初编写此答案的问题。这也是其他几个问题的正确答案,这也是我在此处发布此答案的原因。这是多个类似问题的正确解决方案。我已经针对他们的具体问题调整了我的其他答案,以明确这一点。我只是复制答案以节省一些时间。这并不意味着它不是一个好的正确答案。

于 2019-07-10T18:47:03.080 回答
3

我可能遗漏了一些东西,但声明式、固执己见的管道的想法是提供对大多数简单用例的覆盖。当您需要一些固执己见的东西时,您必须求助于脚本化管道,这仅指“声明性管道”的“要求”:现在不会发生。

至于您的其他“要求”,它们几乎没有意义,因为整个想法是将低级丑陋包装到共享库中,为用户提供以下构造:

    mylib.failable_stages({
      stages {
        stage('stage 1') {
          steps {
            echo "I need to run every time"
          }
        }
        stage('stage 2') {
          steps {
            echo "I need to run every time, even if stage 1 fails"
          }
        }
        stage('stage 3') {
          steps {
            echo "Bonus points if the solution is robust enough to allow me to continue *or* be halted based on previous stage status"
          }
        }
      }
    })

自然地,您必须找到或实现这样mylib的类,并且failable_stages会得到一个闭包,并将其包装在各种管道/样板代码片段中。

希望这会有所帮助。

于 2017-07-11T11:10:54.633 回答
2

我认为这取决于工作之间的依赖程度。源自您的示例,我假设

  • 阶段 1独立于所有其他阶段,因为它是第一个
  • 第 2 阶段独立于所有其他阶段,因为第 1 阶段可能会立即失败,而第 2 阶段仍然需要运行
  • 第 3 阶段取决于第1阶段和第 2阶段的结果

所以相应的管道可能是

pipeline {
    stages {
        stage('Independent tasks') {
            parallel {
                stage('stage 1') {
                    steps {
                        sh 'exit 1' // failure
                    }
                }
                stage('stage 2') {
                    steps {
                        echo 'Happens even so stage 1 fails'
                        sh 'exit 0' // success
                    }
                }
            }
            post {  // 'stage 3'
                failure {
                    echo "... at least one failed"
                }
                success {
                    echo "Success!"
                }
            }
        }
        stage ('stage 4') {
            steps {
                echo 'Happens only if all previous succeed'
            }
        }
    }
}

第 1 阶段第 2 阶段将始终运行,第 3 阶段对它们的组合成功/失败做出反应。


额外的想法:这个概念只适用于管道的“末端”。如果您在中间某个地方需要它并且必须继续构建,您可以将它移到自己的工作中并使用该build job插件。

pipeline {
    stages {
    stage('Start own job for stage 1, 2, 3') {
        steps {
            build job: 'stageOneTwoThree', propagate: false, wait: true
        }
    }
    stage ('stage 4') {
        steps {
            echo 'Happens always, because "propagate: false"'
        }
    }
}
于 2019-03-09T15:53:58.030 回答
2

我使用post实现了它。我的要求是无论构建状态如何都发送松弛通知。

@Library('instanceGroups')
import x.z.y.jenkins.libraries.SlackNotifier

def slackHelper = new x.z.y.jenkins.libraries.SlackNotifier(env)
final String projectName = "pomeranian"
final String featureBranchPattern = "f_"

pipeline {
    agent any
    options { disableConcurrentBuilds() }

    stages {
        stage('clean') {
            steps {
                script {
                    try {
                        echo 'Current Branch...' + env.BRANCH_NAME
                        sh 'rm -rf /var/lib/jenkins/.gradle/caches'
                        sh './gradlew clean'
                    } catch (e) {
                        currentBuild.result = 'FAILURE'
                        slackHelper.buildGenericJobFailureNotificationMessage()
                        throw e
                    }
                }
            }
        }

        stage('compile') {
            steps {
                script {
                    try {
                        sh "./gradlew compileJava"
                    } catch (e) {
                        currentBuild.result = 'FAILURE'
                        slackHelper.getCompilationFailureSlackNotificationMessage()
                        throw e
                    }
                }
            }
        }

        stage('test') {
            steps {
                script {
                    try {
                        sh "./gradlew test"
                    } finally {
                        junit 'build/test-results/test/*.xml'

                        slackHelper.getTestStatuses(currentBuild)
                        slackHelper.buildUnitTestSlackNotificationMessage()
                    }
                }
            }
        }

        stage('publish 2 nexus') {
            steps {
                script {
                  // some code
                }
            }
        }

        stage('git tagging') {
            steps {
                script {
                    // some more code...
            }
        }
    }


    post {
        always {
            script {
                slackHelper.finalBuildStatusMessage(currentBuild)
                slackSend(channel: '#ci-cd', attachments: slackHelper.getFinalSlackMessage())
            }
        }
    }
}
于 2019-10-24T04:26:40.467 回答