【问题标题】:Abort current build from pipeline in Jenkins在 Jenkins 中从管道中止当前构建
【发布时间】:2017-07-28 19:12:48
【问题描述】:

我有一个包含多个阶段的 Jenkins 管道,例如:

node("nodename") {
  stage("Checkout") {
    git ....
  }
  stage("Check Preconditions") {
    ...
    if(!continueBuild) {
      // What do I put here? currentBuild.xxx ?
    }
  }
  stage("Do a lot of work") {
    ....
  }
}

如果不满足某些先决条件并且没有实际工作要做,我希望能够取消(不失败)构建。我怎样才能做到这一点?我知道currentBuild 变量可用,但我找不到它的文档。

【问题讨论】:

    标签: jenkins jenkins-pipeline


    【解决方案1】:

    您可以将构建标记为 ABORTED,然后使用error 步骤使构建停止:

    if (!continueBuild) {
        currentBuild.result = 'ABORTED'
        error('Stopping early…')
    }
    

    在阶段视图中,这将显示构建在此阶段停止,但整个构建将被标记为中止,而不是失败(请参阅构建 #9 的灰色图标):

    【讨论】:

    • 太棒了。有没有办法提前成功退出?
    • 抱歉,已经找到。只需返回 node-level 而不是 stage-level 即可使管道提前成功退出。
    • if (!continueBuild)...我们如何设置“ContinueBuild”值?
    • @NishantKansal 这只是原始发帖人提到的变量名。语法为def continueBuild = false(或true),但由您决定何时要中止构建,例如通过调用方法def continueBuild = makeSomeDecision()
    • 仅供参考,hudson/model/Result.java
    【解决方案2】:

    经过一些测试,我想出了以下解决方案:

    def autoCancelled = false
    
    try {
      stage('checkout') {
        ...
        if (your condition) {
          autoCancelled = true
          error('Aborting the build to prevent a loop.')
        }
      }
    } catch (e) {
      if (autoCancelled) {
        currentBuild.result = 'ABORTED'
        echo('Skipping mail notification')
        // return here instead of throwing error to keep the build "green"
        return
      }
      // normal error handling
      throw e
    }
    

    这将导致以下阶段视图:

    失败阶段

    如果你不喜欢失败的阶段,你必须使用返回。但请注意,您必须跳过每个阶段或包装器。

    def autoCancelled = false
    
    try {
      stage('checkout') {
        ...
        if (your condition) {
          autoCancelled = true
          return
        }
      }
      if (autoCancelled) {
        error('Aborting the build to prevent a loop.')
        // return would be also possible but you have to be sure to quit all stages and wrapper properly
        // return
      }
    } catch (e) {
      if (autoCancelled) {
        currentBuild.result = 'ABORTED'
        echo('Skipping mail notification')
        // return here instead of throwing error to keep the build "green"
        return
      }
      // normal error handling
      throw e
    }
    

    结果:

    自定义错误作为指标

    您也可以使用自定义消息代替局部变量:

    final autoCancelledError = 'autoCancelled'
    
    try {
      stage('checkout') {
        ...
        if (your condition) {
          echo('Aborting the build to prevent a loop.')
          error(autoCancelledError)
        }
      }
    } catch (e) {
      if (e.message == autoCancelledError) {
        currentBuild.result = 'ABORTED'
        echo('Skipping mail notification')
        // return here instead of throwing error to keep the build "green"
        return
      }
      // normal error handling
      throw e
    }
    

    【讨论】:

    • 我需要更清楚一点:如果(您的条件)...我有一个与先前和当前提交 id 匹配的 shell 脚本来决定构建是应该继续还是停止。是不是我必须将该 shell 脚本的退出状态传递给 if(您的条件)?如果是,那么如何?请帮忙。
    【解决方案3】:

    按照来自 Jenkins 的 documentation,您应该能够生成错误以停止构建并像这样设置构建结果:

    currentBuild.result = 'ABORTED'

    希望对您有所帮助。

    【讨论】:

    • 我刚试过这个,之后有一个回声,它并没有阻止管道的其余部分运行。
    • 该命令只设置构建结果。要停止管道,您必须生成信号错误:error('error message')throw new Exception()
    • 仅当您想查看堆栈跟踪时才使用throw new Exception()
    【解决方案4】:

    我以声明方式处理如下:

    基于 catchError 块,它将执行 post 块。 如果发布结果属于失败类别,则会执行错误块以停止即将到来的阶段,如生产、PreProd 等。

    pipeline {
    
      agent any
    
      stages {
        stage('Build') {
          steps {
            catchError {
              sh '/bin/bash path/To/Filename.sh'
            }
          }
          post {
            success {
              echo 'Build stage successful'
            }
            failure {
              echo 'Compile stage failed'
              error('Build is aborted due to failure of build stage')
    
            }
          }
        }
        stage('Production') {
          steps {
            sh '/bin/bash path/To/Filename.sh'
          }
        }
      }
    }
    

    【讨论】:

    • 我不知道您的设置,但是授予 sudo bash 任何权限都不是很安全。更好的是,只对您需要的脚本授予 sudo 权限,并在之前仔细检查它。
    【解决方案5】:

    受到所有答案的启发,我将所有内容整合到一个脚本化管道中。请记住,这不是声明式管道。

    要让这个例子正常工作,你需要:

    我的想法是如果管道是“重播”而不是由“运行按钮”启动(在 Jenskins BlueOcean 的分支选项卡中),则中止管道:

    def isBuildAReplay() {
      // https://stackoverflow.com/questions/51555910/how-to-know-inside-jenkinsfile-script-that-current-build-is-an-replay/52302879#52302879
      def replyClassName = "org.jenkinsci.plugins.workflow.cps.replay.ReplayCause"
      currentBuild.rawBuild.getCauses().any{ cause -> cause.toString().contains(replyClassName) }
    }
    
    node { 
            try {
                    stage('check replay') {
                        if (isBuildAReplay()) {
                            currentBuild.result = 'ABORTED'
                            error 'Biuld REPLAYED going to EXIT (please use RUN button)'
                        } else {
                            echo 'NOT replay'
                        }
                    }
                    stage('simple stage') {
                        echo 'hello from simple stage'
                    }
                    stage('error stage') {
                        //error 'hello from simple error'
                    }
                    stage('unstable stage') {
                        unstable 'hello from simple unstable'
                    }
                    stage('Notify sucess') {
                        //Handle SUCCESS|UNSTABLE
                        discordSend(description: "${currentBuild.currentResult}: Job ${env.JOB_NAME} \nBuild: ${env.BUILD_NUMBER} \nMore info at: \n${env.BUILD_URL}", footer: 'No-Code', unstable: true, link: env.BUILD_URL, result: "${currentBuild.currentResult}", title: "${JOB_NAME} << CLICK", webhookURL: 'https://discordapp.com/api/webhooks/')
    
                    }
    
            } catch (e) {
                    echo 'This will run only if failed'
    
                    if(currentBuild.result == 'ABORTED'){
                        //Handle ABORTED
                        discordSend(description: "${currentBuild.currentResult}: Job ${env.JOB_NAME} \nBuild: ${env.BUILD_NUMBER} \nMore info at: \n${env.BUILD_URL}\n\nERROR.toString():\n"+e.toString()+"\nERROR.printStackTrace():\n"+e.printStackTrace()+" ", footer: 'No-Code', unstable: true, link: env.BUILD_URL, result: "ABORTED", title: "${JOB_NAME} << CLICK", webhookURL: 'https://discordapp.com/api/webhooks/')
                        throw e
                    }else{
                        //Handle FAILURE
                        discordSend(description: "${currentBuild.currentResult}: Job ${env.JOB_NAME} \nBuild: ${env.BUILD_NUMBER} \nMore info at: \n${env.BUILD_URL}\n\nERROR.toString():\n"+e.toString()+"\nERROR.printStackTrace():\n"+e.printStackTrace()+" ", footer: 'No-Code', link: env.BUILD_URL, result: "FAILURE", title: "${JOB_NAME} << CLICK", webhookURL: 'https://discordapp.com/api/webhooks/')
                        throw e
                    }
            } finally {
                    echo 'I will always say Hello again!'
    
            }
    }
    

    主要技巧是达到中止状态的行顺序:

    currentBuild.result = 'ABORTED'
    error 'Biuld REPLAYED going to EXIT (please use RUN button)'
    

    先设置状态,然后抛出异常。

    在 catch 块中都可以工作:

    currentBuild.result
    currentBuild.currentResult
    

    【讨论】:

      【解决方案6】:

      我们使用的是:

      try {
       input 'Do you want to abort?'
      } catch (Exception err) {
       currentBuild.result = 'ABORTED';
       return;
      }
      

      最后的“return”确保不再执行任何代码。

      【讨论】:

        【解决方案7】:

        您可以转到 Jenkins 的脚本控制台并运行以下命令来中止挂起/任何 Jenkins 作业的构建/运行:

        Jenkins .instance.getItemByFullName("JobName")
                .getBuildByNumber(JobNumber)
                .finish(hudson.model.Result.ABORTED, new java.io.IOException("Aborting build"));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-07-18
          • 2020-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多