Search code examples
jenkinsgroovyjenkins-job-dsl

Extending Jenkins job DSL code in multiple classes


I've read a lot of tutorials regarding the Jenkins job DSL plugin but I cannot figure out how to create a job factory class that in turn uses another class that generates the jobs.

I already have a lot of jobs Groovy scripts that directly call the job factory and that works and my jobs are generated correctly. What I need is another class that in turn generates a lot of jobs using the previous job factory.

I've spent hours trying to debug this issue. I'm pretty sure it has something to do with closures and instantiating the factory objects.

package company.factory

import javaposse.jobdsl.dsl.DslFactory
import javaposse.jobdsl.dsl.Job

/**
 * Base DSL templates for all Jenkins jobs.
 *
 */
class JobFactory {
    private DslFactory dslFactory

    JobFactory(DslFactory dslFactory) {
        this.dslFactory = dslFactory
    }

    Job generateBaseJob() {
        dslFactory.job('TEST-1') {
            logRotator(365, -1, 1, -1)
        }
    }

    def generate() {
        generateBaseJob()
    }
}

Calling it a Groovy script works:

import company.factory.JobFactory

JobFactory jobfactory = new JobFactory(this)

jobfactory.generate()

Now, when I try to extend that class with another class, it fails.

package company.flow

import company.factory.JobFactory

class DeploymentFlow {
    JobFactory jobfactory = new JobFactory(this)

    def generateAllJobs() {
        jobfactory.generate()
    }
}

Calling it a Groovy script fails:

import company.flow.DeploymentFlow

new DeploymentFlow().generateAllJobs()

Error:

javaposse.jobdsl.dsl.DslScriptException: (JobFactory.groovy, line 36) No signature of method: company.flow.DeploymentFlow.job() is applicable for argument types: (java.lang.String, company.factory.JobFactory$_generateBaseJob_closure1) values: [TEST-1, company.factory.JobFactory$_generateBaseJob_closure1@60ed3159]
        Possible solutions: any(), wait(), getA(), find(), grep(), dump()
            at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScriptEngine(AbstractDslScriptLoader.groovy:114)
            at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts_closure1(AbstractDslScriptLoader.groovy:61)
            at groovy.lang.Closure.call(Closure.java:414)
            at groovy.lang.Closure.call(Closure.java:430)
            at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScripts(AbstractDslScriptLoader.groovy:46)
            at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScript(AbstractDslScriptLoader.groovy:87)
            at JobScriptsSpec.test script #file.name(JobScriptsSpec.groovy:57)

            Caused by:
            groovy.lang.MissingMethodException: No signature of method: company.flow.DeploymentFlow.job() is applicable for argument types: (java.lang.String, company.factory.JobFactory$_generateBaseJob_closure1) values: [TEST-1, company.factory.JobFactory$_generateBaseJob_closure1@60ed3159]
            Possible solutions: any(), wait(), getA(), find(), grep(), dump()
                at company.factory.JobFactory.generateBaseJob(JobFactory.groovy:36)
                at company.flow.DeploymentFlow.generateAllJobs(DeploymentFlow.groovy:31)
                at script.run(script:24)
                at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScript(AbstractDslScriptLoader.groovy:138)
                at javaposse.jobdsl.dsl.AbstractDslScriptLoader.runScriptEngine(AbstractDslScriptLoader.groovy:108)
                ... 6 more

I need to extend my job factory class into another class as I want to generate a lot of jobs and I want to avoid duplicated code. Any help would be greatly appreciated.


Solution

  • I managed to figure it out with the help from the nice people on Google Jenkins DSL plugin group.

    The working code is below.

    Factory class:

    package company.factory
    
    import javaposse.jobdsl.dsl.DslFactory
    import javaposse.jobdsl.dsl.Job
    
    class JobFactory {
        private DslFactory dslFactory
    
        JobFactory(DslFactory dslFactory) {
            this.dslFactory = dslFactory
        }
    
        Job generateBaseJob() {
            dslFactory.job('TEST-1')
        }
    }
    

    Deployment class:

    package company.flow
    
    import company.factory.JobFactory
    import javaposse.jobdsl.dsl.DslFactory
    
    class DeploymentFlow {
        JobFactory JobFactory
    
        DeploymentFlow(DslFactory dslFactory) {
            JobFactory = new JobFactory(dslFactory)
        }
    
        void generateAllJobs() {
            JobFactory.generateBaseJob()
        }
    }
    

    Calling my deployment class in my seed job:

    import company.flow.DeploymentFlow
    
    DeploymentFlow deploymentFlow = new DeploymentFlow(this)
    
    deploymentFlow.generateAllJobs()