74

I have a Jenkinsfile with some global variables and some stages. can I update the global variable out from a stage?

An example:

pipeline {
  agent any

  environment {                 
    PASSWD = "${sh(returnStdout: true, script: 'python -u do_some_something.py')}"
    ACC = "HI"
  }

  stage('stage1') {
      when { expression { params.UPDATE_JOB == false } }

      steps{
        script {
          def foo= sh(  returnStdout: true, script: 'python -u do_something.py ')
          env.ACC =  foo
          println foo
          print("pw")
          println env.PASSWD
       }
     }  
   }
}

Is it possible to update the ACC variable with the value from foo, so that I can use the ACC Variable in the next stage?

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
Marvin Kallohn
  • 943
  • 3
  • 9
  • 12

2 Answers2

163

You can't override the environment variable defined in the environment {} block. However, there is one trick you might want to use. You can refer to ACC environment variable in two ways:

  • explicitly by env.ACC
  • implicitly by ACC

The value of env.ACC cannot be changed once set inside environment {} block, but ACC behaves in the following way: when the variable ACC is not set then the value of env.ACC gets accessed (if exists of course). But when ACC variable gets initialized in any stage, ACC refers to this newly set value in any stage. Consider the following example:

pipeline {
    agent any

    environment {
        FOO = "initial FOO env value"
    }

    stages {
        stage("Stage 1") {
            steps {
                script {
                    echo "FOO is '${FOO}'" // prints: FOO is 'initial FOO env value'

                    env.BAR = "bar"
                }
            }
        }

        stage("Stage 2") {
            steps {
                echo "env.BAR is '${BAR}'" // prints: env.BAR is 'bar'
                echo "FOO is '${FOO}'" // prints: FOO is 'initial FOO env value'
                echo "env.FOO is '${env.FOO}'" // prints: env.FOO is 'initial FOO env value'
                script {
                    FOO = "test2"
                    env.BAR = "bar2"
                }
            }
        }

        stage("Stage 3") {
            steps {
                echo "FOO is '${FOO}'" // prints: FOO is 'test2'
                echo "env.FOO is '${env.FOO}'" // prints: env.FOO is 'initial FOO env value'
                echo "env.BAR is '${BAR}'" // prints: env.BAR is 'bar2'

                script {
                    FOO = "test3"
                }

                echo "FOO is '${FOO}'" // prints: FOO is 'test3'
            }
        }
    }
}

And as you can see in the above example, the only exception to the rule is if the environment variable gets initialized outside the environment {} block. For instance, env.BAR in this example was initialized in Stage 1, but the value of env.BAR could be changed in Stage 2 and Stage 3 sees changed value.

UPDATE 2019-12-18

There is one way to override the environment variable defined in the environment {} block - you can use withEnv() block that will allow you to override the existing env variable. It won't change the value of the environment defined, but it will override it inside the withEnv() block. Take a look at the following example:

pipeline {
  agent any 

  stages {
    stage("Test") {
      environment {
        FOO = "bar"
      }

      steps {
        script {
          withEnv(["FOO=newbar"]) {
            echo "FOO = ${env.FOO}" // prints: FOO = newbar
          }
        }
      }
    }
  }
}

I also encourage you to check my "Jenkins Pipeline Environment Variables explained " video.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
  • 4
    Nice answer. I have been stuffing about with this for half a day, and this answer is exactly what i needed!! – donkeyx Sep 02 '19 at 06:56
  • 2
    Thank you for a great explanation with a working piece of code. I've been googling around in search of this for HOURS now. – Tommi Feb 27 '20 at 13:18
  • 2
    Thank you, Tommi! You can find even more examples in the blog post I wrote some time ago about this specific problem - https://e.printstacktrace.blog/jenkins-pipeline-environment-variables-the-definitive-guide/ – Szymon Stepniak Feb 27 '20 at 13:22
  • 1
    Updating environment variables looks easy now. Thanks – Kanav Narula Apr 19 '20 at 07:48
  • 8
    Wow, I never saw "cannot be changed once set inside environment {} block" anywhere in the Jenkins docs... I've been trying to figure out why setting `env.FOO` was not working at all in my script for about 6 hours now... :facepalm: Jenkins is such a nightmare. – CodingWithSpike Nov 24 '20 at 17:45
  • thanks for the tips, now i just do env.myvariable="sometihng" in the steps and i can use them. and overidem along any of the steps, i was putting them in the environmentStep =(... now is easy stuff, thanks again. – pelos Jul 08 '21 at 16:31
  • thanks, now i just create variables in the steps as env.Myvar so i can use them and overide them in other steps, =) – pelos Jul 21 '21 at 17:15
  • Could someone help point me to the Jenkins source code that implements this rule? i.e., "cannot be changed once set inside environment {} block" – kevin Aug 05 '23 at 03:22
  • it seems the global Variables in jenkins file was different with the configuration UI. I was using the pipeline configuration UI, i change the global variable value in somewhere (eg powershell) and it was changed accordingly with echo, but in the mail notification the value still was the initial one. that was confusing me a lot. – Chuenkei Sit Aug 24 '23 at 02:13
-2
loggedInUser = ""
node ("cm-windows") {
withEnv(["UserLoggedIn='Vrishali'"]) {
  echo env.UserLoggedIn       
   stage('Setup'){
    def buildCause = currentBuild.getBuildCauses()[0]
    def buildPrincipal = [type:"unknown", name:""]
    def buildUserCause = 
    currentBuild.getRawBuild().getCause(hudson.model.Cause.UserIdCause)
    buildPrincipal = [type:"user", name:buildCause.userId]
    print "Prining.."
    print buildCause.userId
    print "Checking the env var"
    print env.UserLoggedIn
    echo "[*] Starting build (id: ${env.UserLoggedIn}) on ${env.UserLoggedIn}"  
    loggedInUser = buildCause.userId
    echo "Loggedin user"
    print loggedInUser
    echo loggedInUser
   } 
}
stage ('override env'){         
   withEnv(["UserLoggedIn=${loggedInUser}"]) {
       echo "inside 2 stgae"
        echo loggedInUser
        print loggedInUser 
        echo "env"
        echo env.UserLoggedIn
   }
}

}