Cheatsheet for Groovy to be used in Jenkins pipelines
Groovy is an object-oriented programming language used for JVM platform. This dynamic language has a lot of features like processing lists and arrays, loops and parralel execution. It is very usefull when you are working with Jenkins to automate your CI/CD pipelines.
I will not go deap into details. Obviously you are looking for some examples here.
Variables definition
Define global variable for your pipeline script:
foo = "bar"
Define local variable for the current scope (stage, step, script)
def qwe = "rty"
Define environment variables
env.AWS_DEFAULT_REGION = "us-west-1"
another option is to use environment block:
environmnt {
AWS_DEFAULT_REGION = "us-west-1"
profile = "dev"
}
Modify the value of the variable
Let’s consider the following example:
def myvar = "my-custom-value"
replace all -
with +
. The following will result into my+custom+value
myvar.replaceAll("-", "+")
Split value
In order to split the string we have the following options:
- tokenize() returns a list, will ignore empty string
- split() returns multiple strings
myvar.split("-")
Will result into the following:
my
custom
value
myvar.tokenize("-")
Will result into the following:
['my', 'custom', 'value']
Collections
Let’s create a list value from myvar string:
def myList = myvar.tokenize("-")
Check if the list in not empty:
if(myList) {
... do something ...
}
get the size of array:
myList.size()
Access elements in array
myList[0] // first element
myList[1,2,-1] //second, third and first element
loop over array and check if one array contains elements from other array
// define new array
newList = ['my', 'list' ]
// loop over new array
newList.each {
// check if element exists in first array
if myList.contains(it) {
// do something
}
}
// If you need indexes
newList.eachWithIndex{
element, index -> assert myList[index] == element
}
More operations with collections
Searching over array
find()
- returns the first appearance of a search request. ReturnsStr
findAll()
- returns all appearances of a search request. ReturnsList
myList.findAll("my")
in case of numeric search:
def intArray = ["1", "2", "3", "4"]
intArray.findAll { it > "2" } // returns ["3", "4"]
add element to array:
def intArray = ["1", "2", "3", "4"]
intArray.add("5")
List methods available in Groovy are another benefit.
Add()
Append the new value to the end of this list.Get()
Returns the element at the specified position in this list.Contains()
Returns true if this list contains the specified value.Minus()
Create a new list of original elements that removes the specified elementPlus()
Create a new list of the original list elements and the specified elements.Pop()
Remove the last item from this listRemove()
Remove elements from the specified position in the listReverse()
Create a new list that is the opposite of the original list’s elementsSize()
Get the number of elements in this list.Sort()
Returns a sorted copy of the original list
Working with maps
def myMap = [
"name": "Elon Mask",
"gender": "male",
"occupation": "business magnate"
]
if(!myMap.car) {
println "Returns true true if cat key is in the list, otherwise return false"
}
another example with bit more nested map:
def myMap = [
"a": [
"id": "1",
"name": "foo"
],
"b": [
"id": "2",
"name": "bar"
],
"c": [
"id": "3",
"name": "foo"
]
]
Find first appearance of name==foo. ‘?’ ensures that the following argument won’t be executed if the result is null
myMap.find { it.value.name == "foo" }?.key //returns "a"
Find all appearances of name==foo, list and grabs only specific components of nested elements, list
myMap.findAll { it.value.name == "foo" }.collect { it.value.id} //returns ["1", "3"]
Access map elements
myMap.a.id //returns "1"
myMap["a"]["id"] //returns "1"
Map methods available in Groovy are another benefit.
containsKey()
Does this Map contain this key. Exampleget()
Look up the key in this Map and return the corresponding value. If there is no entry in this Map for the key, then return null.keySet()
Obtain a Set of the keys in this Map Exampleput()
Associates the specified value with the specified key in this Map. Examplesize()
Returns the number of key-value mappings in this Map.values()
Returns a collection view of the values contained in this Map. Example
Conditions
Switch/case is faster and are much easier to read
weekDays = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
]
weekDays.each { day ->
switch(day) {
case "Monday": // if no break, will execute the next action
case "Tuesday":
case "Wednesday":
println "${day} is just another business day"
break // 'break' breaks the loop, no other action will be executed
case "Friday":
println "TGIF!"
break
case "Thursday":
println "On ${day} we praise Thor"
break
case "Saturday":
case "Sunday":
println "It's ${day} :)"
default: // default condition, when other didn't match
break
}
}
If statements
If statements are less flexible than case. Groovy doesn’t support elseif/elif. So they are applicable only in if ... else
way:
int a = 2
//Check for the boolean condition
if (a<100) {
//If the condition is true print the following statement
println("The value is less than 100");
} else {
//If the condition is false print the following statement
println("The value is greater than 100");
}
Do something with list if it is not empty:
if(myList) {
... do something ...
}
Do something if varible has some value
if( foo == "bar" ) {
... do something ...
}
Variables with shell execution
def myVar = "Im with Groovy"
sh """
myVar="Im with Shell"
# this one is groovy
echo ${myVar}
# but this one is shell
echo \${myVar}
"""
Create groovy variable from shell output
def myWhoAmI = sh(script: "whoami", returnStdout: true).toString().trim()
trim()
will remove empty space at the end.
toString()
will convert the output to the str type
Read file and save it into variable
def varFromFile = readFile 'filename.txt'
echo "The contexts of the file is ${varFromFile}"
Another trick is to capture the status of the sh command and do something is status is not error:
def commandStatus = sh(script: "whoami 2>&1> whoami.txt", returnStatus:true).toString().trim()
if (commandStatus == 0) {
myWhoAmI = readFile 'whoami.txt'
} else {
println('Something went wrong')
}
Exiting pipeline
If something goes wrong in your pipeline than obviously you’d like to make it stop at that point and change the job status. The best way to do this is is the following:
currentBuild.result = 'UNSTABLE'
return
currentBuild.result
is the system variable that can be defined in the pipeline. Possible values are “SUCCESS”, “UNSTABLE”, “FAILURE”, “NOT_BUILT”, “ABORTED”. May be null for an ongoing build.
It can be used in exception handling:
try {
stage {
....
}
} catch (e) {
if (something) {
currentBuild.result = 'SUCCESS'
return
} elif (something) {
currentBuild.result = 'UNSTABLE'
return
} elif (something) {
currentBuild.result = 'NOT_BUILT'
return
}
}
Alternatively you can interrupt pipeline execution inside the stage if something is not working. For example:
stage('Stage1'){
...
if ( somevar == false ) {
currentBuild.result = 'ABORTED'
return
}
}
Parsing XML
The Groovy XmlParser class
employs a simple model for parsing an XML document into a tree of Node instances
.
Lets’ consider we have an xml like the following Movies.xml
:
<collection shelf = "New Arrivals">
<movie title = "Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title = "Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
</collection>
import groovy.xml.MarkupBuilder
import groovy.util.*
def parser = new XmlParser()
def doc = parser.parse("Movies.xml");
doc.movie.each{
bk->
print("Movie Name:")
println "${bk['@title']}"
print("Movie Type:")
println "${bk.type[0].text()}"
print("Movie Format:")
println "${bk.format[0].text()}"
}
Another flow is to loop over all keys and values inside xml file using XmlSlurper
:
doc = new XmlSlurper().parse("Movies.xml")
doc.collection.each { item ->
println "item index: ${item.@indexNum}"
item.children().each { tag ->
println " ${tag.name()}: ${tag.text()}"
}
}
Parsing Json
import groovy.json.JsonSlurper
def jsonSlurper = new JsonSlurper()
def object = jsonSlurper.parseText('{ "name": "John", "ID" : "1"}')
println(object.name);
println(object.ID);
Loop over all key/values in the given json file
def jsonFile = parse(new File('filename.json'))
def jsonObject = new groovy.json.JsonSlurper().jsonFile
jsonObject.each { key, value ->
println "$key : $value"
}
Templating
Groovy’s template engine is very similar to bash envsubst
.
SimpleTemplateEngine()
Let’s assume we have the following Student.template
file:
<Student>
<name>${name}</name>
<ID>${id}</ID>
<subject>${subject}</subject>
</Student>
The following will update the variables with the give values
import groovy.text.*
import java.io.*
def file = new File("D:/Student.template")
def binding = [
'name' : 'Joe',
'id' : 1,
'subject' : 'Physics'
]
def engine = new SimpleTemplateEngine()
def template = engine.createTemplate(file)
def writable = template.make(binding)
println writable
StreamingTemplateEngine()
The StreamingTemplateEngine engine is another templating engine available in Groovy. This is kind of equivalent to the SimpleTemplateEngine, but creates the template using writeable closures making it more scalable for large templates.
def text = '''This Tutorial is <% out.print TutorialName %> The Topic name
is ${TopicName}'''
def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)
def binding = [
TutorialName : "Groovy",
TopicName : "Templates",
]
String response = template.make(binding)
println(response)
XmlTemplateEngine()
The XmlTemplateEngine is used in templating scenarios where both the template source and the expected output are intended to be XML.
def binding = [StudentName: 'Joe', id: 1, subject: 'Physics']
def engine = new groovy.text.XmlTemplateEngine()
def text = '''\
<document xmlns:gsp='http://groovy.codehaus.org/2005/gsp'>
<Student>
<name>${StudentName}</name>
<ID>${id}</ID>
<subject>${subject}</subject>
</Student>
</document>
'''
def template = engine.createTemplate(text).make(binding)
println template.toString()