Passing parameter from for loop to multiline sh in jenkins pipeline - jenkins

I have groovy jenkins pipeline step and I want to pass for loop value as parameter to multiline sh script in loop. But parameter is not getting passed.
Or if theres a better way to add step in jenkins stage?
for (int i = 0; i < elements.size(); i++) {
sh '''
cd terraform/
terraform init
terraform workspace select ${elements[i]}-${envtype}
terraform plan -var-file="./configs/${elements[i]}/var.tf"
'''
}

It seems that you should use """ instead of '''. ''' is triple single quoted String and doesn't support interpolation.

You need a triple double quoted string. You are using a triple single quoted string. Any single quoted string in Groovy does not feature String interpolation, so '''${i}''' prints ${i}, while """${i}""" prints 3 (if i = 3).

Related

Understanding Jenkins Groovy scripted pipeline code

I am looking at a Jenkins Scripted Pipeline tutorial here https://www.jenkins.io/blog/2019/12/02/matrix-building-with-scripted-pipeline/ and found that I need to learn some Groovy to understand this.
I have been reading through Groovy documentation, but still and not understanding all of this code. I will list the areas of question.
1
List getMatrixAxes(Map matrix_axes) {
List axes = []
matrix_axes.each { axis, values ->
List axisList = []
values.each { value ->
axisList << [(axis): value]
}
axes << axisList
}
// calculate cartesian product
axes.combinations()*.sum()
}
In most of the Groovy documentation I have seen, it defines lists such as List axes = []. The syntax above looks more like a function which would return a List. If this is what this is, I don't see any return statement inside the curly brackets, which just confuses me.
2
node(nodeLabel) {
withEnv(axisEnv) {
stage("Build") {
echo nodeLabel
sh 'echo Do Build for ${PLATFORM} - ${BROWSER}'
}
stage("Test") {
echo nodeLabel
sh 'echo Do Build for ${PLATFORM} - ${BROWSER}'
}
}
}
I have seen this concept of node in Groovy scripts before, somethings with the parameter section, ie: node(nodelabel) {...} and sometimes without, ie: node {...}. Is this core Groovy or somehow something specific to Jenkins? What does it mean and where can I find documentation about it?
getMatrixAxes is a function. In Groovy return statement is optional. If you don't explicitly return something in a function, the last expression evaluated in the body of a method or a closure is returned. In your case, the output generated by the axes.combinations()*.sum() will be returned. In the example, it's generating a List. You can read more from here.
These constructs are something specific to Jenkins. Specifically the mentioned syntax is from Jenkins Scripted Pipeline Syntax. node {...} Simply means run on any agent. node(nodelabel) {...} means run on the agent with the label nodelabel. Jenkins has a new Job DSL called Declarative syntax which is preferred over Scripted Syntax. You can read more about both here.

Jenkins scripted pipeline nested environment variable

I'm using the Jenkins scripted pipeline and having trouble understanding how to nest environment variables within each other, here is a MWE:
// FROM https://jenkins.io/doc/pipeline/examples/#parallel-multiple-nodes
def labels = []
if (HOST == 'true') {
labels.add(<HOSTNAME>)
}
def builders = [:]
for (x in labels) {
def label = x
builders[label] = {
ansiColor('xterm') {
node(label) {
stage('cleanup') {
deleteDir()
}
stage('build') {
env.test = "TESTA"
env.intern = '''
TEST = "${env.test}"
'''
sh '''
echo $intern
printenv
'''
}
}
}
}
}
parallel builders
The idea here is that env.test contains the value TESTA, which sets env.intern to TEST = TESTA this is what I want to happen. After this the code is just to print out the values.
Sadly the result is TEST = "${env.test}".
How can I use nested string environment variables in Jenkins scripted pipeline?
The syntax difference here is literal strings versus interpolated strings in Groovy versus shell interpreters within shell step methods.
": interpolated string in Groovy
': literal string in Groovy and interpolated string in shell interpreter
Essentially, a Groovy variable is interpolated within " in the pipeline execution, and an environment variable is interpolated within " in the pipeline execution and within ' in the shell interpreter (and within the pipeline must also be accessed within the env object, but is a first class variable expression in the shell step method).
Therefore, we can fix the assigned value of env.intern with:
env.intern = "TEST = ${env.test}"
where the assigned value of env.test will be interpolated within the Groovy string and assigned to the env pipeline object at the intern key. This will then also be accessible to the shell interpreter within shell step methods, and the rest of your pipeline is already correct and will behave as expected.
Try the following:
env.intern = "TEST = ${env.test}"
As you're setting it now, the actual result of env.intern will be "TEST= ${env.test}". So long as you set env.test before you set env.intern you should be good. Also, good to note that if you change the value of env.test then you need to reset the value of env.intern or it's going to hold the original value of env.test that it was set to.

How to run a conditional in Jenkins to fail based on output from a previous stage

Below is a basic construct I built to present my question.
stage('Run pre-checks') {
steps {
//Run pre-check scripts
}
}
stage('Deploy config ') {
when {
expression {
//Insert expression here
}
}
steps {
//Run a script
}
}
Based on the construct below, what I am trying to do is to run a specific script only when a specific output from the “run pre-checks” script is displayed on the stdout of that stage, which will be a python script. If the pre-check shows this output, you will skip the second step rather than running it. Would anyone know the environment variable(s) and/or Methods that would be able to do this?
Sh command can return a value instead of printing it.
MY_OUTPUT = sh (
script: '... your command....',
returnStdout: true
)
Then you can do whatever you want with MY_OUTPUT (trim(), substr...)
The current link to the documentation is here (Sh shell script) :
returnStdout (optional)
If checked, standard output from the task is returned as the step value as a String, rather than being printed to the build log. (Standard error, if any, will still be printed to the log.) You will often want to call .trim() on the result to strip off a trailing newline.
Type: boolean

obtaining groovy value from map given computed key for jenkins?

Given the map:
def mymap = ["first":"aaa", "second":"bbb", "third":"ccc"]
I would like to get the value for a key where the key is a parameter of the Jenkins job that runs this Groovy script.
I have tried a number of methods similar to
sh "echo the value is ${mymap.${paramValue}}"
but this is throwing the error
" unclassified method java.util.LinkedHashMap"
the way to fix this was to separate out getting the value from the map and feeding that value into the next step.
def value = mymap."${paramValue}"
sh "echo the value is ${value}"
You can use the get method:
sh "echo the value is ${mymap.get(paramValue)}"

Dynamic variable in Jenkins pipeline with groovy method variable

I have a Jenkinsfile in Groovy for a declarative pipeline and two created Jenkins variables with names OCP_TOKEN_VALUE_ONE and OCP_TOKEN_VALUE_TWO and the corresponding values. The problem comes when I try to pass a method variable and use it in an sh command.
I have the next code:
private def deployToOpenShift(projectProps, environment, openshiftNamespaceGroupToken) {
sh """/opt/ose/oc login ${OCP_URL} --token=${openshiftNamespaceGroupToken} --namespace=${projectProps.namespace}-${environment}"""
}
The problem is, the method deployToOpenShift has in the openshiftNamespaceGroupToken variable, a value that is the name of variable that has been set in Jenkins. It needs to be dynamic and the problem is that Jenkins don't resolve the Jenkins variable value, just the one passed as String, I mean, the result is:
--token=OCP_TOKEN_VALUE_ONE
If I put in the code
private def deployToOpenShift(projectProps, environment, openshiftNamespaceGroupToken) {
sh """/opt/ose/oc login ${OCP_URL} --token=${OCP_TOKEN_VALUE_ONE} --namespace=${projectProps.namespace}-${environment}"""
}
works perfect but is not dynamic that is the point of the method variable. I have tried with the """ stuff as you can see, but not working.
Any extra idea?
Edited with the code that calls the method:
...
projectProps = readProperties file: './gradle.properties'
openShiftTokenByGroup = 'OCP_TOKEN_' + projectProps.namespace.toUpperCase()
...
stage ('Deploy-Dev') {
agent any
steps {
milestone ordinal : 10, label: "Deploy-Dev Milestone"
deployToOpenShift(projectProps, 'dev', openShiftTokenByGroup)
}
}
I have got two different ways to do that. One is using evaluate from groovy like this:
def openShiftTokenByGroup = 'OCP_TOKEN_' + projectProps.namespace.toUpperCase()
evaluate("${openShiftTokenByGroup}") //This will resolve the configured value in Jenkins
The second one is the same approach but in the sh command with eval escaping the $ character:
sh """
eval \$$openShiftTokenByGroup
echo "Token: $openShiftTokenByGroup
"""
This will do the magic too and you'll get the Jenkins configured value.

Resources