如何使用Jenkins Pipeline插件实现后构建阶段?

60
阅读了 Jenkins tutorial 解释 Pipeline 插件后,似乎该插件应该能够实现构建后步骤。然而,文档在具体说明方面相当有限。
例如,我想知道如何实现:
  • 只在构建成功时运行
  • 仅在构建成功或不稳定时运行
  • 无论构建结果如何都要运行
  • Run only if build succeeds

    stage 'build'
    ... build
    ... tests
    stage 'post-build'
    ...
    

    (Or add -Dmaven.test.failure.ignore=false to the MAVEN_OPTS)

  • Run only if build succeeds or is unstable

    stage 'build'
    ... build
    try {
        ... tests
    } catch {
        ...
    }
    stage 'post-build'
    ...
    

    (Or add -Dmaven.test.failure.ignore=true to the MAVEN_OPTS)

  • Run regardless of build result - could it be done using try / catch / finally ?

    try {
        stage 'build'
        ...
    } catch {
        ...
    } finally {
        stage 'post-build'
        ...
    }
    
我注意到最终构建状态被设置为“成功”(SUCCESS),即使一些阶段失败了,比如“build”,因为它是基于最后一个阶段设置的。这是否意味着需要明确设置最终构建状态,例如:currentBuild.result = 'UNSTABLE'

4个回答

56

最佳方式是在管道脚本中使用后置构建操作。

处理失败
声明式管道默认通过其后置section支持强大的故障处理, 允许声明多个不同的“后置条件”,例如:总是执行、不稳定、成功、失败和变更。 《Pipeline Syntax》部分提供了有关如何使用各种后置条件的更多详细信息。

Jenkinsfile(声明式管道)

pipeline {
    agent any
    stages {
        stage('Test') {
            steps {
                sh 'make check'
            }
        }
    }
    post {
        always {
            junit '**/target/*.xml'
        }
        failure {
            mail to: team@example.com, subject: 'The Pipeline failed :('
        }
    }
}

以下是文档说明 https://jenkins.io/doc/book/pipeline/syntax/#post


7
在流水线项目中运行时,这对我没有用。 - Subrat Sahoo
@Mohamed,正如Subrat所说,这在Jenkins文件之外是不起作用的。还有其他方法可以做到吗? - Jason
1
可能是由于Jenkins版本或插件版本的原因,但我不确定。另一种方法是将更改放在try catch和finally块中。 - Mohamed Thoufeeque
@MohamedThoufeeque,你知道能否将posy步骤设置为有条件的吗?我只想在某些分支构建失败时发送电子邮件。 - thecoshman
这对我来说完美运作,我们也可以在post中使用“success”。 - valdeci
显示剩余2条评论

7

如果您正在使用脚本管道而非声明式管道,则应按照其他答案中建议的使用try/catch/finally块。在finally块中,如果您想模仿声明式管道的行为,可以直接将以下内容放入块中,或将其作为函数并从finally块中调用该函数:

def currResult = currentBuild.result ?: 'SUCCESS'
def prevResult = currentBuild.previousBuild?.result ?: 'NOT_BUILT'

// Identify current result
boolean isAborted = (currResult == 'ABORTED')
boolean isFailure = (currResult == 'FAILURE')
boolean isSuccess = (currResult == 'SUCCESS')
boolean isUnstable = (currResult == 'UNSTABLE')

boolean isChanged = (currResult != prevResult)
boolean isFixed = isChanged && isSuccess && (prevResult != 'ABORTED') && (prevResult != 'NOT_BUILT')
boolean isRegression = isChanged && currentBuild.resultIsWorseOrEqualTo(prevResult)

onAlways()
if (isChanged) {
    onChanged()
    if (isFixed) {
        onFixed()
    } else if (isRegression) {
        onRegression()
    }
}
if (isSuccess) {
    onSuccess()
} else {
    if (isAborted) {
        onAborted()
    }
    onUnsuccessful()
    if (isFailure) {
        onFailure()
    }
    if (isUnstable) {
        onUnstable()
    }
}
onCleanup()


各种 onXYZ() 调用是函数,您需要定义这些函数来处理特定条件,而不是使用声明式 post 块的更好语法。

1
我刚试了一下,发现有些阶段错误(故意添加的错误以测试后构建步骤)无法检测到... 当任务明显失败时(Jenkins在控制台中写道“已完成:FAILURE”),currResult == SUCCESS。在我的finally块中,currentBuild.result和currentBuild.currentResult都是SUCCESS。有什么想法吗? - MoOx
@MoOx 抱歉我现在才看到这个问题...自从我上次查看以来已经过了很长时间,也许当前构建结果的处理方式内部发生了一些变化。需要进行测试,但是您可能需要在第一行中使用 def currResult = currentBuild.currentResult ?: 'SUCCESS'。我忘记了 Jenkins 设置哪个,Groovy 代码设置哪个,但如果我的记忆没有出错,currentResult 可能是此处所需的内容。如果未设置,则可以假定为 SUCCESS。如果有失败,则已将其设置为 UNSTABLEFAILURE - Will
@MoOx,我需要具体了解你的代码编写方式,try/catch/finally语句块的位置以及错误条件的发生情况。根据我的经验,调试管道并不是一件有趣的事情,但也不是不可能的。只需要能够全面地看待代码,并能在我的Jenkins实例上运行它。 - Will

5
如果您正在使用try/catch,并且希望将构建标记为不稳定或失败,则必须使用currentBuild.result = 'UNSTABLE'等语句。我认为,某些插件(如JUnit报告插件)会在junit结果中发现失败的测试时为您设置此选项。但在大多数情况下,如果您捕获错误,则必须自己设置它。
第二个选择是重新抛出错误,如果您不想继续执行。
stage 'build'
... build
try {
    ... tests
} catch(err) {
    //do something then re-throw error if needed.
    throw(err)
}
stage 'post-build'
...

3

try-catch块可以像真正的应用程序代码一样设置以处理错误。

例如:

try {
    node {
        sh 'sleep 20' // <<- can abort here
    }
} catch (Exception e) {
    println 'catch'
} finally {
    println 'finally'
}

node {
    println 'second'
}

try {
    node {
        sh 'sleep 20' // <<- can abort here again
    }
} catch (Exception e) {
    println 'catch'
} finally {
    println 'finally'
}

这里有一个包含两个异常终止的输出示例。

Started by user me
Replayed #3
[Pipeline] node
Running on my-node in /var/lib/jenkins-slave/workspace/my-job
[Pipeline] {
[Pipeline] sh
[my-job] Running shell script
+ sleep 20

Aborted by me

Sending interrupt signal to process

/var/lib/jenkins-slave/workspace/my-job@tmp/durable-9e1a15e6/script.sh: line 2: 10411 Terminated              sleep 20
[Pipeline] }
[Pipeline] // node
[Pipeline] echo
catch
[Pipeline] echo
finally
[Pipeline] node
Running on my-node in /var/lib/jenkins-slave/workspace/my-job
[Pipeline] {
[Pipeline] echo
second
[Pipeline] }
[Pipeline] // node
[Pipeline] node
Running on my-node in /var/lib/jenkins-slave/workspace/my-job
[Pipeline] {
[Pipeline] sh
[my-job] Running shell script
+ sleep 20

Aborted by me

Sending interrupt signal to process
/var/lib/jenkins-slave/workspace/my-job@tmp/durable-d711100c/script.sh: line 2: 10416 Terminated              sleep 20
[Pipeline] }
[Pipeline] // node
[Pipeline] echo
catch
[Pipeline] echo
finally
[Pipeline] End of Pipeline
Finished: ABORTED

当然,这适用于执行期间发生的任何异常。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接