Jenkins Pipeline Choices attributes - jenkins

I was under the impression that the Jenkins pipeline choices syntax supported only a static newline-separated list of options and does not currently support dynamic population as the result of a groovy function (returning a map, say).
However, doing some reading on .net core I found this post.
I was particularly interested in a section of one of the pipeline code extracts:
parameters {
choice(choices: services, description: 'Name of the ECS service to deploy', name: 'serviceName')
choice(choices: services, description: 'Name of Docker image to update', name: 'imageName')
string(defaultValue: 'Tag to deploy', description: 'Docker image tag', name: 'tag')
}
Where and how does the services variable get set / populated?
What is services type? Is it a map of some sort (value and description)?
Thanks in advance.

The services variable here is most probably either a string with newlines (services = "choice a/nchoice b") or a list (services = ["choice a", "choice b"]. Both work these days.
I think you can set the variable in the environment directive and then use it in parameters [in deed the environment version does not work] or (probably evil) outside of the pipeline:
List<String> CHOICES = ["a", "b", "c"]
pipeline {
agent any
options {
timestamps()
}
parameters {
choice(name: 'CHOICE', choices: CHOICES, description: 'Who to greet?')
}
stages {
stage("test") {
steps {
echo params.CHOICE
}
}
}
}
I once used this to get all labels of a Docker images on our registry, to choose which one should be deployed. There are multiple issues with this:
This is AFAIK completely undocumented, so it might just eventually stop working.
The code is executed every when the Jenkinsfile is read. It configures the job, so the parameters are changed for the next build. So in my case, I only got the labels which were existing during the last build, not the currently existing ones.

Related

How can I reference my constant within a Jenkins Parameter?

I have the following code in a Pipelineconstant.groovy file:
public static final list ACTION_CHOICES = [
N_A,
FULL_BLUE_GREEN,
STAGE,
FLIP,
CLEANUP
]
and this PARAMETERS in Jenkins multi-Rapper-file:
parameters {
string (name: 'ChangeTicket', defaultValue: '000000', description : 'Prod change ticket otherwise 000000')
choice (name: 'AssetAreaName', choices: ['fpukviewwholeof', 'fpukdocrhs', 'fpuklegstatus', 'fpukbooksandjournals', 'fpukleglinks', 'fpukcasesoverview'], description: 'Select the AssetAreaName.')
/* groovylint-disable-next-line DuplicateStringLiteral */
choice (name: 'AssetGroup', choices: ['pdc1c', 'pdc2c'])
}
I would like to ref ACTION_CHOICES in the parameter as this:
choice (name: 'Action', choices: constants.ACTION_CHOICES, description: 'Multi Version deployment actions')
but it doesn't work for me.
I tried to do this:
choice (name: 'Action', choices: constants.ACTION_CHOICES, description: 'Multi Version deployment actions')
but it doesn't work for me.
You're almost there! Jenkinsfile(s) can be extended with variables / constants defined (directly in your file or (better I'd say) from a Jenkins shared library (this scenario).
The parameter syntax within you pipeline was fine as well as the idea of lists of constants, but what was missing: a proper interlink of those parts together - proper library import. See example below (the names below in the example are not carved in stone and can be of course changed but watch out - Jenkins is quite sensitive about filenames, paths, ... (especially in shared libraries]):
Pipelineconstant.groovy should be placed in src/org/pipelines of your Jenkins shared library.
Pipelineconstant.groovy
package org.pipelines
class Pipelineconstant {
public static final List<String> ACTION_CHOICES = ["N_A", "FULL_BLUE_GREEN", "STAGE", "FLIP", "CLEANUP"]
}
and then you can reference this list of constants within your Jenkinsfile pipeline.
Jenkinsfile
#Library('jsl-constants') _
import org.pipelines.Pipelineconstant
pipeline {
agent any
parameters {
choice (name: 'Action', choices: Pipelineconstant.ACTION_CHOICES , description: 'Multi Version deployment actions')
}
// rest of your pipeline code
}
The first two lines of the pipeline are important - the first loads the JSL itself! Therefore the second line of that import can be used (otherwise Jenkins would not know where find that Pipelineconstant.groovy file.
B) Without Jenkins shared library (files in one repo):
I've found this topic discussed and solved for scripted pipeline here: Load jenkins parameters from external groovy file

Dynamic assignment of values as default parameters in Jenkinsfile

Whenever I run this pipeline in Jenkins I have to manually copy-paste some values from a YAML file in a remote Gitlab repository. What I would like to achieve is an auto-fill of the values that .
This is how my Jenkinsfile and the YAML look like:
Jenkinsfile
pipeline {
agent {
docker {
image 'artifactory...'
args "..."
}
}
parameters {
string(name: 'BACKEND_TAG_1', defaultValue: '', description: 'Tag...')
string(name: 'BACKEND_TAG_2', defaultValue: '', description: 'Tag...')
}
stage('prepare') {
steps {
script {
dir('application') {
git url: env.PIPELINE_APPLICATION_GIT_URL, branch: env.PIPELINE_APPLICATION_GIT_BRANCH
}
Values = readYaml file: 'application/values.yaml'
values.yaml
version:
default: 0.1.2
company_tag_1: 0.1.124
company_tag_2: 0.1.230
So I need to loop into the parameters and assign the corresponding values:
Values.each { Value ->
Value.version.minus('company')
/* This value should be assigned to the corresponding parameter BACKEND_TAG_* parameter.
e.g.: BACKEND_TAG_1.default=company_tag_1
BACKEND_TAG_2.default=company_tag_2
*/
}
Reading the YAML works fine but I don't know how to proceed in the assignment of the values.
I presume you would like to populate all parameters before click Build button. I mean after clicking "Build with Parameters" button, you basically would like to see your parameters are populated from your YAML file.
If this is the case You can use Active Choice Parameter or Extended Choice Parameter plugins for this purpose. These Plugins are able to run Groovy Script, so you can develop a small Groovy Script read and select parameters automatically.

How to use multiple choices to run a job?

I have created a jenkins pipleine to run a job (e.g. Pipeline A runs job B). Within job B there is multiple parameters. One of the parameters is a choice parameter that has multiple different choices. I need pipeline A to run job B with all of the different choices at once (Pipeline A runs Job B with all of the different choices in one build). I am not too familiar with using the Jenkins declarative syntax but I am guessing I would use some sort of for loop to iterate over all of the available choices?
I have searched and searched through Stack overflow/google for an answer but have not had much luck.
You can define the options in a separate file outside your jobs, in shared library:
// vars/choices.groovy
def my_choices = [
"Option A",
"Option B", // etc.
]
You can then use these choices when defining the job:
// Job_1 Jenkinsfile
#Library('my-shared#master') _
properties([
parameters([
[$class: 'ChoiceParameterDefinition',
name: 'MY_IMPORTANT_OPTION',
choices: choices.my_choices as List,
description: '',
],
...
pipeline {
agent { any }
stages {
...
In Job 2, you can iterate over the values:
// Job_2 Jenkinsfile
#Library('my-shared#master') _
pipeline {
agent { any }
stages {
stage {
for (String option : choices.my_choices) {
build job: "Job_1",
wait: false,
parameters: [ string(name: 'MY_IMPORTANT_OPTION', value: option) , // etc.
]
Job_2 when it is run will asynchronously trigger a number of runs of Job_1 each time with a different parameter.

How can I parameterize Jenkinsfile jobs

I have Jenkins Pipeline jobs, where the only difference between the jobs is a parameter, a single "name" value, I could even use the multibranch job name (though not what it's passing as JOB_NAME which is the BRANCH name, sadly none of the envs look suitable without parsing). It would be great if I could set this outiside of the Jenkinsfile, since then I could reuse the same jenkinsfile for all the various jobs.
Add this to your Jenkinsfile:
properties([
parameters([
string(name: 'myParam', defaultValue: '')
])
])
Then, once the build has run once, you will see the "build with parameters" button on the job UI.
There you can input the parameter value you want.
In the pipeline script you can reference it with params.myParam
Basically you need to create a jenkins shared library example name myCoolLib and have a full declarative pipeline in one file under vars, let say you call the file myFancyPipeline.groovy.
Wanted to write my examples but actually I see the docs are quite nice, so I'll copy from there. First the myFancyPipeline.groovy
def call(int buildNumber) {
if (buildNumber % 2 == 0) {
pipeline {
agent any
stages {
stage('Even Stage') {
steps {
echo "The build number is even"
}
}
}
}
} else {
pipeline {
agent any
stages {
stage('Odd Stage') {
steps {
echo "The build number is odd"
}
}
}
}
}
}
and then aJenkinsfile that uses it (now has 2 lines)
#Library('myCoolLib') _
evenOrOdd(currentBuild.getNumber())
Obviously parameter here is of type int, but it can be any number of parameters of any type.
I use this approach and have one of the groovy scripts that has 3 parameters (2 Strings and an int) and have 15-20 Jenkinsfiles that use that script via shared library and it's perfect. Motivation is of course one of the most basic rules in any programming (not a quote but goes something like): If you have "same code" at 2 different places, something is not right.
There is an option This project is parameterized in your pipeline job configuration. Write variable name and a default value if you wish. In pipeline access this variable with env.variable_name

How to access all nodes from NodeParameterDefinition in jenkins pipeline?

I'm writing a Jenkinsfile that use the NodeLabel Parameter Plugin for jenkins. Here I use the NodeParameterDefinition to give the user the ability to select nodes where the build should happen. I have enabled allowMultiSelectionForConcurrentBuilds, but I only still get a string with only one node name when accessing the parameter value in the Jenkinsfile. The parameter value type is also a string, how can I get all the nodes the user selected for the parameter?
paramter definition:
[
$class: 'NodeParameterDefinition',
allowedSlaves: ['ALL (no restriction)'],
defaultSlaves: ['master'],
description: 'What nodes to run the build on.',
name: 'BUILD_NODE',
nodeEligibility: [$class: 'AllNodeEligibility'],
triggerIfResult: 'allowMultiSelectionForConcurrentBuilds'
]
So if I select multiple nodes when executing, I still only get one node name when accessing this parameter value.
echo "Will build on $BUILD_NODE";
Is multi node selection was enabled not possible with pipeline scripts?
How I access the parameter value:
echo "Will build on $BUILD_NODE";
node("$BUILD_NODE")
{
...
}
NodeLabel Parameter Plugin doesn't work smoothly with Pipeline and Blue Ocean, just as it is not updated frequently (see the revision history). Jenkins Plugins must follow requirements in order to be compatible with Pipeline.
Unfortunately the issue is still unresolved (unknown when it will be resolved):
https://issues.jenkins-ci.org/browse/JENKINS-43720
The problem is that I can not use env.NODE_PARAM or NODE_PARAM to get
multiple selection of nodes, as those are only a string representation
of a single node.
You can vote for this jira-task JENKINS-43720 (click "Vote for this issue"), or participate in the plugin development.
So far I found my clumsy way to imitate the plugin behavior by using another parameter option choice (but this works in Blue Ocean!):
properties([
parameters([
choice(choices: ["none", "node_1", "node_2"], description: "", name: "NODE_1"),
choice(choices: ["none", "node_1", "node_2"], description: "", name: "NODE_2")
])
])
// here you can write your behaviour
// e.g. validation of params, e.g. if 'none' is selected, then use the default node_X
node(env.NODE_1) { }
node(env.NODE_2) { }
or you can use the option string:
properties([
parameters([
string(defaultValue: "node_1, node_2", description: "", name: "NODE", trim: false)
])
])
// parse here the param env.NODE

Resources