How to differentiate build triggers in Jenkins Pipeline

后端 未结 7 1608
挽巷
挽巷 2020-12-03 10:23

I\'m hoping to add a conditional stage to my Jenkinsfile that runs depending on how the build was triggered. Currently we are set up such that builds are either triggered by

相关标签:
7条回答
  • 2020-12-03 10:48

    I think that the answers here are incomplete and do not provide an actual ready to use answer. Here's my code to get it working:

    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()
    }
    

    When started by user:

    00:00:01.353 [hudson.model.Cause$UserIdCause@fa5cb22a]
    [Pipeline] echo
    00:00:01.358 false
    

    When started by timer:

    00:00:01.585 [hudson.triggers.TimerTrigger$TimerTriggerCause@5]
    [Pipeline] echo
    00:00:01.590 true
    

    Note: the NonCPS decorator is needed because otherwise the next non-script step will throw.

    0 讨论(0)
  • 2020-12-03 10:49

    In Jenkins Pipeline without currentBuild.rawBuild access the build causes could be retrieved in the following way:

    // 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')
    
    0 讨论(0)
  • 2020-12-03 10:51

    Assuming the two different build causes are "timer" and "push" (to a git repo), you can add the following stage to your Jenkinsfile (in a declarative Jenkins pipeline) to make use of 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"
    
            }
          }
        }
      }
    }
    
    

    Then I can decide whether to perform certain stages conditionally (depending on the build cause). For example, pulling a docker base image and inspecting for changes in system libraries (likely security updates) should be done periodically, regardless of whether there was a source code change or not.

    0 讨论(0)
  • 2020-12-03 10:58

    The ability to get causes for a workflow run was released in version 2.22 (2018 Nov 02) to the Pipeline Supporting APIs Plugin. The feature was requested in JENKINS-41272.

    A couple methods were added to the currentBuild global variable with that release:

    getBuildCauses

    • Returns a JSON array of build causes for the current build

    EXPERIMENTAL - MAY CHANGE getBuildCauses(String causeClass)

    • Takes a string representing the fully qualified Cause class and returns a JSON array of build causes filtered by that type for the current build, or an empty JSON array if no causes of the specified type apply to the current build

    And an example from me submitting:

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

    And the output:

    [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
    

    NOTE

    There appears to be an issue with the currentBuild.getBuildCauses(type) when the type is a type of Cause contributed by a plugin. For example, currentBuild.getBuildCauses('org.jenkinsci.plugins.workflow.cps.replay.ReplayCause') fails with a java.lang.ClassNotFoundException. This was reported in JENKINS-54673 for the 2.22 version of the Pipeline: Supporting APIs (workflow-support) plugin. It is reportedly fixed in the 2.24 version.

    0 讨论(0)
  • 2020-12-03 11:02

    We can use "BUILD_CAUSE" variable for getting the information about who initiated the run

    for [jenkins-pipeline] you may use

    currentBuild.rawBuild.getCauses()
    

    (see github.com/jenkinsci/pipeline-examples/blob/master/… for more details)

    0 讨论(0)
  • 2020-12-03 11:03

    There was a similar requirement, where user detail who triggered the build should be there in success / failure notification. The job was already had time based triggered, hence could not use wrap([$class: 'BuildUser']) directly.

    I used below step, which print username if the job is triggered manually or timer triggered. So, I used this:

    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}"
                }
            }
        }   
    }
    
    0 讨论(0)
提交回复
热议问题