Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jenkins pipeline: return value of build step

In this integration pipeline in Jenkins, I am triggering different builds in parallel using the build step, as follows:

stage('trigger all builds') {   parallel   {     stage('componentA')     {       steps       {         script          {           def myjob=build job: 'componentA', propagate: true, wait: true         }       }     }     stage('componentB')     {       steps        {         script         {           def myjob=build job: 'componentB', propagate: true, wait: true         }       }     }   } } 

I would like to access the return value of the build step, so that I can know in my Groovy scripts what job name, number was triggered.

I have found in the examples that the object returned has getters like getProjectName() or getNumber() that I can use for this.

But how do I know the exact class of the returned object and the list of methods I can call on it? This seems to be missing from the Pipeline documentation. I am asking for this case in particular, but generally speaking, how can I know the class of the returned object and its documentation?

like image 402
Florian Castellane Avatar asked Jun 29 '18 13:06

Florian Castellane


People also ask

What is build step in Jenkins?

This build step enables your Jenkins job to run a Command Workflows in Commander. For the build step to run a command workflow, you must configure the following: Target Type: The types of target that you want to run the command workflow on.

What is SH in Jenkins pipeline?

On Linux, BSD, and Mac OS (Unix-like) systems, the sh step is used to execute a shell command in a Pipeline. Jenkinsfile (Declarative Pipeline) pipeline { agent any stages { stage('Build') { steps { sh 'echo "Hello World"' sh ''' echo "Multiline shell steps works too" ls -lah ''' } } } }

Can we run a step conditionally in Jenkins?

The Conditional BuildStep plugin lets users add conditional logic to Freestyle jobs from within the Jenkins web UI. It does this by: Adding two types of Conditional BuildStep ("Single" and "Multiple") - these build steps contain one or more other build steps to be run when the configured condition is met.


Video Answer


1 Answers

The step documentation is generated based on some files that are bundled with the plugin, which sometimes isn't enough. One easy way would be to just print out the class of the result object by calling getClass:

def myjob=build job: 'componentB', propagate: true, wait: true echo "${myjob.getClass()}" 

This output would tell you that the result (in this case) is a org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper which has published Javadoc.

For other cases, I usually have to dive into the Jenkins source code. Here is my general strategy:

  • Figure out which plugin the step comes from either by the step documentation, jenkins.io steps reference, or just searching the internet
  • From the plugin site, go to the source code repository
  • Search for the String literal of the step name, and find the step type that returns it. In this case, it looks to be coming from the BuildTriggerStep class, which extends AbstractStepImpl

    @Override public String getFunctionName() {     return "build"; } 
  • Look at the nested DescriptorImpl to see what execution class is returned

    public DescriptorImpl() {     super(BuildTriggerStepExecution.class); } 
  • Go to BuildTriggerStepExecution and look at the execution body in the start() method

  • Reading over the workflow step README shows that something should call context.onSuccess(value) to return a result. There is one place in that file, but that is only on the "no-wait" case, which always returns immediately and is null (source).

    if (step.getWait()) {     return false; } else {     getContext().onSuccess(null);     return true; } 
  • Ok, so it isn't completing in the step execution, so it must be somwhere else. We can also search the repository for onSuccess and see what else might trigger it from this plugin. We find that a RunListener implementation handles setting the result asynchronously for the step execution if it has been configured that way:

    for (BuildTriggerAction.Trigger trigger : BuildTriggerAction.triggersFor(run)) {     LOGGER.log(Level.FINE, "completing {0} for {1}", new Object[] {run, trigger.context});     if (!trigger.propagate || run.getResult() == Result.SUCCESS) {         if (trigger.interruption == null) {             trigger.context.onSuccess(new RunWrapper(run, false));         } else {             trigger.context.onFailure(trigger.interruption);         }     } else {         trigger.context.onFailure(new AbortException(run.getFullDisplayName() + " completed with status " + run.getResult() + " (propagate: false to ignore)"));     } } run.getActions().removeAll(run.getActions(BuildTriggerAction.class)); 
  • The trigger.context.onSuccess(new RunWrapper(run, false)); is where the RunWrapper result comes from

like image 90
mkobit Avatar answered Sep 22 '22 16:09

mkobit