14

Previously asked a question about how to overwrite variables defined in an environment directive and it seems that's not possible.

I want to set a variable in one stage and have it accessible to other stages. In a declarative pipeline it seems the only way to do this is in a script{} block.

For example I need to set some vars after checkout. So at the end of the checkout stage I have a script{} block that sets those vars and they are accessible in other stages.

This works, but it feels wrong. And for the sake of readability I'd much prefer to declare these variables at the top of the pipeline and have them overwritten. So that would mean having a "set variables" stage at the beginning with a script{} block that just defines vars- thats ugly.

I'm pretty sure I'm missing an obvious feature here. Do declarative pipelines have a global variable feature or must I use script{}

Viraj Amarasinghe
  • 911
  • 10
  • 20
red888
  • 27,709
  • 55
  • 204
  • 392
  • 2
    Have you tried just using something like `def myVar` outside of the `pipeline` definition? – mkobit Dec 08 '17 at 16:25

6 Answers6

15

This is working without an error,

def my_var
pipeline {
    agent any
    environment {
        REVISION = ""
    }
    stages {
        stage('Example') {
            steps {
                script{
                    my_var = 'value1'
                }
            }
        }

        stage('Example2') {
            steps {
                script{
                    echo "$my_var" 
                }
            }
        }
    }
}
felipecrs
  • 549
  • 4
  • 16
Viraj Amarasinghe
  • 911
  • 10
  • 20
10

Like @mkobit says, you can define the variable to global level out of pipeline block. Have you tried that?

def my_var
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                my_var = 'value1'
            }
        }

        stage('Example2') {
            steps {
                printl(my_var)
            }
        }

    }
}
Daniel Majano
  • 976
  • 2
  • 10
  • 18
  • 3
    this is not working. @red888 can you please let us know what worked. – vinay May 14 '18 at 07:30
  • you should prefix variables that you mutate with @Field. see my answer https://stackoverflow.com/a/74182228/1391012 this avoid surprises and weird behavior where your mutation is lost – fredericrous Oct 24 '22 at 13:58
  • This does not work unless you puth the my_var = 'value1' inside script block. Also, If you do this and then rerun stage 2 it won't have the value from stage one correct? – user3307624 Jan 13 '23 at 22:48
5

For strings, add it to the 'environment' block:

pipeline {
  environment {
    myGlobalValue = 'foo'
  }
}

But for non-string variables, the easiest solution I've found for declarative pipelines is to wrap the values in a method.

Example:

pipeline {
  // Now I can reference myGlobalValue() in my pipeline.
  ...
}

def myGlobalValue() {
    return ['A', 'list', 'of', 'values']

// I can also reference myGlobalValue() in other methods below
def myGlobalSet() {
    return myGlobalValue().toSet()
}
txace
  • 81
  • 2
  • 3
5

@Sameera's answer is good for most use cases. I had a problem with appending operator += though. So this did NOT work (MissingPropertyException):

def globalvar = ""
pipeline {
  stages {
    stage("whatever) {
      steps {
        script {
          globalvar += "x"
        }
      }
    }
  }
}

But this did work:

globalvar = ""
pipeline {
  stages {
    stage("whatever) {
      steps {
        script {
          globalvar += "x"
        }
      }
    }
  }
}
akostadinov
  • 17,364
  • 6
  • 77
  • 85
2

The correct syntax is:

  • For global static variable

somewhere at the top of the file, before pipeline {, declare:

def MY_VAR = 'something'
  • For global variable that you can edit and reuse accross stages:

At the top of your file, add an import to Field:

import groovy.transform.Field

somewhere before pipeline {, declare:

@Field def myVar

then inside your step, inside a script, set the variable

  stage('some stage') {
    steps {
      script {
        myVar = 'I mutate myVar with success'
      }
    }
  }
  • to go even further, you can declare functions:

before the pipeline {

def initSteps() {
    cleanWs()
    checkout scm
}

and then

  stages {
    stage('Init') {
      steps {
        initSteps()
      }
    }
  }
fredericrous
  • 2,833
  • 1
  • 25
  • 26
0

This worked for me

pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
               script{
                  env.my_var = 'value1'
               }
            }
        }

        stage('Example2') {
            steps {
                printl(my_var)
            }
        }

    }
}