11

I have a Jenkins project configured (I'll call it SuperJob here) to simply call several different other jenkins projects in order.

I would like to be able to find out the result of all the subprojects for a specific build number of this SuperJob through Jenkins API

Looking at the code posted HERE I am able to get the list of the specific projects configured in the SuperJob project from each build however I am not able to find a way to query what specific build number of each of these projects were run from a specific build of SuperJob.

For example, I would like to find out that "SuperJob build #5" triggered "MyJob build #3" and "OtherJob build #20" so I can aggregated and check the results for all of them.

I have tried all the Upstream and Downstream APIs including using the sub projects as an argument for therelationship ones but they all return empty or null.

I am guessing this is possible since Jenkins itself is able to show that information in the web ui which is coming from a plugin but I have not been able to find out how.

Alexandre Thenorio
  • 2,288
  • 3
  • 31
  • 50
  • Am I really the only person with such a problem? Or maybe it's so simple I am missing something – Alexandre Thenorio Oct 25 '15 at 21:59
  • Nope, few minutes ago I faced the same question ..) I need to retrieve the chain of builds through REST API. – Nakilon Oct 27 '15 at 17:13
  • Well Jenkins is obviously able to retrieve the correct information because when I configure the SuperJob to fail immediately upon one of the sub jobs failing, jenkins will only show the ones that have run in the list however using the API you will end up getting a build which does not belong to that specific super job build – Alexandre Thenorio Oct 28 '15 at 13:10
  • Some native Jenkins Java code for these retrieval is googlable. But through REST API I see only the backward connection as "caused by upstream build...", but not the opposite direction. That tells me to scrape all the downstream builds to find the one, and it would be either DDOS or need of some kind of caching, that is active only on the "finished" builds... that's damn complex for such simple question ..( – Nakilon Oct 28 '15 at 16:51
  • I am only interested in the Java API and not the REST one. I cannot find any way to do it with the java API, have you seen something? – Alexandre Thenorio Oct 29 '15 at 09:41
  • I have no clue in Java, but I guess I was talking about this: http://www.javacodegeeks.com/2013/02/jenkins-hierarchical-jobs-and-jobs-status-aggregation.html – Nakilon Oct 29 '15 at 11:14
  • 2
    I just filed https://issues.jenkins-ci.org/browse/JENKINS-33001. Hopefully that will be fixed, or include a workaround sometime. In the meantime, I guess just upvote that issue – Imran Rashid Feb 17 '16 at 18:42
  • We are still looking for a solution to this. – Mrunal Dadhi Feb 01 '23 at 06:51

2 Answers2

3

I have the same problem, and currently the solution I use to find sub builds, is by parsing the console log of each build. the log contains the triggered jobs names, and the builds numbers (after they finished).

import hudson.console.ConsoleNote;
jenkins = Jenkins.getInstance()
jobName = "root-job-name"     //just an example
buildNumber = 123             //just an example
job = jenkins.getItem(jobName)
startBuild = job.getBuildByNumber(buildNumber)

//scanning the tree using BFS
list = []
visitedList = []
q = list as java.util.Queue
q<<startBuild
visitedList.add(startBuild)
while (!q.empty){
   node = q.poll()

  subjobs = getTriggeredBuildssByBuild(node) //see method bellow
  subjobs.each{ subj ->
      if (!(subj in visitedList)){
          visitedList.add(subj)
          q<<subj
      }
  }
}

//printing results
visitedList.each{
    println "Job name and build number: ${it}"
}


//parsing the log of the Run object to get sub builds triggered by it
def getTriggeredBuildssByBuild(def run){
    list =[]
    if (run != null && ((reader = run.getLogReader()) != null)) {

        BufferedReader bufferedReader = new BufferedReader(reader);

        for (String line = bufferedReader.readLine();
            line != null;
            line = bufferedReader.readLine()) {

            //strip off jenkins specific encoding
            line = ConsoleNote.removeNotes(line);
            matcher = line=~/Finished Build : #(\d+) of Job : (.*) with/
            if(matcher){
               foundJob = matcher[0][2]
               foundBuildNum = Integer.parseInt(matcher[0][1])
               foundBuild=jenkins.getItem(foundJob).getBuildByNumber(foundBuildNum)
               list.add(foundBuild)
            }
        }
    }
return list
}

A few notes:

  1. you will need to check that the regex I used is suitable for all of your cases, of course you can change it to a method that checks for a few other regex matches.
  2. In case you use multijob plugin, and all of your jobs are from that type, it is much more easier, since MultijobBuild has a getSubBuilds() which returns exactly what you want.
  3. I'm still looking for a better way to find sub builds triggered by a given build, especially if it can return builds in all states, finished or still building.
Tidhar Klein Orbach
  • 2,896
  • 2
  • 30
  • 47
  • Thank you for sharing. I sincerely hope that parsing the logs are not the only way to retrieve this information. If this is the case I think we may need to put up an enhancement ticket with Jenkins as such an API should not be missing – Alexandre Thenorio Jan 16 '16 at 03:12
  • Another option I found it to use https://github.com/jenkinsci/downstream-buildview-plugin . this plugin adds a DownstreamBuildViewAction to each build by using DownstreamBuildViewRunListener. then you use the get the DownstreamBuildViewAction which has methods like: public int getDownstreamBuildNumber(String projectName) and public List getDownstreamBuildList(). – Tidhar Klein Orbach Jan 19 '16 at 10:43
  • I tried to attempt one approach here: https://stackoverflow.com/questions/50071652/jenkins-build-pipeline-job-jobs-listing-in-tree-layout-ordered-listing and it works! – AKS May 04 '18 at 16:48
1

If you have the Jenkins server URL, job name and job number, you can swap the values into a request like this:

https://<jenkins server URL>/view/all/job/<job name>/<job number>/api/json?pretty=true&tree=actions[triggeredBuilds[number,url,result]]

Which will give you a JSON response like this:

{
  "_class" : "hudson.model.FreeStyleBuild",
  "actions" : [
    {
      "_class" : "hudson.model.CauseAction"
    },
    {

    },
    {
      "_class" : "hudson.model.ParametersAction"
    },
    {

    },
    {
      "_class" : "hudson.plugins.git.util.BuildData"
    },
    {
      "_class" : "hudson.plugins.git.GitTagAction"
    },
    {

    },
    {
      "_class" : "hudson.plugins.parameterizedtrigger.BuildInfoExporterAction",
      "triggeredBuilds" : [
        {
          "_class" : "hudson.model.FreeStyleBuild",
          "number" : <subjob number>,
          "result" : "SUCCESS",
          "url" : "https://<jenkins server URL>/job/<subjob name>/<subjob number>/"
        },
        {
          "_class" : "hudson.model.FreeStyleBuild",
          "number" : <subjob number>,
          "result" : "SUCCESS",
          "url" : "https://<jenkins server URL>/job/<subjob name>/<subjob number>/"
        }
      ]
    },
    {

    },
    {

    },
    {

    }
  ]
}
Daniel Samuels
  • 423
  • 7
  • 25
  • Note that this does not seem to report builds in progress, only ones that have reached a finishing state – Sean Aug 03 '21 at 09:01