Usage of Global property in Pipeline job - jenkins

I want to use a global variable that I have created in my Jenkins Configuration as follow:
My question is: How can I use it in my Pipeline(aka workflow) job? I'm doing something like:
When I ran it, It displayed:
[Pipeline] node
Running on master in /opt/devops/jenkins_home/jobs/siman/jobs/java/jobs/demo-job/workspace
[Pipeline] {
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
groovy.lang.MissingPropertyException: No such property: PRODUCTION_MAILS for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:224)
Instead If I create a "Free Style Project" I can use the global property as follow without problems:
When I ran it, it display the value if I do some "echo" as follow:

This is how I achieved it:
node('master') {
echo "${env.PRODUCTION_MAILS}"
}

Or You could use
echo "This is the value: " + PRODUCTION_MAILS
That should work.

Related

How to use jenkins use environment variables in parameters in a Pipeline

I'm trying to use "JOB_BASE_NAME" jenkins environmental variable in a parameter's path in a pipeline script that gets set will building the project.
example: string(defaultValue: "/abc/test/workspace/test_${JOB_BASE_NAME}/sample", description: 'test', name: 'HOME')
but while executing the ${JOB_BASE_NAME} is not getting replaced by the value(jenkins job name). I'm unsure if I'm setting the jenkins environmental variable in the path of the parameter correctly.
thank you!
I have replicated your use case and it works for me. This is the section of code
node {
stage ('test') {
sh "echo ${HOME}"
}
}
and this is the output - (my Job name was stackoverflow)
[Pipeline] { (hide)
[Pipeline] stage
[Pipeline] { (test)
[Pipeline] sh
+ echo /abc/test/workspace/test_stackoverflow/sample
/abc/test/workspace/test_stackoverflow/sample
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Check the picture of how I set the String parameter.

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 :)

Jenkins: "Execute system groovy script" in a pipeline step (SCM committed)

Is there a way to use the Jenkins "Execute system groovy script" step from a pipeline file which is SCM commited ?
If yes, how would I access the predefined variables (like build) in it ?
If no, would I be able to replicate the functionality otherwise, using for example the Shared Library Plugin ?
Thanks !
You can put groovy code in a pipeline in a (always-source-controlled) Jenkinsfile, like this:
pipeline {
agent { label 'docker' }
stages {
stage ('build') {
steps {
script {
// i used a script block because you can jam arbitrary groovy in here
// without being constrained by the declarative Jenkinsfile DSL
def awesomeVar = 'so_true'
print "look at this: ${awesomeVar}"
// accessing a predefined variable:
echo "currentBuild.number: ${currentBuild.number}"
}
}
}
}
}
Produces console log:
[Pipeline] echo
look at this: so_true
[Pipeline] echo
currentBuild.number: 84
Click on the "Pipeline Syntax" link in the left navigation of any of pipeline job to get a bunch of examples of things you can access in the "Global Variables Reference."

Hiding password in Jenkins pipeline script

I'm trying to mask a password in my Jenkins build.
I have been trying the mask-passwords plugin.
However, this doesn't seem to work with my Jenkins pipeline script, because if I define the password PASSWD1 and then I use it in the script like this ${PASSWD1}, I am getting:
No such DSL method '$' found among steps [addToClasspath, ansiColor, ansiblePlaybook, ....]
If I use env.PASSWD1, then its value will be resolved to null.
So how should I mask a password in a Jenkins pipeline script?
The simplest way would be to use the Credentials Plugin.
There you can define different types of credential, whether it's a single password ("secret text"), or a file, or a username/password combination. Plus other plugins can contribute other types of credentials.
When you create a credential (via the Credentials link on the main Jenkins page), make sure you set an "ID". In the example below, I've called it my-pass. If you don't set it, it will still work, Jenkins will allocate an opaque UUID for you instead.
In any case, you can easily generate the required syntax with the snippet generator.
withCredentials([string(credentialsId: 'my-pass', variable: 'PW1')]) {
echo "My password is '${PW1}'!"
}
This will make the password available in the given variable only within this block. If you attempt to print the password, like I do here, it will be masked.
Looking at this issue, https://issues.jenkins-ci.org/browse/JENKINS-27392, you should be able to do the following:
node {
wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {
echo env['SECRET'];
}
}
However, if you look at the last comments in that issue it doesn't work, seems like a bug. However, if you know the secret and accidentally print int in the logs, the it is hidden, like this:
node {
wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: '123ADS', var: 'SECRET']]]) {
echo "123ADS";
}
}
This produces:
[Pipeline] node
Running on master in workspace/pl
[Pipeline] {
[Pipeline] wrap
[Pipeline] {
[Pipeline] echo
********
[Pipeline] }
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Regarding the error you are getting, No such DSL method '$' found among steps ..., I'm just guessing but you are probably using ${VAR} directly in the pipeline script, ${...} is only relevant inside strings in groovy.
EDIT:
Or you can use the Credentails Plugin and pipeline step withCredentials:
// Credential d389273c-03a0-45af-a847-166092b77bda is set to a string secret in Jenkins config.
node {
withCredentials([string(credentialsId: 'd389273c-03a0-45af-a847-166092b77bda', variable: 'SECRET')]) {
bat """
if ["${SECRET}"] == ["123ASD"] echo "Equal!"
""";
}
}
This results in:
[Pipeline] node
Running on master in workspace/pl
[Pipeline] {
[Pipeline] withCredentials
[Pipeline] {
[Pipeline] bat
[pl] Running batch script
workspace/pl>if ["****"] == ["****"] echo "Equal!"
"Equal!"
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Note that this plugin binds the variable directly to the closure and not the environment as the other, e.g. I can use the variable SECRET directly.

How to retrieve current workspace using Jenkins Pipeline Groovy script?

I am trying to get the current workspace of my Jenkins build using a Groovy pipeline script:
node('master') {
// PULL IN ENVIRONMENT VARIABLES
// Jenkins makes these variables available for each job it runs
def buildNumber = env.BUILD_NUMBER
def workspace = env.WORKSPACE
def buildUrl = env.BUILD_URL
// PRINT ENVIRONMENT TO JOB
echo "workspace directory is ${workspace}"
echo "build URL is ${env.BUILD_URL}"
}
It returns:
[Pipeline] Allocate node : Start
Running on master in /Users/Shared/Jenkins/Home/jobs/test/workspace
[Pipeline] node {
[Pipeline] echo
workspace directory is null
[Pipeline] echo
build URL is http://localhost:8080/job/test/5/
[Pipeline] } //node
[Pipeline] Allocate node : End
[Pipeline] End of Pipeline
Finished: SUCCESS
For me just ${WORKSPACE} worked without even initializing the variable workspace.
There is no variable included for that yet, so you have to use shell-out-read-file method:
sh 'pwd > workspace'
workspace = readFile('workspace').trim()
Or (if running on master node):
workspace = pwd()
I think you can also execute the pwd() function on the particular node:
node {
def PWD = pwd();
...
}
A quick note for anyone who is using bat in the job and needs to access Workspace:
It won't work.
$WORKSPACE https://issues.jenkins-ci.org/browse/JENKINS-33511 as mentioned here only works with PowerShell. So your code should have powershell for execution
stage('Verifying Workspace') {
powershell label: '', script: 'dir $WORKSPACE'
}
I have successfully used as shown below in Jenkinsfile:
steps {
script {
def reportPath = "${WORKSPACE}/target/report"
...
}
}
This is where you can find the answer in the job-dsl-plugin code.
Basically you can do something like this:
readFileFromWorkspace('src/main/groovy/com/groovy/jenkins/scripts/enable_safehtml.groovy')
In Jenkins pipeline script, I am using
targetDir = workspace
Works perfect for me. No need to use ${WORKSPACE}
The key is that, this works if used within double quotes instead of single quotes, below is my code and this worked!
script {
echo 'Entering Stage - Nexus Upload'
def artefactPath = "${WORKSPACE}/build/deploy/identityiq.war"
echo "printing the path ${artefactPath}"
}

Resources