Search code examples
jenkinsgroovyjenkins-pipeline

Conditional within Jenkins `tool` block


We use Jenkins shared libraries and need to support the ability of individual repositories to override the default JDK. We have added OpenJDK-20 and OpenJDK-11 in Jenkins > Manage Jenkins as available JDKs alongside the default JDK 8. Now, how can I express this conditional within the tools block?

Current pipeline definition (debug_pipeline.groovy):

// Jenkins declarative pipeline for debugging Jenkins agent

def call (body) {
    def pipelineParams= [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = pipelineParams
    body()

    pipeline {
        agent any
        options {
            // Prepend all console output generated by the
            // Pipeline run with the time at which the line was emitted
            timestamps()
        }
        tools {
            // Define tools to auto-install and put on the PATH
            // The tool name must be pre-configured in Jenkins under Manage Jenkins → Tools.
            maven 'apache-maven-3.9.3'
            jdk 'OpenJDK-20'
        }
        stages {
            stage('Initialize') {
                steps {
                    hello(pipelineParams.greeting)
                }
            }
            stage('Debug') {
                steps {
                    sh 'command -v java && java -version'
                    sh 'command -v mvn && mvn -version'
                }
            }
        }
    }
}

Now, I would like for the use of JDK 11 or 20 to be optional by having projects use pipeline parameters to specify them. I have tried:

        tools {
            if (pipelineParams.maven != 'system') {
                maven pipelineParams.maven
            }
            if (pipelineParams.jdk != 'system') {
                jdk pipelineParams.jdk
            }
        }

And the invoking repository's Jenkinsfile:

@Library('pipeline-library') _

debug_pipeline {
    Greeting = 'Goodbye'
    jdk = 'OpenJDK-20'
    maven = 'apache-maven-3.9.3'
}

However, this errors with debug_pipeline.groovy: 15: Expected to find ‘someTool "someVersion"’. It also seems that I cannot use when within tools.

So, how can I effectively allow projects to override the JDK using pipeline parameters?


Solution

  • You are right in stating that tool {} does not allow you to make tool inclusions conditional (within the curly brackets).

    The best way to fix/solve this is to add a default directly inside of def pipelineParams = [:]; these defaults will be overridden by the input of your Jenkinsfile (debug_pipeline {...}). This is done because you specified: body.resolveStrategy = Closure.DELEGATE_FIRST, body.delegate = pipelineParams and body() inside of def call (body) {}. Example:

    • vars/debug_pipeline.groovy
    def call (body) {
        def pipelineParams = [
             'GREETINGS' : 'Hi!'
             'JDK'       : 'OpenJDK-20',
             'MAVEN'     : 'apache-maven-3.9.3'
        ]
        body.resolveStrategy = Closure.DELEGATE_FIRST
        body.delegate = pipelineParams
        body()
        ...
    }
    
    • Jenkinsfile
    @Library('pipeline-library') _
    
    debug_pipeline {
        JDK    = 'OpenJDK-11'
        MAVEN  = 'apache-maven-3.8.8'
        CHEESE = 'GOUDA'
    }
    

    Would Result in:

    pipelineParams == [
         'GREETINGS' : 'Hi!'
         'JDK'       : 'OpenJDK-11',
         'MAVEN'     : 'apache-maven-3.8.8'
         'CHEESE'    : 'GOUDA'
    ]
    

    Considering you are using a pipeline library, you might even create a "helper" class (inside of src) and centralize tool versions. This is really helpful if you have multiple pipelines or many versions of a tool; So only the helper class has to change and not all pipelines and Jenkinsfiles. Example:

    • src/com/corp/lib/EnvironmentHelper.groovy
    package com.corp.lib
    
    class EnvironmentHelper implements Serializable {
        public static final String JDK_11 = 'OpenJDK-11'
        public static final String JDK_20 = 'OpenJDK-20'
        public static final String DEFAULT_JDK = JDK_11
    }
    

    This allows you to use:

    • vars/debug_pipeline.groovy
    import com.corp.lib.EnvironmentHelper
    def call (body) {
        def pipelineParams = [
             'JDK'       : EnvironmentHelper.DEFAULT_JDK,
             ...
        ]
        ...
    }
    
    • Jenkinsfile
    @Library('pipeline-library') _
    import com.corp.lib.EnvironmentHelper
    
    debug_pipeline {
        JDK  = EnvironmentHelper.JDK_20
        ...
    }