I need to parse some JSON in a Jenkins Pipeline and call some regular methods in a loop, however the script always exits after the first function call. How to do this?
import groovy.json.JsonSlurper
import com.cloudbees.groovy.cps.NonCPS
@NonCPS
def myMethod(String json) {
def jsonSlurper = new JsonSlurper()
def jsonObject = jsonSlurper(json)
jsonObject.each {
obj ->
switch(obj.name) {
case "foo":
doAThing(obj)
break
case "bar":
doAnotherThing(obj)
break
}
}
}
In the above example, even with a json object like:
[{
"name": "foo"
}, {
"name": "bar"
}]
...the pipeline always exits after the first iteration. This is presumably due to mixing sync and async functions. Is there any way to do this?
The @NonCPS annotation is useful when you have methods which use objects which aren't serializable. Normally, all objects that you create in your pipeline script must be serializable (the reason for this is that Jenkins must be able to serialize the state of the script so that it can be paused and stored on disk).
Alternatively you can call error(String message) step to stop the pipeline and set its status to FAILED . For example, if your stage 1 calls error(msg) step like: stage("Stage 1") { steps { script { error "This pipeline stops here!" } } }
In Jenkinsfile, simply use load step to load the Groovy script. After the Groovy script is loaded, the functions insides can be used where it can be referenced, as shown above.
The Groovy documentation explains that, “A closure in Groovy is an open, anonymous, block of code that can take arguments, return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope.”
I've resolved this issue essentially by doing the following:
import groovy.json.JsonSlurper
def myMethod(String json) {
def jsonSlurper = new JsonSlurper()
def jsonObject = jsonSlurper(json)
jsonSlurper = null
for(int i = 0; i < jsonObject.size(); i++) {
switch(jsonObject[i].name) {
case "foo":
doAThing(jsonObject[i])
break
case "bar":
doAnotherThing(jsonObject[i])
break
}
}
}
Immediately destroy the JsonSlurper instance after it's used, remove @NonCPS annotation, switch to a c-style for loop instead of each.
Just to clarify, this is documented as an unsupported feature - https://github.com/jenkinsci/workflow-cps-plugin/#technical-design
You may not call regular (CPS-transformed) methods, or Pipeline steps, from a @NonCPS method, so they are best used for performing some calculations before passing a summary back to the main script.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With