papanito
papanito

Reputation: 2574

Global Variables in Jenkins Shared libraries

I have a Jenkinsfile which uses a shared library. I would like to make a global variable which is usable in all functions of the shared library, similar to the params object. However I always end up with

groovy.lang.MissingPropertyException: No such property: pipelineParams for class: groovy.lang.Binding

Following this guideline, I define a Field in the Jenkinsfile:

import org.apache.commons.io.FileUtils
@groovy.transform.Field
def pipelineParams

library identifier: 'pipeline-helper@master', retriever: modernSCM(
  [$class: 'GitSCMSource',
       remote: 'https://bitbucket/scm/jenkins/pipeline-helper.git',
       credentialsId: 'bitbucket.service.user'
  ])

defaultCiPipelineMSBuild {
    nodes     = 'TEST-NODES' /* label of jenkins nodes*/
    email     = '[email protected]' /* group mail for notifications */
    msbuild   = 'MSBUILD-DOTNET-4.6' /* ms build tool to use */ 
}

And then in the defaultCiPipelineMSBuild I set the pipelineParams

def call(body) {
    // evaluate the body block, and collect configuration into the object
    pipelineParams= [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = pipelineParams
    body()

    pipeline {
    ...

Later on I call a function buildApplication which want's to consume the variable:

def msBuildExe = tool pipelineParams.msbuild

Upvotes: 5

Views: 11536

Answers (2)

papanito
papanito

Reputation: 2574

As suggested by @Dillip it is possible to use env even so for non-strings. If the object stored as environment variable is a list or a map, it shall be deserialized

So I slightly changed the pipeline code to store the map as environment variable

def call(body) {
    // evaluate the body block, and collect configuration into the object
    pipelineParams= [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = pipelineParams
    body()

    env.pipelineParams = pipelineParams

    pipeline {
    ...

The pipeline is serialized and thus when reading returns a String

{ nodes=TEST-NODES,[email protected],msbuild=MSBUILD-DOTNET-4.6 }

Thus for usage it has to be deserialized

def pipelineParams = 
// Take the String value between the { and } brackets.
"${env.pipelineParams}"[1..-2]
    .split(', ')
    .collectEntries { entry -> 
        def pair = entry.split('=')
        [(pair.first()): pair.last()]
    }

//use map
pipelineParams.msbuild

You may add the deserialization into a function so you can use it in other places as well.

Upvotes: 0

Dillip Kumar Behera
Dillip Kumar Behera

Reputation: 289

Instead of creating a whole new pipeline parameter your self, did you try adding your variables into already available env parameter which you can use across your shared libraries?

env.param_name = "As per your requirement"

Can also be accessible with env.param_name or env[param_name] across shared library

Upvotes: 6

Related Questions