Create a Parameterized Pipeline using Template

Issue

  • I want to create Parameterized Pipeline jobs using Template

Environment

  • CloudBees Jenkins Enterprise
  • CloudBees Jenkins Operations Center
  • CloudBees Templates Plugin
  • Pipeline Plugin

Resolution

In this article, we are going to explain how to create Parameterized Pipeline Jobs using CloudBees Templates.

Job Definition

Build Parameters need to be defined in the General Job Definition. That is how Jenkins knows that the build is parameterized. The job definition should look like this:

<flow-definition>
<actions/>
<description/>
<keepDependencies>false</keepDependencies>
<properties>
    <hudson.model.ParametersDefinitionProperty>
        <parameterDefinitions>                           
            ...
            //Add parameters here
            ...
        </parameterDefinitions>
    </hudson.model.ParametersDefinitionProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition">
    <sandbox>false</sandbox>
</definition>
<triggers/>
</flow-definition>

Pipeline Script Definition

The parameters values are handled in the Pipeline script. The following snippets gives an idea on how to use parameters in Pipeline Jobs using CloudBees Templates using different methods:

Note: When using sh step, the Double quotes are important. Otherwise the parameter value cannot be resolved.

  • Parameters are accessible as Groovy variables of the same name:

    node {
        //Dislay the parameter value of the parameter name "myparam"
        println myparam
        sh "echo '${myparam}'"
    }
    
  • Parameters values are directly accessible by Parameter key using the methods getProperty and getBinding:

    node {
        /**
         * Use getBinding/getProperty:
         * -Check if a parameter exists by key (returns true even though the value is empty '')
         * -Display a build parameter by key
         */
        if (getBinding().hasVariable("myparam")) {
            println getProperty("myparam")
        }
    }
    
  • Parameters are accessible via the currentBuild variable:

    import hudson.model.ParameterValue;
    import hudson.model.ParametersAction;
    node {
        /**
         * Use currentBuild to:
         * -Retrieve the build parameters
         * -Display all the build parameters
         */
        def myBuildParams = currentBuild.rawBuild.getAction(ParametersAction.class)
        for(ParameterValue p in myBuildParams) {
            println p.name
            println p.value
        }
    }
    
  • For Template Attribute of type Heterogeneous component of ParameterDefinition, parameters values are accessible via the getProperty:

    import hudson.model.ParameterValue;
    import hudson.model.ParametersAction;
    node {
    
        //Display the value of a parameter defined as an attribute
        println myParam.name
        //Display the defaultValue of a parameter defined as an attribute
        println myParam.defaultValue
        //Display the value of a parameter defined as an attribute
        println getProperty(myParam.name)   
    }
    

Control

Three type of users comes into account when creating templates for parameterized jobs:

  • The User that defines the Template
  • The User that creates the Job based on the template
  • The User that triggers the Job

In most cases, there are different solutions to one requirement. Whether one solution or another is suitable often depends on how much control you want to give to the users that create the Jobs.

Examples

Example: Simple Parameterized Pipeline

In this example:

  • We need to create a bunch of pipeline jobs that deploy an application to a specific environment
  • We want the users that build the job to be able to choose the environment

1) Flow Definition:

<flow-definition>
<actions/>
<description/>
<keepDependencies>false</keepDependencies>
<properties>
    <hudson.model.ParametersDefinitionProperty>
        <parameterDefinitions>
            <hudson.model.ChoiceParameterDefinition>
                <name>DeployEnvironment</name>
                <description>Choose the Deploy Environment</description>
                <choices class="java.util.Arrays\$ArrayList">
                    <a class="string-array">
                        <string>DEV</string>
                        <string>TEST</string>
                        <string>QA</string>
                        <string>PROD</string>
                    </a>
                </choices>
            </hudson.model.ChoiceParameterDefinition>
        </parameterDefinitions>
    </hudson.model.ParametersDefinitionProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition">
    <sandbox>false</sandbox>
</definition>
<triggers/>
</flow-definition>

2) Pipeline Script Definition:

node {

  stage 'Deploy'
  sh "echo 'Deploying to ${DeployEnvironment.toLowerCase()}.example.com'"

}

3) Build the Job:

Example: Parameterized Pipeline with Parameters as Template Attributes

In this example:

  • We need to create a bunch of pipeline jobs that deploy an application to a specific environment
  • We want the users that build the job to be able to choose the environment
  • We want the users that create the job to provide the location of each environment

1) Auxiliary for Environment:

We create an Auxiliary Model that represents an Environment:

  • The name of the Environment (DEV, TEST, ..) which will also be the parameter name
  • The hostname

2) Template Attribute:

3) Flow Definition:

<flow-definition>
<actions/>
<description/>
<keepDependencies>false</keepDependencies>
<properties>
    <% if(deployEnvironments) { %>
    <hudson.model.ParametersDefinitionProperty>
        <parameterDefinitions>
            <hudson.model.ChoiceParameterDefinition>
                <name>DeployEnvironment</name>
                <description>Choose the Deploy Environment</description>
                <choices class="java.util.Arrays\$ArrayList">
                    <a class="string-array">
                    <% deployEnvironments.each { %>
                        <string>${it.name}</string>
                    <% } %>
                    </a>
                </choices>
            </hudson.model.ChoiceParameterDefinition>
        </parameterDefinitions>
    </hudson.model.ParametersDefinitionProperty>
    <% } %>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition">
    <sandbox>false</sandbox>
</definition>
<triggers/>
</flow-definition>

4) Pipeline Script Definition:

//The environment location is configured in the job
def deployToMap = [:]
deployEnvironments.each {
    deployToMap.put(it.name, it.hostname)
}

node {
  stage 'Deploy'
  println "Deploying to ${deployToMap[DeployEnvironment]}"
}

5) Create/Configure the Job:

We can provide any environment

6) Build the job:

Further Examples

Another example is to Let users specify any kind of parameters when creating a job from a pipeline template and handle them in the job created

Have more questions? Submit a request

5 Comments

  • 2
    Avatar
    Thomas Sackett

    I'm not sure where to start in my comments, because this document is very unclear.

    What is <flow-definition>? Where does this XML code go? Is it part of a template? This document says it goes in the "General Job Definition", but what is that? It doesn't appear in the official CJE User Guide. Neither does the phrase "Flow Definition".

    Does the first example use a template? I can't tell.

    For instructions to be helpful, you have to give users steps they can follow. A step is an action, not a thing. In the first example, the first two steps are things ("Flow Definition", "Pipeline Script Definition"). There is no information on what do do with these definitions, like where they should go.

    I appreciate that template documentation has improved a bit, but it still seems to be created by someone who has no idea how to provide a user with a set of instructions they can follow and learn from. 

     

  • 0
    Avatar
    Ryan Hutchison

    This doesn't seem to work anymore?

    node {
        /**
         * Use getBinding/getProperty:
         * -Check if a parameter exists by key (returns true even though the value is empty '')
         * -Display a build parameter by key
         */
        if (getBinding().hasVariable("myparam")) {
            println getProperty("myparam")
        }
    }
  • 0
    Avatar
    Allan Burdajewicz

    Hi Thomas,

    @Thomas Thanks for the feedback. This article explains a particular scenario/requirement and it is not a documentation and assume that the reader is familiar with Pipeline template. Pipeline template transformers is divided in 2 different section:

    * General Job Definition: define the configuration (XML) of the Pipeline job

    * Pipeline Definition: define the pipeline script

    I am gonna update this article with Screenshot to make it more clear.

    ---

    @Ryan Thanks for the update. That is right the `getBinding().hasVariable('myparam')` does not work anymore, instead you could use `env.getEnvironment().containsKey('myparam')`. Be aware that the recommended approach is to access the variable directly in the Pipeline script directly as Groovy variables.

    Regards,

  • 0
    Avatar
    Ryan Hutchison

    @Allan, adding a follow-up to share the approach I have been using

     

    node {
        /**
         * Use getBinding/getProperty:
         * -Check if a parameter exists by key (returns true even though the value is empty '')
         * -Display a build parameter by key
         */
        if (params.myparam != null) {
            println params.myparam
        }
    }
  • 0
    Avatar
    Allan Burdajewicz

    @Ryan Indeed this is a better approach since version 2.18 of the Pipeline Groovy Plugin

    Edited by Allan Burdajewicz
Please sign in to leave a comment.