I'm trying to write a Jenkins Job DSL script and would like to write it as declaratively / DRY-ly as possible. The Jenkins task is calling some other tasks via a MultiJob. I have Groovy that originally looks like this (everything's contained within a class because it's referenced elsewhere):
static void buildDownstream(def parentJob, String commit_a="master",
String commit_b="master") {
parentJob.with {
steps {
phase('Phase') {
job("name_1") {
prop('COMMIT_A', commit_a)
nodeLabel('NODE_LABEL', NODE_LABEL_MAP["name_1"])
killPhaseCondition('NEVER')
}
job("name_2") {
prop('COMMIT_A', commit_a)
prop('COMMIT_B', commit_b)
nodeLabel('NODE_LABEL', NODE_LABEL_MAP["name_2"])
killPhaseCondition('NEVER')
}
job("name_3") {
prop('COMMIT_A', commit_a)
prop('COMMIT_B', commit_b)
nodeLabel('NODE_LABEL', NODE_LABEL_MAP["name_3"])
killPhaseCondition('NEVER')
}
}
}
}
}
I'd like to abstract out the job creation, which contains lots of duplication. I've ended up with something strange like this:
static void buildDownstream(def parentJob, String commit_a="master",
String commit_b="master") {
parentJob.with {
steps {
phase('Phase') {
def phase = ({ owner })();
{ ->
add_node_label=true;
{ ->
commit_a = null;
def self = ({ owner })();
addJob("name_1", self).call(phase);
}
def self = ({ owner })();
addJob("name_2", self).call(phase);
addJob("name_3", self).call(phase);
}
}
}
}
}
private static Closure addJob(String job_name, Closure callingClosure) {
return { phase ->
def job_config = {
if(commit_a != null) {
prop('COMMIT_A', commit_a)
}
if(commit_b != null) {
prop('COMMIT_B', commit_b)
}
if(add_node_label == true) {
nodeLabel('NODE_LABEL', NODE_LABEL_MAP[job_name])
}
killPhaseCondition('NEVER')
}
job_config.delegate = callingClosure
job_config.resolveStrategy = Closure.DELEGATE_ONLY
phase.job(job_name, job_config)
}
}
which, probably being totally non-idiomatic Groovy (all this def self = ({ owner })()
stuff doesn't sit right with me), doesn't work at all.
Basically, I want to pass all the variables in callingClosure
's scope to the job_config
closure without explicitly passing all of them in as arguments. (Explicitly passing a map of arguments works, but it gets unwieldy when there are lots of arguments.) How can I do this?
(P.S: Currently, Groovy is trying to resolve the commit_a
variable inside job_config
as coming from javaposse.jobdsl.dsl.helpers.step.PhaseContext
, which I find strange; didn't I explicitly set the delegate to a closure inside that PhaseContext
?)
EDIT: From another SO question, it appears that I can set phase
= delegate
(which defaults to owner
?) instead of ({ owner })()
and be fine; I don't really get this either, since job
is a property of the PhaseContext
, and not its parent (?)