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

时间:2017-04-24 21:12:20

标签: jenkins jenkins-pipeline

我希望为我的Jenkinsfile添加一个条件阶段,该阶段根据构建的触发方式运行。目前我们的设置是由以下内容触发构建:

  1. 更改我们在分支索引
  2. 上获取的git仓库
  3. 用户使用'现在构建'手动触发构建。用户界面中的按钮。
  4. 有没有办法运行不同的管道步骤,具体取决于哪些操作触发了构建?

9 个答案:

答案 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-54673java.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。