5

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:

Sohail Si
  • 2,750
  • 2
  • 22
  • 36
  • Related question: "What is a Jenkins Stage in terms of Groovy?" https://stackoverflow.com/questions/56279390/what-is-a-jenkins-stage-in-terms-of-groovy – Sohail Si Aug 04 '21 at 15:28

2 Answers2

4

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

injecteer
  • 20,038
  • 4
  • 45
  • 89
  • Fantastic. Thanks for the well written answer. – Sohail Si Jun 19 '20 at 11:47
  • So `DSLBuilder` is something (aa utility) outside the Groovy's language and SDK, and is Jenkins-specific. It is a source preprocessor that translates (transforms) a semi-Groovy (but not strictly Groovy) source file into pure Groovy. It modifies the code in the `Jenkinsfile` in various ways such as adding prefixes, imports certain libraries in beginning of the source file, etc. Is this a correct statement? – Sohail Si Jun 19 '20 at 11:51
  • Not quite. There's no semi-Groovy here. The pipeline scripts are pure Groovy and they are fed to Groovy-based Jenkins' DSL builder, and get executed. Important point here, is that the script is not precompiled (like java class would) because of code like `steps{}` which is not provided in Groovy SDK. – injecteer Jun 19 '20 at 11:57
  • 1
    Groovy is flexible about code which can not be compiled straight away, hence you can create a script of arbitrary code which will work in some specific context later on – injecteer Jun 19 '20 at 11:59
  • I thought I had the answer, but now it seems I know nothing in terms of answer to the question: "Is a Jenkinsfile in pure Groovy?". – Sohail Si Jun 21 '20 at 02:18
  • define "pure groovy" – injecteer Jun 21 '20 at 09:46
1

Looks like it's primarily Groovy, so if you're looking for simply syntax highligting adding something like the following does the job.

<!-- language: lang-groovy -->

There are caveats however documented in the online docs, so maybe this implies it's not written in pure groovy but some specialized/constrained form of it?

The basic statements and expressions which are valid in Declarative Pipeline follow the same rules as Groovy’s syntax with the following exceptions:

  • The top-level of the Pipeline must be a block, specifically: pipeline { }.

  • No semicolons as statement separators. Each statement has to be on its own line.

  • Blocks must only consist of Sections, Directives, Steps, or assignment statements.

  • A property reference statement is treated as a no-argument method invocation. So, for example, input is treated as input().

https://www.jenkins.io/doc/book/pipeline/syntax/#declarative-pipeline

jxramos
  • 7,356
  • 6
  • 57
  • 105