How to build Jenkins pipeline input parameters dynamically with Groovy? - jenkins

In a Jenkins pipeline, it is possible to request input data using
def returnValue = input message: 'Need some input',
parameters: [string(defaultValue: 'adefval', description: 'a', name: 'aaa'),
string(defaultValue: 'bdefval', description: 'b', name: 'bbb')]
To build such a list dynamically, I tried something like
def list = ["foo","bar"]
def inputRequest = list.collect { string(defaultValue: "def", description: 'description', name: it) }
def returnValue = input message: 'Need some input', parameters: [inputRequest]
This does not work:
java.lang.ClassCastException: class org.jenkinsci.plugins.workflow.support.steps.input.InputStep.setParameters() expects class hudson.model.ParameterDefinition but received class java.util.ArrayList
Probably, Groovy can figure out dynamically in the first case which object is required, but in the second case it does not work anymore, as collect returns an ArrayList?
How to create such a list correctly?
edit: maybe this question not very useful for itself, but may still serve as a code sample...

Ok it was quite a simple fix, as the collect already returns an ArrayList, it should not be wrapped into another list when setting the parameters...
def returnValue = input message: 'Need some input', parameters: inputRequest

I struggled with this for a while, but it's not as complicated as I thought.
At its simplest, you can define an empty array and fill it with parameter types.
I'm honestly not clear on what the object type is, but it works.
ArrayList pa = []
if(<some conditional>) {
pa += choice (name: 'source_feed', choices: ['Development', 'Production'])
pa += string (name: 'deployVersion', defaultValue: 'Latest', description: 'version')
pa += extendedChoice (name: 'environments', value: 'one,two,three', description: 'envs', type: 'PT_CHECKBOX')
pa += booleanParam (name: 'dryRunMode', defaultValue: false, description: 'dry')
pa += booleanParam (name: 'skipPreChecks', defaultValue: false, description: 'skip')
}
else if (<some other conditional>) {
pa += string (name: 'CommandServiceVersion', defaultValue: '', description: 'commandservice')
}
def result = input message: "Enter Parameters",
ok: 'ok go!',
parameters: pa
echo result.toString()
As long as you can pass the Array[] around, it works. I ended up creating the array[] outside the pipeline, as a global, so it can be passed around throughout the run; as opposed to an env var, which can only be a string.

You can use the the following code. It will generate the choices A,B,C for you. This can be found by using the Pipeline syntax option in Jenkins. I use it because it saves time and less typos.
def createInputParameters(){
properties([[$class: 'RebuildSettings', autoRebuild: false, rebuildDisabled:
false],parameters([choice(choices: ['A', 'B', 'C'], description: '', name:
'Test')]),
[$class: 'ThrottleJobProperty', categories: [],
limitOneJobWithMatchingParams: false,
maxConcurrentPerNode: 0, maxConcurrentTotal: 0,
paramsToUseForLimit: '',
throttleEnabled: false,
throttleOption: 'project']])
}

Related

Jenkinsfile print parameters nicely

We have a Jenkinsfile with parameters declared as follows:
def params = [string(name: 'ENVIRONMENT', value: environment),
string(name: 'VERSION', value: version),
string(name: 'REGION', value: region)]
I'd like to echo these, for example
DEPLOYING: ENVIRONMENT=STAGING, VERSION=1.3.0, REGION=EU
However calling echo "$params" prints:
[#string(name=ENVIRONMENT,value=STAGING), #string(name=VERSION,value=1.3.0), #string(name=REGION,value=EU)]
I tried iterating the array - e.g. :
params.each { echo it } throws UnsupportedOperationException: no known implementation of class java.lang.String is using symbol ‘string’
params.each { echo it.name } throws RejectedAccessException: No such field found: field org.jenkinsci.plugins.structs.describable.UninstantiatedDescribable name
How can I print the params array nicely?
EDIT - from Matt Schuchard's response:
def params = [string(name: 'ENVIRONMENT', value: "STAGING"),
string(name: 'VERSION', value: "1.3.0"),
string(name: 'REGION', value: "EU")]
print "$params"
params.each() { param, value ->
print "Parameter: ${param}, Value: ${value}"
}
returns (i.e. Value is all null):
[#string(name=ENVIRONMENT,value=STAGING), #string(name=VERSION,value=1.3.0), #string(name=REGION,value=EU)]
Parameter: #string(name=ENVIRONMENT,value=STAGING), Value: null
Parameter: #string(name=VERSION,value=1.3.0), Value: null
Parameter: #string(name=REGION,value=EU), Value: null
You can use a Groovy map iterator lambda method (such as each) to iterate over the params map. An example follows:
params.each() { param, value ->
print "Parameter: ${param}, Value: ${value}"
}
If you decide to use this directly inside a pipeline block, then this will need to be placed inside a script block when using declarative DSL.
There must be a better way but the following works
Iterating the params array:
1. Cast each parameter to a regular String
2. Extracted the value between #string( VALUE )
3. Split the key/value pairs first by comma ','
4. Then split each side of the above by equals '='
5. Concatenate the second argument
def pretty(params) {
def s = ""
params.each { param ->
def a = ("${param}" =~ /^#string\((.+)\)$/)[ 0 ][ 1 ]
def b = a.split(",")
s = s + b[0].split("=")[1] + "=" + b[1].split("=")[1] + "\n"
}
return s
}
Returns:
ENVIRONMENT=STAGING
VERSION=1.3.0
REGION=EU
is params goal is to parameterized the build?
if this is the case, you can use parameters directive
The parameters directive provides a list of parameters that a user
should provide when triggering the Pipeline.
The values for these
user-specified parameters are made available to Pipeline steps via the
params object.
declerative pipeline:
Declarative Pipeline supports parameters out-of-the-box, allowing the
Pipeline to accept user-specified parameters at runtime via the
parameters directive.
parameters {
string(name: 'ENVIRONMENT', defaultValue: 'STAGING', description: 'Environment to test. e.g: production/develop'),
string(name: 'VERSION', defaultValue: '1.3.0', description: 'Version to run'),
string(name: 'REGION', defaultValue: 'EU', description: 'Region')
}
scripted pipeline:
Configuring parameters with Scripted Pipeline is
done with the properties step, which can be found in the Snippet
Generator
properties([
parameters([
string(name: 'ENVIRONMENT', defaultValue: 'STAGING', description: 'Environment to test. e.g: production/develop'),
string(name: 'VERSION', defaultValue: '1.3.0', description: 'Version to run'),
string(name: 'REGION', defaultValue: 'EU', description: 'Region')
])
])
now, those parameters are accessible as members of the params variable
so, then you can simply use:
params.each() { param, value ->
print "Parameter: ${param}, Value: ${value}"
}

How can I pass MatrixCombinationsParameterValue with simple filter in groovy pipeline

I have a job with matrix project, I added ElasticAxis name:label
I also added a matrix combinations parameter name: labelFilter
I want to run the job from groovy pipeline with filter label == "PA16"
This call is not working for me:
[$class: 'MatrixCombinationsParameterValue', name: 'labelFilter', value: 'label=="PA16"']
The question is: What is the correct syntax to call the matrix combinations parameter?
I have few branches, each branch should run with specific label, the pipeline gets the branch name and run a job in jenkins with the name of the label. Lets say I want to run the job with the label "PA16" so I add this code to groovy pipeline file:
build job: 'test_matrix',
parameters: [
string(name: 'RndBranch', value: RndBranch),
string(name: 'BuildNumber', value: PAVersion),
string(name: 'Auto_Build_Path', value: autoFolder),
string(name: 'Installer_folder', value: Installer_folder),
string(name: 'RabbitMQ_Server', value: rabbitMQServer),
string(name: 'QueName', value: qName),
[$class: 'MatrixCombinationsParameterValue', name: 'labelFilter', filter: 'label=="PA16"']
]
For Jenkins pipeline please use matrix instead. For example:
stage ('TestMatrix') {
matrix {
axes {
axis {
name 'labelFilter'
values 'PA16', 'PA17', 'PA18'
}
axis {
name 'otherFilter'
values 'Filter1', 'Filter2', 'Filter3'
}
}
stages {
stage ('Doing what you want') {
steps { echo "Doing what I want"}
}
}
}
}
You can read more at following document about matrix or here

How to use Groovy variable into Extended Choice Jenkins Plugin?

I'd like to use a Groovy variable as a value for Extended Choice plugin. Seems trivial, but doesn't work - fails with "groovy.lang.MissingPropertyException: No such property: $COMPONENTS_LIST for class: groovy.lang.Binding".
Any ideas?
environment {
COMPONENTS_LIST= "one two three"
}
parameters {
extendedChoice (description: 'Components', multiSelectDelimiter: ' ',
name: 'Components_To_Deploy', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_MULTI_SELECT',
value: $COMPONENTS_LIST, visibleItemCount: 3)
}
It is a syntax error, you are trying to set the named parameter value to the content of the variable $COMPONENTS_LIST; which doesn't exist. Also there's a problem with the scope of the variable; which needs to be available in both closures. So try defining a variable outside the scope of both closure with the value you need and then use the variables inside the closures, as in the following example:
def componentsList = "one two three"
environment {
COMPONENTS_LIST = componentsList
}
parameters {
extendedChoice (description: 'Components', multiSelectDelimiter: ' ',
name: 'Components_To_Deploy', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_MULTI_SELECT',
value: componentsList, visibleItemCount: 3)
}
I think that this is a syntax issue. You have to use double quote to refer to you variable :
def COMPONENTS_LIST= "one two three"
parameters {
extendedChoice (description: 'Components', multiSelectDelimiter: ' ',
name: 'Components_To_Deploy', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_MULTI_SELECT',
value: "${COMPONENTS_LIST}", visibleItemCount: 3)
}

Why is my LinkedHashMap merging key with value?

Intro
I wrote some code for a Jenkins pipeline in Groovy that looks like this:
def sendNotifications (args) {
// ... use args ...
sendSlack(
failOnError: true,
color: '#00FF00',
message: "foo",
channel: "#mychan"
)
}
// slackMessage not shown returns a string based on the args.
This code seemed to be working just fine in my pipeline. Now I want to test it. So I create a function that mocks out sendSlack because I don't want my test to send a Slack message, I want to check to see if the arguments passed to sendSlack are the expected ones. So I did this:
void testStubbedSendNotifications(Map inputArgs, ArrayList slackArgs) {
def n = new Notifier()
def sendSlackArgs = []
n.metaClass.sendSlack = { Map x -> sendSlackArgs << x }
n.sendNotifications(inputArgs)
assert sendSlackArgs == slackArgs
}
What is happening here is simple. Instead of calling sendSlack, I'm pushing the arguments that would be called onto an ArrayList and then I check to make sure that list looks right in an assert. So this function takes arguments to call sendNotifications with as well as a list of expected values to see sendSlack being called with as a result.
The Problem
My expected values get mangled only in my tests. Instead of the arguments being a hash map like this:
[
failOnError: true,
color: '#00FF00',
message: "foo",
channel: "#mychan"
]
I instead get this:
[
failOnError: true,
color: '#00FF00',
"message:foo" : null,
channel: "#mychan"
]
Why does the message's key and value get merged into the key?

How do i pass named parameters (not all string values) to another job in Jenkins Pipeline?

I want to pass a bunch of parameters that are named, some of which are also Maps of named parameters into another job. The below does not work:
node
{
stage ('Deploying')
{
build job: 'job-runner',
serverSetup: [test: 'test'],
jobs: [
myJob: "true"
],
runType: [test: "test"]
}
}
I want the called job to be able to do all of the following:
parameters.serverSetup.test
if ( parameters.jobs.MyJob == true )
parameters.runtype.test
How would I do that?
With the build job function, you can pass parameters. Ex : build job: 'job-runner', parameters: [[$class: 'StringParameterValue', name: 'string1', value: param1], [$class: 'BooleanParameterValue', name: 'myJob', value: params.myJob]]

Resources