Search code examples
jenkinsjenkins-pipelinepipelinecloudbees

How do I define a global variable in a scripted jenkins pipeline


I would like to define a global variable in a Jenkins Scripted Pipeline that can be accessed anywhere in the pipeline. i.e. any stage, and any method. If I define the var at the top of the pipeline, it is works in the node declration, and in the stage declaration, but not in a called method. I don't want to use the env.XXX and withEnv([]) because I may have to call these methods from various different places, and that means using env sometimes, and not others.

Here is my simple JenkinsFile I use for a scripted pipeline:

def jenkinsNode = 'linux'
def DEBUG = 1

node(jenkinsNode){
  echo ">> node($jenkinsNode)"
  echo "DEBUG = $DEBUG"

  if (DEBUG) {
    echo "DEBUG is On"}
  else {
    echo "DEBUG is Off"
  }

  stage('test-this') {
    if (DEBUG) {
      echo "DEBUG is On"}
    else {
      echo "DEBUG is Off"
    }

    testMethod()
  }
  echo "<< node($jenkinsNode)"
}

def testMethod() {
  echo ">> testMethod()"

  if (DEBUG) {
    echo "DEBUG is On"}
  else {
    echo "DEBUG is Off"
  }

  echo "<< testMethod()"
}

When I run this I get:

Running on rh6-a01 in /jenkins_home/jenkins-rh6-a01/a98289de/workspace/test/test/test-global
[Pipeline] {
[Pipeline] echo
>> node(linux)
[Pipeline] echo
DEBUG = 1
[Pipeline] echo
DEBUG is On
[Pipeline] stage
[Pipeline] { (test-this)
[Pipeline] echo
DEBUG is Off
[Pipeline] echo
>> testMethod()
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
hudson.remoting.ProxyException: groovy.lang.MissingPropertyException: No such property: DEBUG for class: WorkflowScript
[...snip...]

How can I code this Jenkinsfile that will allow any method to access the DEBUG variable?


Solution

  • Removing the def from the declaration at the top resolves this.

    def jenkinsNode = 'linux'
    DEBUG = 1
    
    node(jenkinsNode){
      echo ">> node($jenkinsNode)"
      echo "DEBUG = $DEBUG"
    
      if (DEBUG) {
     .....
    

    Gives the output

    >> node(linux)
    [Pipeline] echo
    DEBUG = 1
    [Pipeline] echo
    DEBUG is On
    [Pipeline] stage
    [Pipeline] { (test-this)
    [Pipeline] echo
    DEBUG is On
    [Pipeline] echo
    >> testMethod()
    [Pipeline] echo
    DEBUG is On
    [Pipeline] echo
    << testMethod()
    [Pipeline] }
    [Pipeline] // stage
    [Pipeline] echo
    << node(docker)
    [Pipeline] }
    [Pipeline] // node
    [Pipeline] End of Pipeline
    Finished: SUCCESS
    

    This is because using def binds the variable to the current scope (which the method contents are not in). Not using def doesn't bind the scope allowing it to be used anywhere in the script.

    Do note thought that Groovy WONT stop you using the variable with def elsewhere which could cause unintended results e.g. adding a def DEBUG = 0 in the method

    def testMethod() {
      echo ">> testMethod()"
      def DEBUG = 0
    
      if (DEBUG) {
        echo "DEBUG is On"}
      else {
        echo "DEBUG is Off"
      }
    

    Would still run fine but would turn off DEBUG in that method.