How to access parameters in a Parameterized Build? - jenkins

How do you access parameters set in the "This build is parameterized" section of a "Workflow" Jenkins job?
TEST CASE
Create a WORKFLOW job.
Enable "This build is parameterized".
Add a STRING PARAMETER foo with default value bar text.
Add the code below to Workflow Script:
node()
{
print "DEBUG: parameter foo = ${env.foo}"
}
Run job.
RESULT
DEBUG: parameter foo = null

I think the variable is available directly, rather than through env, when using Workflow plugin.
Try:
node()
{
print "DEBUG: parameter foo = ${foo}"
}

I tried a few of the solutions from this thread. It seemed to work, but my values were always true and I also encountered the following issue:
JENKINS-40235
I managed to use parameters in groovy jenkinsfile using the following syntax: params.myVariable
Here's a working example:
Solution
print 'DEBUG: parameter isFoo = ' + params.isFoo
print "DEBUG: parameter isFoo = ${params.isFoo}"
A more detailed (and working) example:
node() {
// adds job parameters within jenkinsfile
properties([
parameters([
booleanParam(
defaultValue: false,
description: 'isFoo should be false',
name: 'isFoo'
),
booleanParam(
defaultValue: true,
description: 'isBar should be true',
name: 'isBar'
),
])
])
// test the false value
print 'DEBUG: parameter isFoo = ' + params.isFoo
print "DEBUG: parameter isFoo = ${params.isFoo}"
sh "echo sh isFoo is ${params.isFoo}"
if (params.isFoo) { print "THIS SHOULD NOT DISPLAY" }
// test the true value
print 'DEBUG: parameter isBar = ' + params.isBar
print "DEBUG: parameter isBar = ${params.isBar}"
sh "echo sh isBar is ${params.isBar}"
if (params.isBar) { print "this should display" }
}
Output
[Pipeline] {
[Pipeline] properties
WARNING: The properties step will remove all JobPropertys currently configured in this job, either from the UI or from an earlier properties step.
This includes configuration for discarding old builds, parameters, concurrent builds and build triggers.
WARNING: Removing existing job property 'This project is parameterized'
WARNING: Removing existing job property 'Build triggers'
[Pipeline] echo
DEBUG: parameter isFoo = false
[Pipeline] echo
DEBUG: parameter isFoo = false
[Pipeline] sh
[wegotrade-test-job] Running shell script
+ echo sh isFoo is false
sh isFoo is false
[Pipeline] echo
DEBUG: parameter isBar = true
[Pipeline] echo
DEBUG: parameter isBar = true
[Pipeline] sh
[wegotrade-test-job] Running shell script
+ echo sh isBar is true
sh isBar is true
[Pipeline] echo
this should display
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
I sent a Pull Request to update the misleading pipeline tutorial#build-parameters quote that says "they are accessible as Groovy variables of the same name.". ;)
Edit: As Jesse Glick pointed out:
Release notes go into more details
You should also update the Pipeline Job Plugin to 2.7 or later, so that build parameters are defined as environment variables and thus accessible as if they were global Groovy variables.

When you add a build parameter, foo,
it gets converted to something which acts like a "bare variable",
so in your script you would do:
node {
echo foo
}
If you look at the implementation of the workflow script, you will see that when a script is executed, a class called WorkflowScript is
dynamically generated. All statements in the script are executed in the context of this class. All build parameters passed down to this script are converted to properties which are accessible from this class.
For example, you can do:
node {
getProperty("foo")
}
If you are curious, here is a workflow script I wrote which attempts to print out the build parameters, environment variables, and methods on the WorkflowScript class.
node {
echo "I am a "+getClass().getName()
echo "PARAMETERS"
echo "=========="
echo getBinding().getVariables().getClass().getName()
def myvariables = getBinding().getVariables()
for (v in myvariables) {
echo "${v} " + myvariables.get(v)
}
echo STRING_PARAM1.getClass().getName()
echo "METHODS"
echo "======="
def methods = getMetaClass().getMethods()
for (method in methods) {
echo method.getName()
}
echo "PROPERTIES"
echo "=========="
properties.each{ k, v ->
println "${k} ${v}"
}
echo properties
echo properties["class"].getName()
echo "ENVIRONMENT VARIABLES"
echo "======================"
echo "env is " + env.getClass().getName()
def envvars = env.getEnvironment()
envvars.each{ k, v ->
println "${k} ${v}"
}
}
Here is another code example I tried, where I wanted to test to see
if a build parameter was set or not.
node {
groovy.lang.Binding myBinding = getBinding()
boolean mybool = myBinding.hasVariable("STRING_PARAM1")
echo mybool.toString()
if (mybool) {
echo STRING_PARAM1
echo getProperty("STRING_PARAM1")
} else {
echo "STRING_PARAM1 is not defined"
}
mybool = myBinding.hasVariable("DID_NOT_DEFINE_THIS")
if (mybool) {
echo DID_NOT_DEFINE_THIS
echo getProperty("DID_NOT_DEFINE_THIS")
} else {
echo "DID_NOT_DEFINE_THIS is not defined"
}
}

Use double quotes instead of single quotes
e.g. echo "$foo" as opposed to echo '$foo'
If you configured your pipeline to accept parameters using the Build with Parameters option, those parameters are accessible as Groovy variables of the same name. See Here.
You can drop the semicolon (;), drop the parentheses (( and )), and use single quotes (') instead of double (") if you do not need to perform variable substitutions. See Here. This clued me into my problem, though I've found that only the double (") is required to make it work.

To parameter variable add prefix "params."
For example:
params.myParam
Don't forget: if you use some method of myParam, may be you should approve it in "Script approval".

You can also try using parameters directive for making your build parameterized and accessing parameters:
Doc:
Pipeline syntax: Parameters
Example:
pipeline{
agent { node { label 'test' } }
options { skipDefaultCheckout() }
parameters {
string(name: 'suiteFile', defaultValue: '', description: 'Suite File')
}
stages{
stage('Initialize'){
steps{
echo "${params.suiteFile}"
}
}
}

Hope the following piece of code works for you:
def item = hudson.model.Hudson.instance.getItem('MyJob')
def value = item.lastBuild.getEnvironment(null).get('foo')

The following snippet gives you access to all Job params
def myparams = currentBuild.rawBuild.getAction(ParametersAction)
for( p in myparams ) {
pMap[p.name.toString()] = p.value.toString()
}

Please note, the way that build parameters are accessed inside pipeline scripts (pipeline plugin) has changed. This approach:
getBinding().hasVariable("MY_PARAM")
Is not working anymore. Please try this instead:
def myBool = env.getEnvironment().containsKey("MY_BOOL") ? Boolean.parseBoolean("$env.MY_BOOL") : false

As per Pipeline plugin tutorial:
If you have configured your pipeline to accept parameters when it is built — Build with Parameters — they are accessible as Groovy variables of the same name.
So try to access the variable directly, e.g.:
node()
{
print "DEBUG: parameter foo = " + foo
print "DEBUG: parameter bar = ${bar}"
}

Related

How to use declared variables in when conditional step?

I am declaring a variable outside the pipeline tags and initializing in one of the stages inside script using readFile. When I try to use this declared variable inside when condition, the when condition always skips.
When I initialize the variable with var1='myValue' and check for
when{ expression{var1=='myValue'} } works .
I tried making the varible into environment variable but not else works
def test1=''
pipeline{
agent { label 'local'}
stages{
stage('initialization'){
steps{
sh """echo "myValue" > user_file
pwd
"""
script{
test1=readFile file: 'user_file
//env.TEST=readFile file: 'user_file', encoding: 'UTF-8' doesn't work
//test1='myValue' only this works
}
}
}
stage('test'){
when {
expression { return test1 == 'myValue'}
//environment name: 'TEST', value: 'myValue'
}
steps{
echo " user :${env.TEST}"
//this step always gets skipped because of when condition above
}
}
}
}
I expect the steps under when to run, but it gets skips every time.
As Matt commented on the question, I had a new line character in the file. The new line character was introduced by echo by default. I had to suppress it using the -n option from echo.
echo -n "myValue" > user_file
The above command only puts the value without the newline in the file
Sorry that my shell-foo is bad and didn't realize that echo puts in a new line by default.

Jenkinsfile ${steps.env.BUILD_NUMBER}: bad substitution

I am trying to print a variable in Jenkins. But I am getting an error saying "bad substitution". I am using Jenkinsfile to achieve that. This is what I am doing.
static def printbn() {
sh '''
#!/usr/bin/env bash
echo \"${env.BUILD_NUMBER}\"
'''
}
pipeline {
agent any
stages {
stage('Print Build Number') {
steps {
printbn()
}
}
}
}
Error that I am getting
/var/lib/jenkins/workspace/groovymethod#tmp/durable-7d9ef0b0/script.sh: line 4: ${steps.env.BUILD_NUMBER}: bad substitution
NOTE: I am using Jenkins version Jenkins ver. 2.163
In Shell, variable name is not allow use ., that's why you get following error: bad substitution
In Groovy, there are 4 ways to represent a string:
single quote: ' a string '
tripe single quote: ''' a string '''
double quote: " a string "
tripe double quote: """ a string """
And Groovy only execute string interpolation on double and triple double quote string.
For example:
def name = 'Tom'
print "Hello ${name}"
print """Hello ${name}"""
// do interpolation before print, thus get Hello Tom printed out
print 'Hello ${name}'
print '''Hello ${name}'''
//no interpolation thus, print Hello ${name} out directly.
BUILD_NUMBER is Jenkins job's build-in environment variable. You can directly access it in shell/bat.
static def printbn() {
sh '''
#!/usr/bin/env bash
echo ${BUILD_NUMBER}
// directly access any Jenkins build-in environment variable,
// no need to use pattern `env.xxxx` which only works in groovy not in shell/bat
'''
}
If you want use env.xxxx pattern, you can archive that via groovy string interpolation.
static def printbn() {
// use pipeline step: echo
echo "${env.BUILD_NUMBER}" // env.BUILD_NUMBER is groovy variable
// or use pipeline step: sh
sh """#!/usr/bin/env bash
echo ${env.BUILD_NUMBER}
"""
// will do interpolation firstly, to replace ${env.BUILD_NUMBER} with real value
// then execute the whole shell script.
}

Jenkins Pipeline Conditional Stage based on Environment Variable

I want to create a Jenkins (v2.126) Declarative syntax pipeline, which has stages with when() clauses checking the value of an environment variable. Specifically I want to set a Jenkins job parameter (so 'build with parameters', not pipeline parameters) and have this determine if a stage is executed.
I have stage code like this:
stage('plan') {
when {
environment name: ExecuteAction, value: 'plan'
}
steps {
sh 'cd $dir && $tf plan'
}
}
The parameter name is ExecuteAction. However, when ExecuteAction is set via a Job "Choice" parameter to: plan, this stage does not run. I can see the appropriate value is coming in via environment variable by adding this debug stage:
stage('debug') {
steps {
sh 'echo "ExecuteAction = $ExecuteAction"'
sh 'env'
}
}
And I get Console output like this:
[Pipeline] stage
[Pipeline] { (debug)
[Pipeline] sh
[workspace] Running shell script
+ echo 'ExecuteAction = plan'
ExecuteAction = plan
[Pipeline] sh
[workspace] Running shell script
+ env
...
ExecuteAction=plan
...
I am using the when declarative syntax from Jenkins book pipeline syntax, at about mid-page, under the when section, built-in conditions.
Jenkins is running on Gnu/Linux.
Any ideas what I might be doing wrong?
Duh! You need to quote the environment variable's name in the when clause.
stage('plan') {
when {
environment name: 'ExecuteAction', value: 'plan'
}
steps {
sh 'cd $dir && $tf plan'
}
}
I believe you need to use params instead of environment. Try the following:
when {
expression { params.ExecuteAction == 'plan' }
}

iterate over environment variables in Jenkins Pipeline Groovy [duplicate]

Given a jenkins build pipeline, jenkins injects a variable env into the node{}. Variable env holds environment variables and values.
I want to print all env properties within the jenkins pipeline. However, I do no not know all env properties ahead of time.
For example, environment variable BRANCH_NAME can be printed with code
node {
echo ${env.BRANCH_NAME}
...
But again, I don't know all variables ahead of time. I want code that handles that, something like
node {
for(e in env){
echo e + " is " + ${e}
}
...
which would echo something like
BRANCH_NAME is myBranch2
CHANGE_ID is 44
...
I used Jenkins 2.1 for this example.
According to Jenkins documentation for declarative pipeline:
sh 'printenv'
For Jenkins scripted pipeline:
echo sh(script: 'env|sort', returnStdout: true)
The above also sorts your env vars for convenience.
Another, more concise way:
node {
echo sh(returnStdout: true, script: 'env')
// ...
}
cf. https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#code-sh-code-shell-script
The following works:
#NonCPS
def printParams() {
env.getEnvironment().each { name, value -> println "Name: $name -> Value $value" }
}
printParams()
Note that it will most probably fail on first execution and require you approve various groovy methods to run in jenkins sandbox. This is done in "manage jenkins/in-process script approval"
The list I got included:
BUILD_DISPLAY_NAME
BUILD_ID
BUILD_NUMBER
BUILD_TAG
BUILD_URL
CLASSPATH
HUDSON_HOME
HUDSON_SERVER_COOKIE
HUDSON_URL
JENKINS_HOME
JENKINS_SERVER_COOKIE
JENKINS_URL
JOB_BASE_NAME
JOB_NAME
JOB_URL
You can accomplish the result using sh/bat step and readFile:
node {
sh 'env > env.txt'
readFile('env.txt').split("\r?\n").each {
println it
}
}
Unfortunately env.getEnvironment() returns very limited map of environment variables.
Why all this complicatedness?
sh 'env'
does what you need (under *nix)
Cross-platform way of listing all environment variables:
if (isUnix()) {
sh env
}
else {
bat set
}
Here's a quick script you can add as a pipeline job to list all environment variables:
node {
echo(env.getEnvironment().collect({environmentVariable -> "${environmentVariable.key} = ${environmentVariable.value}"}).join("\n"))
echo(System.getenv().collect({environmentVariable -> "${environmentVariable.key} = ${environmentVariable.value}"}).join("\n"))
}
This will list both system and Jenkins variables.
I use Blue Ocean plugin and did not like each environment entry getting its own block. I want one block with all the lines.
Prints poorly:
sh 'echo `env`'
Prints poorly:
sh 'env > env.txt'
for (String i : readFile('env.txt').split("\r?\n")) {
println i
}
Prints well:
sh 'env > env.txt'
sh 'cat env.txt'
Prints well: (as mentioned by #mjfroehlich)
echo sh(script: 'env', returnStdout: true)
The pure Groovy solutions that read the global env variable don't print all environment variables (e. g. they are missing variables from the environment block, from withEnv context and most of the machine-specific variables from the OS). Using shell steps it is possible to get a more complete set, but that requires a node context, which is not always wanted.
Here is a solution that uses the getContext step to retrieve and print the complete set of environment variables, including pipeline parameters, for the current context.
Caveat: Doesn't work in Groovy sandbox. You can use it from a trusted shared library though.
def envAll = getContext( hudson.EnvVars )
echo envAll.collect{ k, v -> "$k = $v" }.join('\n')
Show all variable in Windows system and Unix system is different, you can define a function to call it every time.
def showSystemVariables(){
if(isUnix()){
sh 'env'
} else {
bat 'set'
}
}
I will call this function first to show all variables in all pipline script
stage('1. Show all variables'){
steps {
script{
showSystemVariables()
}
}
}
The easiest and quickest way is to use following url to print all environment variables
http://localhost:8080/env-vars.html/
The answers above, are now antiquated due to new pipeline syntax. Below prints out the environment variables.
script {
sh 'env > env.txt'
String[] envs = readFile('env.txt').split("\r?\n")
for(String vars: envs){
println(vars)
}
}
Includes both system and build environment vars:
sh script: "printenv", label: 'print environment variables'
if you really want to loop over the env list just do:
def envs = sh(returnStdout: true, script: 'env').split('\n')
envs.each { name ->
println "Name: $name"
}
I found this is the most easiest way:
pipeline {
agent {
node {
label 'master'
}
}
stages {
stage('hello world') {
steps {
sh 'env'
}
}
}
}
You can get all variables from your jenkins instance. Just visit:
${jenkins_host}/env-vars.html
${jenkins_host}/pipeline-syntax/globals
ref: https://www.jenkins.io/doc/pipeline/tour/environment/
node {
sh 'printenv'
}
You can use sh 'printenv'
stage('1') {
sh "printenv"
}
another way to get exactly the output mentioned in the question:
envtext= "printenv".execute().text
envtext.split('\n').each
{ envvar=it.split("=")
println envvar[0]+" is "+envvar[1]
}
This can easily be extended to build a map with a subset of env vars matching a criteria:
envdict=[:]
envtext= "printenv".execute().text
envtext.split('\n').each
{ envvar=it.split("=")
if (envvar[0].startsWith("GERRIT_"))
envdict.put(envvar[0],envvar[1])
}
envdict.each{println it.key+" is "+it.value}
I suppose that you needed that in form of a script, but if someone else just want to have a look through the Jenkins GUI, that list can be found by selecting the "Environment Variables" section in contextual left menu of every build
Select project => Select build => Environment Variables

Jenkins Groovy script

I have a boolean parameter named MyTests as part of the build job. The job calls a Groovy script. I believe the particular code below is causing a problem within the script. Any idea on the proper way in Groovy to reference a boolean within an if statement.
stage("post_build") {
if (${params.MyTests}) {
my_code_block...
}
java.lang.NoSuchMethodError: No such DSL method '$' found among steps
Remove the ${...} and write param.MyTests directly. The ${...} should only be used when referencing a variable (or regular groovy/java expression) inside a string. So:
def foo = "bar"
echo foo
echo "Withing a string: ${foo}"
So in you're case:
stage("post_build") {
if (params.MyTests) {
my_code_block...
}
...
See Pipeline Syntax, Flow Control:
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
}
}
and JENKINS-27295:
I would say that it is a best practice to always use the params object if you want the ensure that the type is consistent. Referencing the parameter as either foo or env.foo returns the value as it was injected into an environment variable and will always be of type String.
properties([parameters([booleanParam(defaultValue: false, description: '', name: 'foo')])])
echo "foo: " + foo.getClass().toString()
echo "env.foo: " + env.foo.getClass().toString()
echo "params.foo: " + params.foo.getClass().toString()
returns:
[Pipeline] echo
foo: class java.lang.String
[Pipeline] echo
env.foo: class java.lang.String
[Pipeline] echo
params.foo: class java.lang.Boolean
[Pipeline]

Resources