如何区分Jenkins管道中的构建触发器

old*_*ard 15 jenkins jenkins-pipeline

我希望为我的Jenkinsfile添加一个条件阶段,该阶段根据构建的触发方式运行.目前我们的设置使得构建可以通过以下方式触发:

  1. 我们的git仓库的变化是在分支索引上获得的
  2. 用户使用UI中的"立即构建"按钮手动触发构建.

是否有任何方法可以运行不同的管道步骤,具体取决于哪些操作触发了构建?

Vit*_*dir 20

在没有currentBuild.rawBuild访问权限的Jenkins Pipeline 中,可以通过以下方式检索构建原因:

// 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')
Run Code Online (Sandbox Code Playgroud)

  • 作为补充,要访问原因的内部信息,请使用: `def name = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause').userName` 更多信息:https://github.com/jenkinsci/workflow-support-插件/blob/c019079f526f627665c812fe86dd72419075df62/src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/RunWrapper.java#L165 (2认同)
  • 您可以使用以下命令检查计时器是否触发构建:`isTriggeredByTimer = !currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause').isEmpty()` (2认同)

Ild*_*ial 13

我可能会遗漏一些东西,但是您可以通过使用when 指令轻松实现您想要的东西:

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'
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您将在when 指令的文档中找到许多针对各种用例的类似有用示例。

编辑:感谢Jean-Francois Larvoire 的回答,我能够找出我的用例所需的“我的触发器”GitLabWebHookCause。


Phi*_*lip 11

以下代码应用于确定用户是否已启动管道或计时器/其他触发器:

def isStartedByUser = currentBuild.rawBuild.getCause(hudson.model.Cause$UserIdCause) != null
Run Code Online (Sandbox Code Playgroud)

  • 可以在此处找到不同的 Cause 子类:https://javadoc.jenkins-ci.org/hudson/model/Cause.html。我猜(未经测试)您正在寻找的原因是:hudson.triggers.TimerTrigger$TimerTriggerCause 和 hudson.model.Cause$RemoteCause。 (4认同)
  • 声明性管道呢? (3认同)
  • 我只想为现在遇到这个答案的人补充一下:访问“rawBuild”是一个潜在的安全风险(并且需要得到管理员的批准),但正如[这个答案](https://stackoverflow.com/a/ 53342374/11744714)提到,从版本 2.22 开始,您可以使用 `currentBuild.getBuildCauses()` 方法代替。 (2认同)

mko*_*bit 8

获取工作流运行原因的功能已在2.22(2018年11月2日)中发布Pipeline Supporting APIs Plugin。在JENKINS-41272中请求了此功能。

currentBuild该版本中,向全局变量添加了一些方法:

getBuildCauses

  • 返回当前构建的构建原因的JSON数组

实验-可能会改变 getBuildCauses(String causeClass)

  • 接受一个表示完全合格的Cause类的字符串,并为当前构建返回一个按此类型过滤的构建原因的JSON数组,如果没有指定类型的原因适用于当前构建,则返回一个空JSON数组

我提交的一个例子:

echo "${currentBuild.buildCauses}" // same as currentBuild.getBuildCauses()
echo "${currentBuild.getBuildCauses('hudson.model.Cause$UserCause')}"
echo "${currentBuild.getBuildCauses('hudson.triggers.TimerTrigger$TimerTriggerCause')}"
Run Code Online (Sandbox Code Playgroud)

并输出:

[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
Run Code Online (Sandbox Code Playgroud)

注意

currentBuild.getBuildCauses(type)typeCause插件提供的一种类型时,似乎存在问题。例如,currentBuild.getBuildCauses('org.jenkinsci.plugins.workflow.cps.replay.ReplayCause')失败以java.lang.ClassNotFoundException。在JENKINS-54673中针对管道:支持API)插件2.22版本进行了报告。据报道该版本已修复。workflow-support2.24


Tom*_*myD 7

我认为这里的答案是不完整的,并没有提供实际的即用型答案。这是我让它工作的代码:

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()
}
Run Code Online (Sandbox Code Playgroud)

用户启动时:

00:00:01.353 [hudson.model.Cause$UserIdCause@fa5cb22a]
[Pipeline] echo
00:00:01.358 false
Run Code Online (Sandbox Code Playgroud)

定时器启动时:

00:00:01.585 [hudson.triggers.TimerTrigger$TimerTriggerCause@5]
[Pipeline] echo
00:00:01.590 true
Run Code Online (Sandbox Code Playgroud)

注意:需要 NonCPS 装饰器,否则下一个非脚本步骤将抛出。


Jea*_*ire 5

@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()  
Run Code Online (Sandbox Code Playgroud)

.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.
}
Run Code Online (Sandbox Code Playgroud)

最后,如果目标是在特定情况下中止管道构建,则必须在管道开始之前完成测试。
例如,我们遇到了分支索引触发额外无用构建的问题。这是通过在管道之前添加这个来解决的:

// 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.)
}
Run Code Online (Sandbox Code Playgroud)