Jenkins, Multibranch Pipeline: how to iterate params map - jenkins

I have a multibranch pipeline in Jenkins.
I defined multiple check boxes (over 20) for each parameter to be passed to a script, which then starts my application and runs corresponding test case (this might not be an optimal solution but this framework was created before I started at current company and I am not going to refactor it):
booleanParam(name: 'cluster_number', defaultValue: false, description: '')
booleanParam(name: 'post_cluster_wu', defaultValue: false, description: '')
etc.
I need to collect user selection for each checkbox (true-false). I would prefer to do it in a loop, like this:
sh """
for (element in params) {
// testing:
echo "${element.key} ${element.value}"
}
"""
but keep getting an error:
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: element for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:264)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:288)
Also tried to put loop outside of shell script. No luck so far.
steps {
echo "username: ${params.OWNER_USERNAME}"
for (element in params) {
echo "${element.key} ${element.value}"
}
...
Wonder if anyone was able to loop through params?
Thanks in advance!

This works:
pipeline {
agent any
parameters {
booleanParam(name: 'alpha', defaultValue: true)
booleanParam(name: 'beta', defaultValue: true)
booleanParam(name: 'gamma', defaultValue: false)
}
stages {
stage('only') {
steps {
script {
params.keySet().each {
echo "The value of the ${it} parameter is: ${params[it]}"
}
}
}
}
}
}

Related

Re-run a pipeline using script jenkins

I have a pipeline with some information detailed behind
pipeline {
parameters {
booleanParam(name: 'RERUN', defaultValue: false, description: 'Run Failed Tests')
}
stage('Run tests ') {
steps {
runTest()
}
}
post {
always {
reRun()
}
}
}
def reRun() {
if ("SUCCESS".equals(currentBuild.result)) {
echo "LAST BUILD WAS SUCCESS"
} else if ("UNSTABLE".equals(currentBuild.result)) {
echo "LAST BUILD WAS UNSTABLE"
}
}
but I want that after the stage "Run tests" execute, if some tests fail I want to re-run the pipeline with parameters RERUN true instead of false. How can I replay via script instead of using plugins ?
I wasn't able to find how to re-run using parameters on my search, if someone could help me I will be grateful.
First of you can use the post step to determine if the job was unstable:
post{
unstable{
echo "..."
}
}
Then you could just trigger the same job with the new parameter like this:
build job: 'your-project-name', parameters: [[$class: 'BooleanParameterValue', name: 'RERUN', value: Boolean.valueOf("true")]]

How to run call a sharedlibrary pipeline inside another pipline?

I've written a pipeline as a shared library and I would like to call as one of the stage of master pipeline, but I am getting an error that probably node is not defined. What is the best approach for that? In second case I rewrite sharedTest as a standard pipe line and use "build job" instead of call a shared library, but in that I am repeating a code in some places.
So generally I would like to have:
sharedTest as a independed pipeline but also reusing it in some places, so first one is simple because I can create a separate pipeline where I am importing lib and then calling such lib method. The problem is when I would like to use a shared pipeline as a stage of master piple.
sharedTest.groovy :
def call() {
pipeline{
agent {
label "ansirobotSpy3-devel"
}
parameters {
choice(name: 'TEST', choices: ['bts1', 'bts2'], description: '')
string(name: 'PATH', defaultValue: '/bts1/, description: '')
}
environment {
HTTPS_PROXY = 'http://1.1.1.1'
HTTP_PROXY = 'http://1.1.1.1'
}
stages{
stage('Test stage'){
steps{
script {
sh "ls -lart ./*"
installPyLibs('pytest')
}
}
}
}
}
}
master pipeline:
...
stage("tests"){
agent none
options {
skipDefaultCheckout()
}
when{
beforeAgent true
allOf{
not { expression { currentBuild.result == 'ABORTED' } }
not { expression { SharedTest == 'true' } }
}
}
steps {
script {
stage ("Seek && Destoy") {
sharedTest()
}
stage ("Deploy") {
def deploy = build job: 'Deploy',
parameters: [
string(name: 'BUILD_NUMBER', value: "${env.NEW_BUILD_NR_VAR}")
], wait: true, propagate: false
}
...
From my experience Jenkins doesn't allow using shared libraries locally. I did a workaround registering my shared library this way:
library identifier: 'LIBRARYNAME#BRANCH',
retriever: modernSCM([$class: 'GitSCMSource',
credentialsId: 'CREDENTIALS_FROM_JENKINS',
id: 'GUID',
remote: 'CLONE_LINK_TO_GIT_REPO',
traits: [[$class: 'jenkins.plugins.git.traits.BranchDiscoveryTrait']]])
This also can be achieved using UI and registering the library. More on that here: https://www.jenkins.io/doc/book/pipeline/shared-libraries/
As for the code - I assume your pipeline is inside vars folder in your repository. (details about this here: folder structure) .This way they will be accessible during the pipeline.
Let's assume I have file vars/internalStepTestEcho.groovy. After loading a library this can be accessed using:
internalStepTestEcho()

How to configure dynamic parameters in declarative pipeline (Jenkinsfile)?

Using the declarative pipeline syntax, I want to be able to define parameters based on an array of repos, so that when starting the build, the user can check/uncheck the repos that should not be included when the job runs.
final String[] repos = [
'one',
'two',
'three',
]
pipeline {
parameters {
booleanParam(name: ...) // static param
// now include a booleanParam for each item in the `repos` array
// like this but it's not allowed
script {
repos.each {
booleanParam(name: it, defaultValue: true, description: "Include the ${it} repo in the release?")
}
}
}
// later on, I'll loop through each repo and do stuff only if its value in `params` is `true`
}
Of course, you can't have a script within the parameters block, so this won't work. How can I achieve this?
Using the Active Choices Parameter plugin is probably the best choice, but if for some reason you can't (or don't want to) use a plugin, you can still achieve dynamic parameters in a Declarative Pipeline.
Here is a sample Jenkinsfile:
def list_wrap() {
sh(script: 'echo choice1 choice2 choice3 choice4 | sed -e "s/ /\\n/g"', , returnStdout: true)
}
pipeline {
agent any
stages {
stage ('Gather Parameters') {
steps {
timeout(time: 30, unit: 'SECONDS') {
script {
properties([
parameters([
choice(
description: 'List of arguments',
name: 'service_name',
choices: 'DEFAULT\n' + list_wrap()
),
booleanParam(
defaultValue: false,
description: 'Whether we should apply changes',
name: 'apply'
)
])
])
}
}
}
}
stage ('Run command') {
when { expression { params.apply == true } }
steps {
sh """
echo choice: ${params.service_name} ;
"""
}
}
}
}
This embeds a script {} in a stage, which calls a function, which runs a shell script on the agent/node of the Declarative Pipeline, and uses the script's output to set the choices for the parameters. The parameters are then available in the next stages.
The gotcha is that you must first run the job with no build parameters in order for Jenkins to populate the parameters, so they're always going to be one run out of date. That's why the Active Choices Parameter plugin is probably a better idea.
You could also combine this with an input command to cause the pipeline to prompt the user for a parameter:
script {
def INPUT_PARAMS = input message: 'Please Provide Parameters', ok: 'Next',
parameters: [
choice(name: 'ENVIRONMENT', choices: ['dev','qa'].join('\n'), description: 'Please select the Environment'),
choice(name: 'IMAGE_TAG', choices: getDockerImages(), description: 'Available Docker Images')]
env.ENVIRONMENT = INPUT_PARAMS.ENVIRONMENT
env.IMAGE_TAG = INPUT_PARAMS.IMAGE_TAG
}
Credit goes to Alex Lashford (https://medium.com/disney-streaming/jenkins-pipeline-with-dynamic-user-input-9f340fb8d9e2) for this method.
You can use CHOICE parameter of Jenkins in which user can select a repository.
pipeline {
agent any
parameters
{
choice(name: "REPOS", choices: ['REPO1', 'REPO2', 'REPO3'])
}
stages {
stage ('stage 1') {
steps {
// the repository selected by user will be printed
println("$params.REPOS")
}
}
}
}
You can also use the plugin Active Choices Parameter if you want to do multiple select : https://plugins.jenkins.io/uno-choice/#documentation
You can visit pipeline syntax and configure in below way to generate code snippet and you can put it in the jenkins file:
Copy the snippet code and paste it in jenkinsfile at the start.

Jenkins parameterized input in stage

I know how to request for the user input for the whole pipeline using parameters directive. Now i want to be able to request for the user input inside a specific stage and be able to access that value inside the stage. Here's my pipeline:
pipeline {
agent none
stages {
stage('Stage 1') {
when{
beforeAgent true
expression {
timeout (time: 30, unit: "SECONDS"){
input message: 'Should we continue?', ok: 'Yes',
parameters:[[
$class: 'ChoiceParameterDefinition',
choices: ['Stable release', 'SNAPSHOT'],
description: 'Which Version?',
name: 'version'
]]
}
return true
}
}
agent any
steps {
echo 'Checking dependencies ...'
echo "${params}"
}
}
}
}
In this pipeline I'm able to prompt the user to choose between Stable release and SNAPSHOT inside Stage 1 stage. However I'm not able to access this variable using ${params.version}. Any ideas how to solve this?
I managed to work around the problem and read the input chosen by user as in the following pipeline:
def version //define a global variable for the whole pipeline.
pipeline {
agent none
stages {
stage('Stage 1') {
when{
beforeAgent true
expression {
timeout (time: 30, unit: "SECONDS"){
//Assign the variable here.
version = input message: 'Should we continue?', ok: 'Yes',
parameters:[[
$class: 'ChoiceParameterDefinition',
choices: ['Stable release', 'SNAPSHOT'],
description: 'Which Version?',
name: 'v'
]]
}
return true
}
}
agent any
steps {
// And finally access it.
echo "${version}"
}
}
}
}

Jenkins Pipeline passing parameter as shell script argument

I have a parameterized Jenkins Pipeline with a default value and I'm trying to pass that param as a script argument but it doesn't seem to pass anything. Here is the script :
pipeline {
agent any
stages {
stage('Building') {
steps {
build job: 'myProject', parameters: [string(name: 'configuration', value: '${configuration}')]
}
}
stage('Doing stuff') {
steps {
sh "~/scripts/myScript ${configuration}"
}
}
}
}
It seems to work for the build step but not for the script. I returns an error saying I have no argument.
I tried to get it with ${configuration}, ${params.configuration} and $configuration.
What is the right way to access a param and pass it correctly to a script ?
Thanks.
Actually, you are using the build step, to pass a parameter to the Jenkins job 'myProject'.
build job: 'myProject', parameters: [string(name: 'configuration', value: '${configuration}')]
If you want to declare a Parameter in this job you need to declare your parameter in a "parameters" block.
pipeline {
agent any
parameters {
string(defaultValue: '', description: '', name: 'configuration')
}
stages {
stage('Doing stuff') {
steps {
sh "~/scripts/myScript ${configuration}"
}
}
}
}

Resources