我希望为我的Jenkinsfile添加一个条件阶段,该阶段根据构建的触发方式运行。目前我们的设置是由以下内容触发构建:
有没有办法运行不同的管道步骤,具体取决于哪些操作触发了构建?
答案 0 :(得分:10)
以下代码应该用于确定用户是否已启动管道或计时器/其他触发器:
def isStartedByUser = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause) != null
答案 1 :(得分:3)
@vitalii-blagodir:
您的答案适用于检测由用户和计时器触发的构建,但不适用于提交。
相反,我发现这适用于我的情况:
def isTriggeredByIndexing = currentBuild.getBuildCauses('jenkins.branch.BranchIndexingCause').size()
def isTriggeredByCommit = currentBuild.getBuildCauses('com.cloudbees.jenkins.GitHubPushCause').size()
def isTriggeredByUser = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause').size()
def isTriggeredByTimer = currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause').size()
.size() 后缀在对象丢失时返回 0,如果对象存在则返回 1。这使得结果可用作布尔值。
为了找到要使用的对象名称,我发现在日志中显示它很方便:
echo "# Build causes"
def buildCauses = currentBuild.buildCauses
def numCause = 0
for (cause in buildCauses) {
echo "${numCause++}: ${cause.shortDescription}" // Display a human-readable index and description
echo "${cause}" // Display the object class name. This allows knowing what names to use in getBuildCauses(name) calls below.
}
最后,如果目标是在特定情况下中止管道构建,那么测试必须在管道开始之前完成。
例如,我们遇到了分支索引触发额外无用构建的问题。通过在管道之前添加此内容来解决此问题:
// Avoid useless buils: The branch indexing should only trigger the initial build of a new branch.
def isTriggeredByBranchIndexing = currentBuild.getBuildCauses('jenkins.branch.BranchIndexingCause').size()
if (isTriggeredByBranchIndexing && currentBuild.previousBuild) { // Then it's not the initial build.
echo "# Reindexing a branch already built. It is useless to rebuild it now. Aborting."
currentBuild.result = 'SUCCESS' // Make sure the build is not displayed in red in the Jenkins UI.
return // Abort before the pipeline even starts. (Inside the pipeline, this would only abort one stage.)
}
答案 2 :(得分:2)
获取工作流运行原因的功能已在Pipeline Supporting APIs Plugin的版本 2.22(2018年11月2日)中发布。该功能是在JENKINS-41272中请求的。
该版本向sort
全局变量中添加了一些方法:
currentBuild
- 为当前构建返回构建原因的JSON数组
实验性-可能会更改
getBuildCauses
- 获取一个表示完全合格的
getBuildCauses(String causeClass)
类的字符串,并为当前构建返回一个按该类型过滤的构建原因的JSON数组,如果没有指定类型的原因适用于当前构建,则返回一个空JSON数组
我提交的一个示例:
Cause
输出:
echo "${currentBuild.buildCauses}" // same as currentBuild.getBuildCauses()
echo "${currentBuild.getBuildCauses('hudson.model.Cause$UserCause')}"
echo "${currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause')}"
注意
当[Pipeline] echo
[[_class:hudson.model.Cause$UserIdCause, shortDescription:Started by user anonymous, userId:null, userName:anonymous], [_class:org.jenkinsci.plugins.workflow.cps.replay.ReplayCause, shortDescription:Replayed #12]]
[Pipeline] echo
[]
[Pipeline] echo
[]
[Pipeline] End of Pipeline
Finished: SUCCESS
是插件贡献的currentBuild.getBuildCauses(type)
类型时,type
似乎有问题。例如,Cause
失败,出现currentBuild.getBuildCauses('org.jenkinsci.plugins.workflow.cps.replay.ReplayCause')
。在JENKINS-54673的java.lang.ClassNotFoundException
版本的Pipeline: Supporting APIs (workflow-support
) plugin中报告了此情况。据报道,它是在2.22
版本中修复的。
答案 3 :(得分:2)
我认为这里的答案不完整,不能提供实际可用的答案。这是我的代码,以使其正常工作:
import com.cloudbees.groovy.cps.NonCPS
@NonCPS
def isStartedByTimer() {
def buildCauses = currentBuild.rawBuild.getCauses()
echo buildCauses
boolean isStartedByTimer = false
for (buildCause in buildCauses) {
if ("${buildCause}".contains("hudson.triggers.TimerTrigger\$TimerTriggerCause")) {
isStartedByTimer = true
}
}
echo isStartedByTimer
return isStartedByTimer
}
// [...]
// Other pipeline stuff
script {
isStartedByTimer()
}
由用户启动时:
00:00:01.353 [hudson.model.Cause$UserIdCause@fa5cb22a]
[Pipeline] echo
00:00:01.358 false
由计时器启动时:
00:00:01.585 [hudson.triggers.TimerTrigger$TimerTriggerCause@5]
[Pipeline] echo
00:00:01.590 true
注意:需要NonCPS装饰器,因为否则将引发下一个非脚本步骤。
答案 4 :(得分:1)
我们可以使用“BUILD_CAUSE”变量来获取有关谁发起了运行的信息
对于[jenkins-pipeline]你可以使用
currentBuild.rawBuild.getCauses()
(更多详情,请参阅github.com/jenkinsci/pipeline-examples/blob/master/ ...)
答案 5 :(得分:1)
在没有currentBuild.rawBuild
访问权限的Jenkins管道中,可以通过以下方式检索生成原因:
// started by commit
currentBuild.getBuildCauses('jenkins.branch.BranchEventCause')
// started by timer
currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause')
// started by user
currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause')
答案 6 :(得分:0)
假设两个不同的生成原因是“ timer”和“ push”(到git repo),则可以将以下阶段添加到Jenkinsfile中(在声明性Jenkins管道中)以使用getBuildCauses()
:
pipeline {
stages {
stage('preparation') {
steps {
script {
// get build cause (time triggered vs. SCM change)
def buildCause = currentBuild.getBuildCauses()[0].shortDescription
echo "Current build was caused by: ${buildCause}\n"
// e.g. "Current build was caused by: Started by GitHub push by mirekphd"
// vs. "Started by timer"
}
}
}
}
}
然后,我可以决定是否有条件地执行某些阶段(取决于构建原因)。例如,应该定期提取docker基本映像并检查系统库中的更改(可能是安全更新),而不管源代码是否发生更改。
答案 7 :(得分:0)
有一个类似的要求,成功/失败通知中应该包含触发构建的用户详细信息。该作业已基于时间触发,因此无法直接使用wrap([$ class:'BuildUser'])。
我在下面的步骤中使用了该命令,如果手动触发作业或计时器触发,则会打印用户名。所以,我用了这个:
pipeline {
agent any
stages {
stage('Test') {
steps {
script{
env.buildCauses = currentBuild.rawBuild.getCauses()
if (buildCauses.contains("hudson.triggers.TimerTrigger")){
env.builduser = "TimerTrigger"
} else {
wrap([$class: 'BuildUser']) {
env.builduser = "${BUILD_USER}"
}
}
}
echo "Initiated by: ${env.builduser}"
}
}
}
}
答案 8 :(得分:0)
我可能遗漏了一些东西,但您可以通过使用 when directive 轻松实现您想要的:
pipeline {
agent any
stages {
stage('Always') {
steps {
echo "I am always executed"
}
}
stage('ManualTimed') {
steps {
echo "I am only executed when triggered manually or timed"
}
when {
beforeAgent true
anyOf {
triggeredBy 'TimerTrigger'
triggeredBy cause: 'UserIdCause'
}
}
}
stage('GitLabWebHookCause') {
steps {
echo "I am only executed when triggered by SCM push"
}
when {
beforeAgent true
triggeredBy 'GitLabWebHookCause'
}
}
}
}
您会在 when directive 的文档中找到许多适用于各种用例的类似有用示例。
编辑: 感谢 Jean-Francois Larvoire's answer,我能够找出我的用例所需的“我的触发器”GitLabWebHookCause。