3

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?

AG6HQ
  • 514
  • 2
  • 5
  • 16
  • Globals are usually defined outside the pipeline block. See https://stackoverflow.com/questions/52063864/using-global-variables-in-jenkins-pipeline/54491768 – apr_1985 Mar 18 '21 at 17:16
  • Yes, your reference is to a Declarative Pipeline. My query is specifically for Scripted Pipelines. – AG6HQ Mar 18 '21 at 20:11
  • Apologies you are correct. You just need to remove the def. See full answer – apr_1985 Mar 19 '21 at 08:57

2 Answers2

9

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.

apr_1985
  • 1,764
  • 2
  • 14
  • 27
  • 1
    Not a good practice. See: https://stackoverflow.com/questions/50571316/strange-variable-scoping-behavior-in-jenkinsfile – artegen Aug 13 '21 at 18:59
  • Fair, using `field` is likely safer. But it think you would need a massively complex script for it to be an issue. In over 8 years of Jenkins. I’ve never hit an issue with it for the simplicity it provides. – apr_1985 Aug 14 '21 at 19:22
0
  1. You can pass the variable as an argument
......

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

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

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

  echo "<< testMethod()"
}
  1. If the above solution is not something you are looking for, using the @Field annotation will work as mentioned in this answer https://stackoverflow.com/a/37425799/10697591
import groovy.transform.Field

@Field def DEBUG = 1
def jenkinsNode = 'master'


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()"
}
Sai
  • 15
  • 4