Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jenkins Groovy how to call methods from @NonCPS method without ending pipeline

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?

like image 389
Fo. Avatar asked Apr 14 '16 23:04

Fo.


People also ask

What is @NonCPS method?

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).

How do you abort Jenkins pipeline if stage fails?

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!" } } }

How do you call a Groovy script from Jenkins?

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.

What is closure in Jenkins pipeline?

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.”


2 Answers

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.

like image 88
Fo. Avatar answered Oct 13 '22 16:10

Fo.


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.

like image 4
evildethow Avatar answered Oct 13 '22 16:10

evildethow