在 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变量是可用的,但是我找不到它的文档。

137966 次浏览

按照 Jenkins 的 文件,您应该能够生成一个错误来停止构建,并像下面这样设置构建结果:

currentBuild.result = 'ABORTED'

希望能帮上忙。

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

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

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

Pipeline Stage View

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

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
}

这将导致以下阶段的观点:

enter image description here

失败的舞台

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

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
}

结果是:

enter image description here

自定义错误作为指示器

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

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 块。 如果后期结果属于失败类别,错误块将被执行,以停止即将到来的阶段,如生产,预产品等。

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 的脚本控制台并运行以下命令来中止一个 hang/any Jenkins 作业构建/运行:

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

受到所有答案的启发,我已经把所有的东西放在一起成为一个脚本管道。请记住,这不是声明性管道。

为了让这个例子起作用,你需要:

我的想法是,如果管道被“重播”,而不是通过“运行按钮”(在 Jenkins 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

如果您能够批准 FlowInterruptedException 的构造函数,那么您可以执行以下操作:

throw new FlowInterruptedException(Result.ABORTED, new UserInterruption(getCurrentUserId()))

你可以在你的共享库中添加一个文件 var/abortError.groovy:

import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException
import jenkins.model.CauseOfInterruption.UserInterruption


def call(message)
{
currentBuild.displayName = "#${env.BUILD_NUMBER} $message"
echo message
currentBuild.result = 'ABORTED'
throw new FlowInterruptedException(Result.ABORTED, new UserInterruption(env.BUILD_USER_ID))
}

然后你可以这样使用它(在导入库之后) :

abortError("some message")

注意,如果在控制台日志中出现以下错误:

org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new org.jenkinsci.plugins.workflow.steps.FlowInterruptedException hudson.model.Result jenkins.model.CauseOfInterruption[]

您需要遵循链接表单日志并批准安全异常。

这是在 Jenkins UI 中中止当前正在运行的构建管道的方法(在 Build History 中有一个取消按钮) ,用于捕获:

enter image description here