Can groovy string interpolation be nested? - jenkins

I'm trying to add parameter in Jenkins groovy shell script, then wonder if groovy string interpolation can be used nested way like this.
node{
def A = 'C'
def B = 'D'
def CD = 'Value what I want'
sh "echo ${${A}${B}}"
}
Then what I expected is like this;
'Value what I want'
as if I do;
sh "echo ${CD}"
But it gives some error that $ is not found among steps [...]
Is it not possible?

Like this?
import groovy.text.GStringTemplateEngine
// processes a string in "GString" format against the bindings
def postProcess(str, Map bindings) {
new GStringTemplateEngine().createTemplate(str).make(bindings).toString()
}
node{
def A = 'C'
def B = 'D'
def bindings = [
CD: 'Value what I want'
]
// so this builds the "template" echo ${CD}
def template = "echo \${${"${A}${B}"}}"​
// post-process to get: echo Value what I want
def command = postProcess(template, bindings)
sh command
}

In regard to the accepted answer, if you're putting values in a map anyway then you can just interpolate your [key]:
def A = 'C'
def B = 'D'
def bindings = [ CD: 'Value what I want' ]
bindings["${A}${B}"] == 'Value what I want'

${A}${B} is not a correct groovy syntax.
The interpolation just insert the value of expression between ${}.
Even if you change to the correct syntax and create $ method, the result will not be what you want.
def nested = "${${A}+${B}}"
println nested
static $(Closure closure) { //define $ method
closure.call()
}
CD will be printed.

Related

Jenkins: Set job timeout from a variable in scripted pipeline

I premise that I am not very familiar with Jenkins and Groovy.
I am trying to set a timeout with a time value that can change based on a specific condition. I was wondering if it is possible to do this and how.
This is a shortened example for simplicity, of the pipeline I'm dealing with:
/**
* prepare tests for parallel
* #param filename Name of the file that contains the testsuites list
*/
def doDynamicParallelSteps(filename){
tests = [:]
echo "doDynamicParallelSteps"
def w = pwd()
def path = "$w/$filename"
// read all the lines into a list, each line is an element in the list
def fh = new File(path)
def lines = fh.readLines()
for (line in lines) {
def values = line.split(":")
def testsuite_name = values[0].trim()
def test_path = values[1].trim()
def test_filename_or_directory = test_path.split("/").getAt(-1);
def is_file = test_filename_or_directory.matches("(.*).php")
def is_custom_mycondition = test_filename_or_directory.matches("MyMatchCondition")
if (is_custom_mycondition){ // large timeout
def time_val = 10
} else { // default timeout
def time_val = 5
}
tests["${test_filename_or_directory}"] = {
stage("UnitTest ${test_filename_or_directory}") {
timeout(time: time_val, unit: 'MINUTES') { // scripted syntax
// other stuff here
} // end timeout
} // end stage
} // end MAP
}
parallel tests
}
If I run this pipeline I got the following output:
hudson.remoting.ProxyException: groovy.lang.MissingPropertyException: No such property: time_val for class: mycustomJob
Then I've tried to set it as global value and it worked but not as expected, because its value doesn't seems to changed, it outputs "5" ignoring my condition.
What am I doing wrong? Can anyone show me the right way or a better approach?
What you are doing looks more pythonic than groovy. You must define the variable 'time_val' on a higher level to make it visible in your scope, like:
def time_val = 5
if (is_custom_mycondition){ // large timeout
time_val = 10
}
Instead of your else part.
You can also define it in a single line, like:
def time_val = is_custom_mycondition ? 10 : 5
Your 'timeout' usage looks correct to me. Just define the variable properly.

Jenkins Pipeline Choice Input with List of Map in groovy not working

I have the following input in one of my Jenkins Pipeline Scripts:
def IMAGE_TAG = input message: 'Please select a Version', ok: 'Next',
parameters: [choice(name: 'IMAGE_TAG', choices: imageTags, description: 'Available Versions')]
imageTags is a List of map e.g. :
imageTags : [
[targetSuffix: "", sourceSuffix: "v2.17.1"],
]
When I run the script, I can select only [targetSuffix: "", sourceSuffix: "v2.17.1"] from the dropdown choice as expected.
In my script I can also see the value that gets selected:
echo "Selected Version = ${env.SELECTED_IMAGE_TAG}"
[Pipeline] echo Selected Version = {targetSuffix=, sourceSuffix=v2.17.1}
Now I wanted to find out which item from the original imageTags List got selected, but my script does not work as expected:
def selectedImageTag = imageTags.find { it.targetSuffix == "${env.SELECTED_IMAGE_TAG.targetSuffix}" }
I end up with the following exception:
groovy.lang.MissingPropertyException: No such property: targetSuffix for class: java.lang.String
My question is: How do I get the selected item of my choice out of the original List of maps?
The input step returns a string, so you can't write env.SELECTED_IMAGE_TAG.targetSuffix. You have to extract the substring, e. g. using a regular expression like this:
def match = ( env.SELECTED_IMAGE_TAG =~ /\{targetSuffix=(.*?), sourceSuffix=(.*?)\}/ )
if( match ) {
def selectedTargetSuffix = match[0][1]
def selectedImageTag = imageTags.find { it.targetSuffix == selectedTargetSuffix }
}

How to compare 2 parameters in Jenkins pipeline?

I have 2 string parameters 1) filename 2) Path
filename - sample.txt
path - /usr/cole/jenkins/1240/hd/sample.txt
I want to compare if the "Path" has "Filename" in it and then perform some action if the condition is true
def matchpat = ('${params.path}' =~ /${params.filename}/)
print matchpat
assert params.filename == matchpat[0]
But it doesn't work
In this case you could use String.endsWith(str) method like:
def path = '/usr/cole/jenkins/1240/hd/sample.txt'
def filename = 'sample.txt'
if (path.endsWith(filename)) {
println 'Performing some action...'
}
Running this script produces as expected:
Performing some action...

Groovy Variable $ Dollar Sign in JSON

I've got a JSON file that I am slurping with groovy.
{
"team": "${GLOBAL_TEAM_NAME}",
"jobs": [
{
In the JSON above is a property 'team' that contains a groovy-like variable I want to be resolved at runtime.
teamList.each { tl ->
try
{
def teamSlurper = new JsonSlurperClassic()
def t = teamSlurper.parseText(tl.text)
println "*********************"
println "PROVISIONING JOB FOR: " + t.team
Output:
PROVISIONING JOB FOR: ${GLOBAL_TEAM_NAME}
The above outputs the raw value, but I would like it to resolve the global variable that has been defined for the system.
How can I resolve ${GLOBAL_TEAM_NAME} to its actual system value?
You can do this with Groovy Templates.
def slurper = new groovy.json.JsonSlurperClassic()
def engine = new groovy.text.SimpleTemplateEngine()
def binding = ["GLOBAL_TEAM_NAME": "Avengers"]
def json = '{"team":"${GLOBAL_TEAM_NAME}"}'
def t = slurper.parseText(engine.createTemplate(json).make(binding).toString())
t.team // "Avengers"

How to put a variable into script scope?

I've been using Parametrized-pipelines in Jenkins and notice that while using parameters, the value is both useable from script scope as well as via params.variable.
PARAMETER == true
params.PARAMETER == true
In groovy, is it possible to add a variable to script scope from within a method? I would like to get similar functionality as the following...
// I don't want to have to declare value here
def function1(){
value = 1
}
def function2(){
assert value == 1
}
function1()
function2()
Is there a way to access value from within function2 without doing something like...
value = 0
def function1() {
value = 1
...
Could also do somthing like :
def f1() {
env.aaa = "hello"
}
def f2() {
assert aaa=="hello"
}
node{
f1()
f2()
}
Essentially setting it as an environment variable.
this pipeline works fine:
def f1(){
aaa = "hello"
}
def f2(){
assert aaa=="hello"
}
node{
f1()
f2()
}
the pipeline definition as actually an instance of org.jenkinsci.plugins.workflow.cps.CpsScript that extends groovy.lang.Script
so groovy script properties should work here.
You can use scope variable in script
import groovy.transform.Field
#Field List awe = [1, 2, 3]
def awesum() { awe.sum() }
assert awesum() == 6
http://docs.groovy-lang.org/2.4.9/html/gapi/groovy/transform/Field.html

Resources