In Jenkins/Groovy is it possible to get the build ID from an asynchronously triggered build?

42 Views Asked by At

Running build(job: 'path/to/job') in a Jenkins pipeline script triggers provided @job in a blocking way, i.e. it triggers a build and waits for it to finish and returns a RunWrapper object. Setting wait: false will not wait but also doesn't return anything at all, so I don't have any reference to the triggered build. Is there a way to trigger a build asynchronously and know what build had been triggered?

(related: Build job on Jenkins pipeline returns a null objet when wait is set to false)

1

There are 1 best solutions below

4
Noam Helmer On

The reason that the build step doesn't return anything in case you don't wait for the build is that the build might get stuck in the queue (so there is no build number) or just get stuck in some state that doesn't allow to grab the build id quickly.

You can overcome this by implementing the logic by yourself. For example, assuming you are wiling to wait until the job starts, you can create a function like the following:

def getTriggeredBuild(job) {
    // Run while the job did not start 
    while (true) { 
        // Search for the current build as the cause trigger
        def message = "upstream project \"${JOB_NAME}\" build number ${BUILD_NUMBER}"
        for (build in Jenkins.instance.getItem(job).getBuilds()) {
            // Iterate over all builds and find the one that was triggred by this build
            if(build.getCauses().any{ it.getShortDescription().contains(message) }) {
                return build 
            }
        }
        sleep 5
    }
}

This function can reside in a shared library, making it available for all your pipelines, or it can reside within your Jenkinsfile, but then an administrator will have to approve usage of some of the functions (not needed in the shared library).

Usage will be strait forward:

pipeline {
    agent any
    stages {
        stage('Hello') {
            steps {  
               script {
                   def jobName = 'triggred_job'
                   build job: jobName, wait: false
    
                   // Get the build that was triggered
                   def build = getTriggeredBuild(jobName)
                   println(build.number)
               }
            }
        }
    }
}

The waiting logic of the function can be modified according to your needs.