Search code examples
groovyjenkins-pipelinejenkins-job-dsl

Is a Jenkinsfile in pure Groovy? What Groovy language construct is used in `steps` in a Jenkinsfile?


What Groovy language construct, syntax or control structure is used in the following code fragment in a Jenkinsfile?

stage('Stage 1') {
    steps {
        // One or more steps
    }
}

i.e. What are blocks in Jenkinsfile, in terms of pure Groovy language?

what is 'steps'? or stage? Is it calling a function? or definition? or a function call with anonymous (lambda) argument?

Inherent in this question is another question:

Question 2:

Is a Jenkinsfile, a code fragment in groovy language?

In other words, 1. Does a Jenkinsfile follow all syntax and control structures of pure Groovy? (perhaps by an implicit library import-ed or #include d silently in beginning),

As opposed to being a DSL: 2. Jenkinsfile being almost a groovy source file augmented with new Jenkins-specific constructs not originally in Groovy, e.g. Jenkins using a preprocessing.

Which of the above two hold?

Related:


Solution

  • In Jenkins (or Gradle) 2 main features are used:

    1. Groovy (java) idiomatic structures like loops, switches, chain of command etc
    2. DSLBuilder facility based on Closures to allow for nesting and invoking of domain-specific methods as they were a part of Groovy itself.

    So, if you write something like

    stage('Stage 1') {
        steps {
            // One or more steps
        }
    }
    

    it translates internaly to roughly:

    jenkinsContext.stage('Stage 1') {
        jenkinsContext.steps {
            // One or more steps
        }
    }
    

    so it is way clearer to write and read. Here the Closures - the {...} blocks - represent nesting or grouping of your code.

    In this block you can also see Groovy's way of calling methods where the last argument is a Closure. The code above could be rewritten as:

    jenkinsContext.stage 'Stage 1', { // here no brackets around args
        jenkinsContext.steps( { // here with normal java-style brackets
            // One or more steps
        } )
    }
    

    In jenkins you can mix and match DSL calls with Groovy structures:

    [ 'Stage 1', 'Stage 2' ].each{
      stage( it ) {}
    }
    

    or even have your DSL names generated dynamically:

    [ 'Stage 1':'stage', 'step 2':'steps' ].each{ value, name ->
      "$name"( value ) {}
    }
    

    would create the DSL (as example ONLY!):

      stage( 'Stage 1') {}
      steps( 'Step 2' ) {}
    
    

    So, Jenkins pipeline syntax is Groovy + Jenkins DSL