Search code examples
jenkinsjenkins-pipelinedryjenkins-groovyjenkins-declarative-pipeline

How to dynamically set environment variables in scripted jenkins pipeline?


I'm trying to dynamically set environment variables in the jenkins pipeline script.

I'm using a combination of .groovy and .jenkinsfile scripts to generate the stage{} definitions for a pipeline as DRY as possible.

I have a method below:

def generateStage(nameOfTestSet, pathToTestSet, machineLabel, envVarName, envVarValue)
{
    echo "Generating stage for ${nameOfTestSet} on ${machineLabel}"
    return node("${machineLabel}") {
        stage(nameOfTestSet)
        {
            /////// Area of interest ////////////
            environment {
                "${envVarName} = ${envVarValue}"
            }
           /////////////////////////////////////
            try {
                echo "Would run: "+pathToTestSet

            } finally {
                echo "Archive results here"
            }   
        }
    }
}

There's some wrapper code running this, but abstracting away we'd have the caller essentially use:

generateStage("SimpleTestSuite", "path.to.test", "MachineA", "SOME_ENV_VAR", "ENV_VALUE")

Where the last two parameters are the environment name (SOME_ENV_VAR) and the value (ENV_VALUE)

The equivalent declarative code would be:

stage("SimpleTestSuite")
{
  agent {
     label "MachineA"
  }
  environment = {
   SOME_ENV_VAR = ENV_VALUE
  }
  steps {
    echo "Would run" + "path.to.test" 
  }
  post {
    always {
      echo "Archive results"
      }
  }
}

However, when running this script, the environment syntax in first code block doesn't seem to affect the actual execution at all. If I echo the ${SOME_ENV_VAR} (or even echo ${envVarName} in case it took this variable name as the actual environment value) they both return null.

I'm wondering what's the best way to make this environment{} section as DRY / dynamic as possible?

I would prefer it if there's an extendable solution that can take in a list of environmentName=Value pairs, as this would be more general case.

Note: I have tried the withEnv[] solution for scripted pipelines, however this seems to have the same issue.


Solution

  • I figured out the solution to this.

    It is to use the withEnv([]) step.

    def generateStage(nameOfTestSet, pathToTestSet, machineLabel, listOfEnvVarDeclarations=[])
    {
        echo "Generating stage for ${nameOfTestSet} on ${machineLabel}"
        return node("${machineLabel}") {
            stage(nameOfTestSet)
            {
                withEnv(listOfEnvVarDeclarations) {
                    try {
                        echo "Would run: "+pathToTestSet
    
                    } finally {
                        echo "Archive results here"
                    }   
                }
            }
        }
    }
    

    And the caller method would be:

    generateStage("SimpleTestSuite", "path.to.test", "MachineA", ["SOME_ENV_VAR=\"ENV_VALUE\""])
    

    Since the withEnv([]) step can take in multiple environment variables, we can also do:

    generateStage("SimpleTestSuite", "path.to.test", "MachineA", ["SOME_ENV_VAR=\"ENV_VALUE\"", "SECOND_VAR=\"SECOND_VAL\""])
    

    And this would be valid and should work.