从 Jenkins 中的管道中止当前构建

Abort current build from pipeline in Jenkins

我有一个 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 的 documentation,您应该能够生成错误以停止构建并设置构建结果,如下所示:

currentBuild.result = 'ABORTED'

希望对您有所帮助。

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

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

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

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

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
}

这将导致以下阶段视图:

阶段失败

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

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
}

我们用的东西是:

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

末尾的 "return" 确保不再执行其他代码。

我用如下所示的声明方式处理:

基于 catchError 块,它将执行 post 块。 如果 post 结果属于失败类别,将执行错误块以停止后续阶段,如 Production、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'
      }
    }
  }
}

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

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

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

要使此示例正常运行,您需要:

我的想法是,如果管道是 "replayed" vs 由 "run button" 启动(在 Jenskins BlueOcean 的分支选项卡中):

def isBuildAReplay() {
  // 
  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