3

I am trying to write a groovy-dsl script for Jenkins to generate two jobs:

  • The first job is a FreestyleJob
  • The second one is a MatrixJob

Their definitions are almost the same; there are only minor differences between them. Therefore, I want to reuse most of the job code and I came to the following refactoring scenario (please focus in the fifth line, in the ternary operator):

[
    ['toolchainsBuild': false],
    ['toolchainsBuild': true],
].each { Map config ->
    config.toolchainsBuild ? job("job1") : matrixJob("job2") {
        // job definition follows...for example:
        out.println("debug")
        steps {
            cmake {
                buildToolStep {}
            }
        }
        // if (config.toolchainsBuild) {
        //     ... // different actions, depending on the job type
        // }
    }
}

However, this does not work. Proof: debug is printed just once in the logfile (it should appear twice, as I want two different jobs to be defined).

I also tried to wrap the ternary operator and its operands in parentheses, as in:

(config.toolchainsBuild ? job("job1") : matrixJob("job2")) {
// ...

However, this causes a syntax error:

Processing provided DSL script
ERROR: (script, line 20) No signature of method: javaposse.jobdsl.dsl.jobs.MatrixJob.call() is applicable for argument types: (script$_run_closure1$_closure2) values: [script$_run_closure1$_closure2@2cb2656f]
Possible solutions: wait(), label(), any(), wait(long), label(java.lang.String), each(groovy.lang.Closure)
Started calculate disk usage of build
Finished Calculation of disk usage of build in 0 seconds
Started calculate disk usage of workspace
Finished Calculation of disk usage of workspace in 0 seconds
Notifying upstream projects of job completion
Finished: FAILURE

How can I rewrite the above expression to produce two different jobs, depending on the value of the boolean?

I believe the problem is related to the usage of the ternary operator with closures, maybe it is not intended to be used this way?

thiagowfx
  • 4,832
  • 6
  • 37
  • 51
  • Does `if(config.toolchainsBuild){ job("job1") }else{ matrixJob("job2") }` work? – Raphael May 09 '17 at 00:47
  • I will test it. Supposing it works, how would I include the job body in each job without duplicating it? – thiagowfx May 09 '17 at 01:14
  • You can put matrixJob("job2"){ etc; etc; } inside the else. – Raphael May 09 '17 at 01:15
  • My suspicion is the DSL overrides the ternary operator for something else. – Raphael May 09 '17 at 01:16
  • 1
    The syntax you specified works. However, I will repeat my last question: how to include the job body in each job **without duplicating it**? Let's say, I would write: `if(config.toolchainsBuild) { job("job1") { expr1; expr2; ... } } else { matrixJob("job2") { expr1; expr2; ... } }`. In this case, the `expr`s would be several expressions and would be duplicated. How to refactor them into a single variable? – thiagowfx May 09 '17 at 19:04
  • My expressions DSL contain around 100 lines defining the build step, so it is not feasible to repeat these lines twice. If you find a way to refactor them into a single variable, I would be glad to accept your answer. – thiagowfx May 09 '17 at 19:06

1 Answers1

9

I managed to solve it this way:

def jobInstance = !config.toolchainsBuild ? job("job1") : matrixJob("job2")

jobInstance.with {
    // ... job definition follows
}

I.e., by using the with method. This way, the closure is only written once.

thiagowfx
  • 4,832
  • 6
  • 37
  • 51
  • 1
    Another alternative would be to assign the closure to a variable, and then try to use the aforementioned variable to initialize the jobs. It would probably be more elegant than my solution, however I could not find a way to properly do it. – thiagowfx May 10 '17 at 06:10