Jenkins Plugin With Optional Input Parameters

In a previous post, the Jenkins Stapler plugin was used to implement a plugin to be used with freestyle and pipeline jobs. In this example, all plugin parameters had to be defined in the pipeline script. However, sometimes it would be more convenient to make some plugin parameters optional.

First, let us assume we have the following pipeline. For simplicity, there is just one step executing our plugin called ‘myPlugin’. Three parameters, that is instance, project, and revision can be defined as input parameters.

pipeline {   
   stages {
      stage("Plugin execution") {
         steps {
            myPlugin instance:'PROD', project:'xyz', revision:'latest'
         }
      }
   }
}

Stapler will invoke the public constructor annotated with @DataBoundConstructor and binds all parameters to the constructor’s parameters. It throws an exception if one is missing or of the wrong type.

import org.kohsuke.stapler.DataBoundConstructor;

@DataBoundConstructor
public SofitProjectBuilder(String project, BackendInstance instance, String revision) {
     this.project = project;
     this.instance = instance;
     this.revision = revision ;
}

Our goal is to make revision optional and to set it to the default parameter ‘latest’ if it is omitted in the step definition.

The backend and the project parameter should stay mandatory. If you leave out one of the parameters, Jenkins will throw an exception as it tries to bind a property in the constructor which is undefined.

Define mandatory parameters

By default, all parameters defined in the annotated constructor are mandatory and have to be defined in the plugin call.

Stapler will first invoke the DataBoundConstructor-annotated constructor, and if there are any remaining properties, it’ll try to find a matching DataBoundSetter-annotated setter method or field.

Define optional parameters

To convert revision to an optional parameter, we have to remove it from the constructor and create a @DataBoundSetter-annotated method.

import org.kohsuke.stapler.DataBoundSetter;

@DataBoundSetter
public void setRevision(String revision) {
     if (revision == null || "".equals(revision)) {
         this.revision = REVISION_LATEST;
     } else {
         this.revision = revision;
     }
}

The setter method is discovered through reflection. The setter method name must match the property name (such as setFoo for the foo property), and it needs to be public.

A field is discovered through simple reflection, so its name must match the property name. However, its access modifier can be anything.

I check if the revision field is invalid, e.g. null or empty. If so, the default value ‘latest’ is assigned. Otherwise, the given value is taken.

The following plugin call would be successful as well. The revision parameter is automatically assigned the default value.

pipeline {   
   stages {
      stage("Plugin execution") {
         steps {
            myPlugin instance:'PROD', project:'xyz'
         }
      }
   }
}