String Manipulation in Groovy - jenkins

I am writing a groovy script which will return me the list of Task-Definition in AWS ECS service,
Here is the code snippet for the same
def p = 'aws ecs list-task-definitions --family-prefix test'.execute() | 'jq .taskDefinitionArns[]'.execute()
p.waitFor()
print p.text
and the output is
"arn:aws:ecs:us-west-2:496712345678:task-definition/test:2"
"arn:aws:ecs:us-west-2:496712345678:task-definition/test:3"
Now I want to capture only the last part of the result, i.e test:2, test:3 and so on without double quotes
How can I do that using Groovy language as I have to use it in Jenkins's active choice reactive parameter plugin

Assuming:
​def text = "arn:aws:ecs:us-west-2:496712345678:task-definition/test:2" + "\n" + "arn:aws:ecs:us-west-2:496712345678:task-definition/test:3"​​​​​​​​​​​​
Try :
text​.split("\n")​​​​​​​​​​​​​.collect {c -> c.split("/").last()}​​​​​​
This prints a list of [test:2, test:3]
If you want it in one line and not in an list, use:
text​.split("\n")​​​​​​​​​​​​​.collect {c -> c.split("/").last()}​​​​​.join(",")​
This prints: test:2,test:3
Update
Due to OP's comment, the answer after all should look something like:
def p = 'aws ecs list-task-definitions --family-prefix test'.execute() | 'jq .taskDefinitionArns[]'.execute()
p.waitFor()
def text = p.text
println text​.split("\n")​​​​​​​​​​​​​.collect {c -> c.split("/").last()}​​​​​​

You can split using / and get the last element:
def p = "arn:aws:ecs:us-west-2:496712345678:task-definition/test:2"
def result = p.split("/").last()

Just adding another Style :
String.metaClass.getMyString{-> delegate.substring(delegate.lastIndexOf("/")+1, delegate.length()-1).replace(":", "")}
println p.text.readLines()*.getMyString().join(" ")
Happy Learning... ! :)

Related

Jenkins/Groovy: How to pull specific part of a string

I have a string that look like:
data = ABSIFHIEHFINE -2938 NODFNJN {[somedate]} oiejfoen
I need to pull {[somedate]} only with {[]} included.
I tried to do data.substring(0, data.indexOf(']}')) to remove the end of the string but it is also removing the symbols that I need to keep
I need to pull {[somedate]} only with {[]} included.
def data = 'ABSIFHIEHFINE -2938 NODFNJN {[somedate]} oiejfoen'
// you could do error checking on these to ensure
// >= 0 and end > start and handle that however
// is appropriate for your requirements...
def start = data.indexOf '{['
def end = data.indexOf ']}'
def result = data[start..(end+1)]
assert result == '{[somedate]}'
You can do it using regular expression search:
data = "ABSIFHIEHFINE -2938 NODFNJN {[somedate]} oiejfoen"
def matcher = data =~ /\{\[.+?\]\}/
if( matcher ) {
echo matcher[0]
}
else {
echo "no match"
}
Output:
{[somedate]}
Explanations:
=~ is the find operator. It creates a java.util.regex.Matcher.
The string between the forward slashes (which is just another way to define a string literal), is the regular expression: \{\[.+?\]\}
RegEx breakdown:
\{\[ - literal { and [ which must be escaped because they have special meaning in RegEx
.+? - any character, at least one, as little as possible (to support finding multiple sub strings enclosed in {[]})
\]\} - literal ] and } which must be escaped because they have special meaning in RegEx
You can test the RegEx only or use Groovy IDE to test the full sample code (replace echo by println).

Jenkins dynamic pipeline parameters

I have a jenkins pipeline which gives the user a list of keys from Consul, the user should choose one option (using active choice parameter), I need the pipeline to dynamically generate the list of "sub keys" (depends on the user first choice, for example: key/path/${user_choice} ) and let the user to choose a sub key
my current code his:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = ['/bin/bash', '-c', 'consul kv get -keys --http-addr=X key/path/ | awk -F / \'{print $(NF-1)}\''].execute()
proc.consumeProcessOutput(sout, serr)
proc.waitFor()
return sout.tokenize()
It works fine till now, but "active choice reactive parameter" is not acting dynamically and refuse to relate to the user's first choice. I haven't found any other useful plugin
Any help?
thanks :)
From what I know you can't have an interactive command prompt in Jenkins. However, you can use the input step to get feedback and use it throughout the pipeline like so:
def keys = sh(script: 'consul kv get -keys --http-addr=X key/path/ | awk -F / \'{print $(NF-1)}\'', returnStdout: true).trim().tokenize('\n')
def choice = input message: 'Please choose a sub-key', parameters: [choice(choices: keys, description: '', name: 'Subkeys')]
println "You chose $choice"

How can I force Jenkins Blue Ocean to display print output instead of "Print Message"?

In the below screenshot some debug entries display the output text (with - Print Message at the end) while others simply display Print Message. To view these you have to expand the step to see the output.
All lines are using the format print "TEXT HERE". I've tried using print, println, and echo. All have the same output.
Why do these sometimes display the message, while others force it into a collapsed section? Is it possible to configure this to always show? The normal non-Blue Ocean Jenkins interface displays fine but there is a lot of verbosity.
This seems to be a known issue:
https://issues.jenkins-ci.org/browse/JENKINS-53649
It looks like that BlueOcean does not handle the Groovy GStrings correctly. This is what I've observed:
A simple:
echo "hello world"
will work as expected and will display correctly.
Whereas a templated string with variables, like:
echo "hello ${some_variable}"
will hide the message under a "Print Message" dropdown.
See also this answer.
It appears that if echo uses a variable with value from params or environment (i.e. "params.*"), then step label gets "Print message" name instead of actual value being echoed. It does not matter if the variable itself is a String or not. Even explicitly converting the params value to String does not help.
String param_str
String text_var_2
parameters {
string(name: 'str_param', defaultValue: 'no value')
}
param_str = params.str_param.toString()
echo "string text in double quotes is ${param_str}"
echo "simple quoted string is here"
echo 'simple quoted string is here'
echo 'Single quoted with str ' + param_str + ' is here'
echo param_str
text_var_2 = 'Single quoted str ' + param_str + ' combined'
echo "GString global text2 is ${text_var_2}"
echo 'String global text2 is' + text_var_2
BlueOcean shows simple quoted strings in step label, but everything else as "Print message".
BlueOcean output
Note that 'normal' variables (strings, integers) are not included into this example, but they are also shown in the label normally. So if you have a code like this
def text_str = 'Some string'
def int_var = 1+2
echo text_str + ' is here'
echo int_var
These will be shown on the label.
And indeed it appears to be a known Jenkins issue as stated in a previous answer.
This is a known BlueOcean bug. The console output in the "classic" view interpolates variables correctly.
One workaround is to use the label parameter of the sh step:
def message = 'Hello World'
sh(script: "echo $message", label: message)
I tried lots of things and seems the moment an environment variable is going to be displayed, it uses Print Message instead the text.
Another workaround would be to split the multiline string into an array and iterate over it :-
String[] splitData = MULTI_LINE_STRING.split("\n");
for (String eachSplit : splitData) {
print(eachSplit);
}

Environment variables manipulation

When using:
echo "${env.PRODUCT_NAME}"
it will echo:
MyProdName
When using:
echo "${env.MyProdName_Key}"
it will echo:
123456789
I would like to use something as follows:
echo "${env.${env.PRODUCT_NAME}_Key}"
Is this possible? How?
In Bash this is termed as variable in direction
Try using variables to make it further simplified
PRODUCT_NAME=$(echo "${env.PRODUCT_NAME}")
This would assign PRODUCT_NAME=MyProdName
Similarly
MyProdName=$(echo "${env.MyProdName_Key}")
This would assign MyProdName=123456789
Now when you print PRODUCT_NAME value you will get
echo ${PRODUCT_NAME}
MyProdName
And adding '!' variable indirection will give you the value of another variable values
echo ${!PRODUCT_NAME}
123456789
Maybe this will help you somehow:
def env = [
PRODUCT_NAME:'MyProdName',
MyProdName_Key: 123456789,
]
println "${env[env.PRODUCT_NAME+'_Key']}"
env is Map in the example provided but it works in the exactly same way.
Important note, regardless of how you're deriving variables:
There's no need to use string interpolation if the only value in a
string is a variable itself. This just clutters your code.
Instead of:
echo "${env.PRODUCT_NAME}"
you can do:
echo.PRODUCT_NAME.
Additionally you can grab nested object values dynamically using bracket notation
def obj = [a: '1']
echo obj[a] // outputs '1'
Using these put together, you can do:
def prodName = env.PRODUCT_NAME //will set var prodName to "MyProdName"
echo env[prodName + '_Key'] //gets nested field with key "MyProdName_Key"
(Note: this is similar to Opal's answer, hopefully my breakdown helps)

How can I convert GPathResult to text without pretty format

I'm trying to use groovy to update Jenkins job config.xml by the following code
def updateParameter(String key, String value){
println "changing defult value as $value for key $key"
def xml = new XmlSlurper().parseText(jobConfig)
xml.properties.'hudson.model.ParametersDefinitionProperty'.'parameterDefinitions'.'hudson.model.StringParameterDefinition'.each {
println 'found parameter: ' + it.name
if(it.name.text() == key){
println('default value changed')
it.defaultValue=value
}
}
jobConfig = XmlUtil.serialize(xml)
}
When running jobConfig = XmlUtil.serialize(xml), it changes the format, which is pretty, but I lost link break in pipeline plugin, so pipeline script doesn't work anymore. Is there a way to convert GPathResult to String without format changing?
Best Regards,
Eric
It is all my fault, the line breaks were removed when I read the xml. It seems XmlUtil.serialize(xml) doen't format the text of a xml tag, which is good :)
Best Regards,
Eric

Resources