Erik B
Erik B

Reputation: 42574

How to create an extendable base job in Jenkins Job DSL?

I'm trying to create a base job, to reduce the duplication between our jobs. I did the following, but it's not working:

def baseJob(Map m, Closure c = {}) {
    type = m.type ?: 'dev'
    pipelineJob("prefix-${m.name}") {
        parameters {
            stringParam('ONE', 'one', 'Description one')
        }
        c()
    }
}

baseJob(type: 'release', name: 'test') {
    parameters { // <-- Fails here
        stringParam('TWO', 'two', 'Description two')
    }
}

I get the following error:

ERROR: (script, line 12) No signature of method: script.parameters() is applicable for argument types: (script$_run_closure1$_closure4) values: [script$_run_closure1$_closure4@18b249b3]

The following works as expected:

def baseJob(Map m, Closure c = {}) {
    type = m.type ?: 'dev'
    pipelineJob("prefix-${m.name}") {
        parameters {
            stringParam('ONE', 'one', 'Description one')
        }
        parameters { // <-- This is fine
            stringParam('TWO', 'two', 'Description two')
        }
        c()
    }
}

baseJob(type: 'release', name: 'test')

So the problem isn't that I call parameters multiple times. The problem seems to be that I call parameters from inside a closure.

I'd like to believe that there is a way to execute the closure, so that parameters is called correctly. However, I suspect that I will have to learn a lot more about Groovy and Jenkins Job DSL, before I am able to figure it out. So I'm hoping that there is someone that knows how to do it.

If you have an alternative solution to accomplishing an extendable base job, that's a valid answer as well.

Upvotes: 4

Views: 654

Answers (2)

Erik B
Erik B

Reputation: 42574

You just need to set the delegate of the closure that you're calling to the delegate of the closure that you are in:

def baseJob(Map m, Closure c = {}) {
    type = m.type ?: 'dev'
    pipelineJob("prefix-${m.name}") {
        parameters {
            stringParam('ONE', 'one', 'Description one')
        }
        c.delegate = delegate // <-- Just add this line
        c()
    }
}

baseJob(type: 'release', name: 'test') {
    parameters {
        stringParam('TWO', 'two', 'Description two')
    }
}

delegate contains the delegate of the currently executing closure.

Upvotes: 3

Bhanuchander Udhayakumar
Bhanuchander Udhayakumar

Reputation: 1621

Answer : The method parameters is not implemented inside your script. It was actually implemented inside the pipeline Closure delegate class.

This code may help you to understand what's happening there....

class Test {
    void printMe()
    {
        println "I am in test"
    }    
}

void test(Closure cl)
{
    Test t = new Test()
    cl.delegate = t
    cl()
}

def callMe = { printMe()}
test { 
    printMe() // This will run
    callMe() // This will fail
}

In Your case : pipeline (String arg, Closure pipeLineClosure)

pipeLineClousure had been implemented inside a class X where the parameters method can be Found. like shown below code,

class X
{
  ...
  parameters (Closure cl)
}

So the possible implementation could be :

class Custom{
    String val1
    String val2
    String val3
}

def baseJob(Map m, List<Custom> l) {
    type = m.type ?: 'dev'
    pipelineJob("prefix-${m.name}") {
        l.each{v->
            parameters {
                stringParam(v.val1, v.val2, v.val3)
            }
        }
    }
}

List l = []
l.add new Custom(val1: 'ONE', val2: 'one', val3: 'description')
// can be add more values
baseJob(type: 'release', name: 'test', l)

HOPE IT HELPS

Upvotes: 3

Related Questions