Accessing parameters in Jenkins - jenkins

How do I access this variable in a shell script.
I have tried
echo params.$STATES;
echo $STATES;
Output for the first one is params. . Output for the second one is an empty string. The output I am expecting is the string I am passing when I build that job with parameters.

If you are using the 'Execute Shell' block in a Freestyle Project, you will need a $ (dollar sign) before the variable. Since you already tried this, there could be an issue not wrapping variable within {}
try echo ${STATES}
More info on curly braces around variables,
See: codeforester answer on usage of curly braces around shell variables
If you are using a Jenkinsfile without a shell block (valid in Scripted and Declarative)
Use dollar sign with double quotes
node(){
echo "$STATES"
}
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo "$STATES"
}
}
}
}
or without Double quotes and dollar sign
node(){
echo STATES
}
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo STATES
}
}
}
}
If you are using a Shell block in the Jenkinsfile pipeline, use
sh "echo $STATES" or sh "echo ${STATES}"
(as in the Freestyle Execute Shell block, Double quotes are needed for interpolation)
See
String interpolation in Jenkinsfiles
Handling parameters in Jenkinsfiles

Related

Bad substitution when passing parameter to shell script in Jenkinsfile

In a Jenkinsfile I'm attempting to set an environment variable by setting the stdOut of a shell script. The script contains an AWS command that returns an InstanceID:
stage('Set InstanceID') {
steps {
script {
env.IID = sh (script: 'scripts/get-node-id.sh "${params.ENVIRONMENT}" "${params.NODE}"', returnStdout: true).trim()
}
}
}
No matter what I do or how many backslashes I use to escape the quotes, nothing works. I get a bad substitution error. I've also tried without double quotes.
If I hardcode in the shell script arguments, it runs fine.
How do I get this working if I want to use the parameter values here?
Groovy (the language of the Jenkinsfile) and Bash share the same substitution syntax. As you're using single quotes in your example code, the Groovy substitution does not work (see https://groovy-lang.org/syntax.html#_single_quoted_string). So Bash will try to do the substitution, but does not know these variables as they are Jenkins parameter values.
So solve this you need to use double quotes for your script and escape the double quotes in it (or use singe quotes):
stage('Set InstanceID') {
steps {
script {
env.IID = sh (script: "scripts/get-node-id.sh \"${params.ENVIRONMENT}\" \"${params.NODE}\"", returnStdout: true).trim()
}
}
}
I managed to resolve this, the comment from #yong above was almost what I needed. I needed three lots of double quotes and to unquote the variables:
stage('Set InstanceID') {
steps {
script {
env.IID = sh (script: """scripts/get-node-id.sh ${params.ENVIRONMENT} ${params.NODE}""", returnStdout: true).trim()
}
}
}

How to access groovy variable from pipeline into shell script?

I've a global variable in pipeline say BACKUP_DIR_NAME and in shell script which is inside pipeline, I want to build path using it hence have following code -
BACKUP_DIR_NAME="10-04-2020"
pipeline {
agent any
stages {
stage('First') {
steps {
script {
sh '''
BACKUP_DIR_PATH="/home/oracle/SeleniumFramework/SeleniumResultsBackup/"$BACKUP_DIR_NAME"/"
echo "Directory path is "$BACKUP_DIR_PATH
'''
}
}
}
}
}
When executed this, I can see value of BACKUP_DIR_NAME is evaluated as empty. Could you please help me to correct above code?
You mix two types of variables in your sh step. In the first line, you are trying to access the Groovy variable and interpolate its value to construct shell variable. In the second line, you expect to access this shell variable.
To satisfy the first part, you need to use double quotes to construct a Groovy string that supports variables interpolation. To satisfy the second part, you need to escape \$ to prevent $BACKUP_DIR_PATH from being interpolated.
BACKUP_DIR_NAME="10-04-2020"
pipeline {
agent any
stages {
stage('First') {
steps {
script {
sh """
BACKUP_DIR_PATH="/home/oracle/SeleniumFramework/SeleniumResultsBackup/"$BACKUP_DIR_NAME"/"
echo "Directory path is "\$BACKUP_DIR_PATH
"""
}
}
}
}
}

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.
}

Defining a variable in shell script portion of Jenkins Pipeline

I'm trying to dynamically define a variable I use later in a some shell commands of my Jenkins pipeline and it's throwing an exception. I even tried to predefine the variable from an environment section to no avail. Is this a prohibited operation? My other variable myVar seems to work fine, but it's a constant through the pipeline.
pipeline {
agent any
environment {
py2Ana=""
myVar="ABCDE"
}
stages {
stage('Stage1') {
steps {
sh """
echo myVar=$myVar
echo Find Anaconda2 Python installation...
py2Ana=`which -a python | grep --max-count=1 anaconda2`
if [[ -z "$py2Ana" ]]; then
echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
exit 1 # terminate and indicate error
fi
"""
}
}
}
Exception
groovy.lang.MissingPropertyException: No such property: py2Ana for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:242)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:288)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:292)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.run(WorkflowScript:21)
As #jxramos stated, Jenkins is trying to resolve the variables in the script. It interprets any $string as a variable that needs substitution.
The solution is to escape the $ of the in-script variables, as follows:
pipeline {
agent any
stages {
stage('test stage'){
steps {
sh """#!/bin/bash
myvar=somevalue
echo "The value is \$myvar"
"""
}
}
}
}
There appears to be a variable substitution precedence that Jenkins enforces in a preprocessing step if you will. In other words there's no delayed expansion as one would find in the Windows batch file behavior with setlocal ENABLEDELAYEDEXPANSION. This explains what's going on, and here's the test pipeline I used to determine this:
pipeline {
agent any
environment {
py2Ana="DEFAULT"
}
stages {
stage('Stage1') {
steps {
sh """
echo py2Ana=$py2Ana
py2Ana=Initialized
echo py2Ana Initialized=$py2Ana
"""
}
}
}
}
This yields the following console output...
Started by user unknown or anonymous
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] node
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Stage1)
[Pipeline] sh
[TestPipeline] Running shell script
+ echo py2Ana=DEFAULT
py2Ana=DEFAULT
+ py2Ana=Initialized
+ echo py2Ana Initialized=DEFAULT
py2Ana Initialized=DEFAULT
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Another restriction that this poses is that you truly cannot use dynamic variables in the sh portion of the Jenkins declarative pipeline script since Jenkins will first attempt to resolve all variables before execution. Thus the following will always yield an error
sh """
for filename in /tmp/**; do
echo filename=$filename
done
"""
The error being...
groovy.lang.MissingPropertyException: No such property: filename for class: groovy.lang.Binding
One would need to define a script dynamically (after figuring out a way to escape the $ to write to file), or already have it in the source, to be executed.
The error itself seems really to be caused by the assignment of an empty string.
However: Do you really need that environment variable to be defined in the Jenkinsfile?
To me it looks like you just want to set and read the variable from within the shell script. But the way it's coded the if [[ -z "$py2Ana" ]]; then would never pick up the value set by the shell script - it would always want to use a property from the Jenkinsfile - which didn't work.
You could use if [[ -z "${env.py2Ana}" ]]; then for the if condition which would fix that error but it still would not pick up the value set by the previous line but always read the empty string set in the Jenkinsfile.
To solve this you could either enclose the string in single quotes for the whole string like (maybe you even want to get rid of the myVar then)...:
pipeline {
agent any
stages {
stage('Stage1') {
steps {
sh '''
echo Find Anaconda2 Python installation...
py2Ana=`which -a python | grep --max-count=1 anaconda2`
if [[ -z "$py2Ana" ]]; then
echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
exit 1 # terminate and indicate error
fi
'''
}
}
}
}
... or add a backslash right before $py2Ana like:
pipeline {
agent any
stages {
stage('Stage1') {
steps {
sh """
echo Find Anaconda2 Python installation...
py2Ana=`which -a python | grep --max-count=1 anaconda2`
if [[ -z "\$py2Ana" ]]; then
echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
exit 1 # terminate and indicate error
fi
"""
}
}
}
}
Either way without referencing env.py2Ana in the code I doubt the environment block in the Jenkinsfile still would make sense - that's why I removed it from the examples.
Just add a value to py2Ana
environment {
py2Ana="1234"
myVar="ABCDE"
}
It doesn't create the variable in environment if you pass a empty string :)

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

Resources