kenorb kenorb - 1 month ago 9
Groovy Question

How to append a job into a map using << operator?

I'm trying to implement the code inspired from here with

<<
operator in the following way:

builder = { name, param1, param2 ->
[job: name, parameters: [string(name: 'Param1', value: param1), string(name: 'Param2', value: param2)], quietPeriod: 2, wait: false]
}
node {
stage('Tests') {
def testBuilds = [:]
testBuilds << build *builder('Test', 'Foo', 'Bar')
testBuilds << build *builder('Test', 'Foo2', 'Bar2')
parallel testBuilds
}
}


where I expect to append two jobs into
testBuilds
map in order to run them in parallel.

However when running the job, I've got the following exception error:

groovy.lang.MissingPropertyException: No such property: build for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:224)
at org.kohsuke.groovy.sandbox.impl.Checker$4.call(Checker.java:241)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:238)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:221)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:221)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:24)
...


What would be the correct syntax using the above approach?

Answer

You've got few problems in your code:

  1. Branches description testBuild is a map (key: value) object, not a list. So you cannot left shift (<<) values into it the way you did, such operation is not supported for map

  2. Jenkins pipeline parallel operation expects map with closure as its values.

  3. build is part of pipeline DSL, not a common Groovy method. It appears it cannot accept arguments this way. While the expression build *builder(foo, bar) passes syntax check at first, omitting round brackets is just groovy syntactic sugar. Rewriting this line as build(*builder(foo, bar)) generates syntax error exception.

All in all, you can rewrite your code in a way like:

def builder(name, param1, param2) {
    return build(job: name, parameters: [string(name: 'Param1', value: param1)], [string(name: 'Param2', value: param2)], quietPeriod: 2, wait: false)
}

node {
    stage('Tests') {
        def testBuilds = [:]
        testBuilds['test1'] = { builder('Test', 'Foo', 'Bar') }
        testBuilds['test2'] = { builder('Test', 'Foo2', 'Bar2') }
        parallel testBuilds
    }
}