Jenkins Pipelines and their dirty secrets 2.
Tags: jenkins, jobdsl, pipelines, ci
Published: 2017-07-24 10:47:02

---
title: Jenkins Pipelines and their dirty secrets 2.
published: true
description: Solving parameterizing problems with Pipelines
cover_image: https://thepracticaldev.s3.amazonaws.com/i/myh4a4tzvda1g83lyjpx.jpg
tags: jenkins, job-dsl, pipelines, ci
---

#Solving parameterizing problems with Pipelines:

In the following section, I will go through several Jenkins workflow handling examples with pipelines. Let's not waste time and ***see the code***!
***

## 1. Run parameterized jobs
When you create a pipeline, you can set it to be parameterized:
![alt text](https://thepracticaldev.s3.amazonaws.com/i/ryjwgx28gqbbwkxhad7g.png)
If you want to use these parameters in the pipeline script you can refer to them as `params.your_parameter`. Now I'm going to confuse you: **You can declare parameters in your pipeline script too!**
```groovy
#!/usr/bin/env groovy
pipeline {
    agent any
        parameters {
            string(
                name: 'MyString',
                defaultValue:"default",
                description: "Any")
...
```
Indeed nothing stops you from putting a parameters block in your pipeline script. So what will happen if you build the job now? Here's the answer: In this case, when your pipeline job builds for the first time, **it will clear all the previous config set in your job, parameterize it according to the parameters block of the pipeline script, and run it with its default parameters**. If you do this and have a look at your job's Console Output, you will see the following message, which warns you that your config in the jenkis job will be lost, and replaced with the one in the pipeline script: `WARNING: The properties step will remove all JobPropertys currently configured in this job, either from the UI or from an earlier properties step.`
Anyway, this is how you set parameters in your Pipeline Script, and use it, for example to run another job with parameters:
```groovy
#!/usr/bin/env groovy

pipeline {
    agent any
        parameters {
            choice(
                name: 'Nodes',
                choices:"Linux\nMac",
                description: "Choose Node!")
            choice(
                name: 'Versions',
                choices:"3.4\n4.4",
                description: "Build for which version?" )
            string(
                name: 'Path',
                defaultValue:"/home/pencillr/builds/",
                description: "Where to put the build!")
    }
    stages {
        stage("build") {
            steps {
                script {
                    build(job: "builder-job",
                        parameters:
                        [string(name: 'Nodes', value: "${params.Nodes}"),
                        string(name: 'Versions', value: "${params.Versions}"),
                        string(name: 'Path', value: "${params.Path}")])
                }
            }
        }
    }
}
```
---
## 2. Initialize parameterized job:

***One important thing to know:*** It is handy to create the pipeline job as a parameterized job, with all these parameters in it, because if you don't do it, you will *not be able to choose parameters when you build the job the first time!*
**Set your job to be parameterized:**
![alt text](https://thepracticaldev.s3.amazonaws.com/i/ryjwgx28gqbbwkxhad7g.png)
Anyway, there is another way *(explained in the above section too!)*:
When a job,  -that has parameters block in it's Jenkinsfile - runs, **it clears all the previous parameters set in the job's config and overwrites it with the ones in the Jenkinsfile**. This is a kind of first *dry run*, which sets the parameters, and at the second run, you can run the job as a parameterized job **even if you didn't create it as one**.
Unfortunately, in this case, it can happen that at the first dry run, when you can't set your parameters yet, your job basically just starts running with its default parameters. This can be bad, as you may not want that.
***For this scenario I offer a workaround:***
Create an Initializer choice parameter in the jenkinsfile with a "Yes" default.
`choice(name: 'Invoke_Parameters', choices:"Yes\nNo", description: "Do you whish to do a dry run to grab parameters?" )`
Then create a first `stage`, which checks if this is an initial run. If it is, it will abort the build. 
```groovy
    stages {
        stage("parameterizing") {
            steps {
                script {
                    if ("${params.Invoke_Parameters}" == "Yes") {
                        currentBuild.result = 'ABORTED'
                        error('DRY RUN COMPLETED. JOB PARAMETERIZED.')
                    }
                }
            }
        }
```
As this is after the `parameters` block, your job will be parameterized when you run it the second time, and you can unset the Invoke_Parameters choice parameter.

---
## 3. Inheriting job variables from previous jobs:
Previously in build flows, it was a common thing, that you could pass parameters to jobs, and get the resulting AbstractBuild when required.
```
b = build( "job1", param1: "foo", param2: "bar" )
build( "job2", param1: b.build.number )
```
There is a way for this in Pipeline. You can reach these as `buildVariables`:
```groovy
#!/usr/bin/env groovy

pipeline {
    agent any
    stages {
        stage("build") {
            steps {
                script {
                    def b = build(job: "parameter-source-job", propagate: false)
                    build(
                        job: "analyzer-job",
                        parameters: [
                            [
                                $class: 'StringParameterValue',
                                name: 'PARAM_ONE',
                                value: b.buildVariables.PARAM_ONE
                            ],
                            [
                                $class: 'StringParameterValue',
                                name: 'PARAM_TWO',
                                value: b.buildVariables.PARAM_TWO
                            ]
                        ]
                    )
                    if (b.result == 'FAILURE') {
                            error("${b.projectName} FAILED")
                    }
                }
            }
        }
    }
}
```
## 4. Pipeline asking for input during build

Pipeline scripts offer a syntax which is useful, in case you need to ask for permissions or data during the build.
Imagine a scenario in which **I need to choose some parameters for the build depending on some other parameter I previously have chosen**.
This is where the user input choice comes handy.
+ Here first a list of nodes (strings) are generated by a bash script in the node block, during an initial run, stopped by the parameterizing stage. 
+ During the second run, we choose a Node parameter from this list of nodes, as we run the job as a parameterized build. 
+ After this, in the `choose version` stage, another bash script is run with the `node` parameter as its first parameter, which generates the list of node versions for that node.
+ At the `input message` part the job stops, and we can choose from these versions.
+ In the end the job runs another job with our parameters.
```groovy
#!/usr/bin/env groovy

def nodes
def versions

node {
    dir('/home/pencillr/workspace') {
        nodes = sh (script: 'sh list_nodes.sh', returnStdout: true).trim()
    }
}

pipeline {
agent any
    parameters {
            choice(name: 'Invoke_Parameters', choices:"Yes\nNo", description: "Do you whish to do a dry run to grab parameters?" )
            choice(name: 'Nodes', choices:"${nodes}", description: "")
    }
    stages {
        stage("parameterizing") {
            steps {
                script {
                    if ("${params.Invoke_Parameters}" == "Yes") {
                        currentBuild.result = 'ABORTED'
                        error('DRY RUN COMPLETED. JOB PARAMETERIZED.')
                    }
                }
            }
        }
        stage("choose version") {
            steps {
                script {
                    def version_collection
                    def chosen_node = "${params.Nodes}"
                    dir('/home/pencillr/workspace') {
                         version_collection = sh (script: "sh list_versions.sh $chosen_node", returnStdout: true).trim()
                    }
                        versions = input message: 'Choose testload version!', ok: 'SET', parameters: [choice(name: 'TESTLOAD_VERSION', choices: "${version_collection}", description: '')]
                            

        stage("build") {
            steps {
                script {
                    build(job: "builder-job",
                        parameters:
                        [string(name: 'Nodes', value: "${params.Nodes}"),
                        string(name: 'Versions', value: "${versions}"),
                        ])
                }
            }
        }
    }
}
```