¯\_(ツ)_/¯

thunder@home:~$

This is my home blog, mostly to share some useful info or code snippets
~ 2 mins

Hello, Jenkins geeks.

Once upon a time, I wrote a Jenkins Scripted Pipeline with parallel downstream jobs run. As a part of that, I need to get some data from the downstream jobs. In my case, I need to get built docker image tag.

And here is the story how to do that. I have a bunch of the services, which has its own pipelines, and I’d like to run builds in parallel. At the same time, each build generate, for example, docker image with unique tag. Let’s assume, that I want to get created tag back to the main job for reuse or generate aggregated report. How I can achieve that?

Actually, it is easy!

Main pipeline code block:

...
def parallelSteps = [
  'Building service1' : {
    build(
      job: 'service1job',
      parameters: [
        string(name: 'myParam', value: 'myValue'),
      ],
      propagate: false,
      wait: true
    )
  },
  'Building service2' : {
    build(
      job: 'service2job',
      parameters: [
        string(name: 'myOtherParam', value: 'myValue'),
      ],
      propagate: false,
      wait: true
    )
  },
  ...
]
...

Parameter wait is mandatory!

Lets also set to not stop execution of the parallel steps on any failed parallel build:

parallelSteps.put('failFast', false)

And, finally, run our builds in parallel: def parallelResults = parallel(parallelSteps)

Once all your jobs are done, results will be available in parallelResults variable.

Now you can iterate over the completed builds and access build results for each build.

But, wait, what about sharing parameters from downstream builds to the upstream?

Technically, it’s the same as if you run the build without parallelism:

def myBuild = build(
  job: 'service1job',
  parameters: [
    string(name: 'myParam', value: 'myValue'),
  ],
  propagate: false,
  wait: true
)

myBuild is an instance of RunWrapper, so you can access many parameters.

Same here. parallelResults contains a Map<String, RunWrapper>

In order to get some string parameters from downstream build, you just need to use myBuild.getBuildVariables() . That will be a Map<String, String> .

This method returns only variables explicitly set via env.MY_PARAMETER_TO_RETURN='myValueToShare' . In this case, getBuildVariables() will contain MY_PARAMETER_TO_RETURN with defined value. No other Environment variables returned!

But, lets get back to our docker tag…

So, each my pipeline builds the image and expose docker tag as env.APP_IMAGE_TAG=myimagetag . Now I can easily collect tags from all parallel builds:

def myBuildTags = parallelResults.collectEntries { buildName, buildResult ->
  return [name: buildName, imageTag: buildResult.getBuildVariables().get('APP_IMAGE_TAG')]
}

Voila!

Bonus

You can also group parallel exectution results by status:

def parallelResultsGrouped = parallelResults.groupBy { it.getValue().getResult() }

The parallelResultsGrouped will contain something like this:

[
  SUCCESS: [
   'Building service1': <RunWrapper Object>,
   'Building service2': <RunWrapper Object>,
   'Building service3': <RunWrapper Object>,
  ]
]

If one of the downstream job fail, the map can look like this:

[
  SUCCESS: [
   'Building service1': <RunWrapper Object>,
   'Building service2': <RunWrapper Object>,
  ],
  FAILURE: [
   'Building service3': <RunWrapper Object>,
  ]
]

Now you can access only successful builds or failed builds. Remember about other statuses, like ABORTED and UNSTABLE .

Happy Scripting!

Thank You For Reading