I have a multi-branch pipeline project with a scripted Jenkinsfile in SCM. I want to set environment variables in my pipelines from a shared global function. My shared global function looks like this:
#!/usr/bin/groovy
def call(String envName = 'staging') {
def json = libraryResource 'env-config.yaml'
def config = readYaml text: json
def envObj = config.environments.find{it.name == envName}
environment {
PROJECT = ${envObj.project}
ARTIFACTS_REPOSITORY = ${envObj.artifacts_repository}
DOCKER_REGISTRY_PREFIX = ${envObj.docker_registry_prefix}
}
println "${envObj}"
}
But in my Jenkinsfile, I don't see these set:
timestamps {
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'xxx', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
node('klm') {
try {
def revisionTag
loadEnvConfig('staging')
println "project=${env.PROJECT}, repo=${env.ARTIFACTS_REPOSITORY}"
...
env.PROJECT
and env.ARTIFACTS_REPOSITORY
are both null. If I return the envObj
from the function and print the properties in the pipeline, I can see them. Is it possible to set environment variables from my function?
Edit: I just realized that I am unable to set any environment variables in my Jenkinsfile in a multi-branch pipeline. E.g. both these patterns don't work
timestamps {
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'xxx', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
node('klm') {
try {
environment {
FOO = "bar"
}
println "project=${env.FOO}"
...
timestamps {
withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'xxx', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) {
node('klm') {
try {
withEnv(["FOO=BAR"]) {
println "project=${env.FOO}"
...
Search and select System (Control Panel). Click on the Advanced system settings link and then click Environment Variables. Under the section System Variables, select the environment variable you want to edit, and click Edit. If the environment variable you want doesn't exist, click New.
Jenkins environment variable is a global variable, exposed via env variable and used in Jenkins pipelines and anywhere into Jenkinsfile. Any value stored as the environment variable in the env variable is of string type.
Under Build Environment check Set environment variables through a file. give the path of that file here. If the environment variable is created in the first job then again you can save all the environment variable in a file and browse it using the above method. Install this plugin and go to job configuration paeg.
I'm not totally sure what environment
is and why it isn't failing the run for you. PROJECT = ${envObj.project}
is not valid Groovy, so that block is not getting executed. It looks like you are trying to use the environment
directive for declarative pipelines, but, you are using scripted pipelines. The options below are only valid for scripted pipelines due to limitations of shared libraries and declarative pipelines.
In your current code, you aren't modifying any global script variables or returning values to be used in other steps, so they do not take any effect. You have a couple different approaches depending on the API you want to present to consumers.
The first option is to just modify the env
global variable:
env.PROJECT = envObj.project
env.ARTIFACTS_REPOSITORY = envObj.artifacts_repository
env.DOCKER_REGISTRY_PREFIX = envObj.docker_registry_prefix
These will modify the global env
state that will be available everywhere else in the script (unless they are overwritten or removed).
Another option, is to write the method using the existing withEnv
step and allow consumers to supply a Closure
body. Here is an example where I have renamed the function from loadEnvConfig
to withEnvConfig
:
def call(String envName = 'staging', Closure body) {
// Previous code...
withEnv([
"PROJECT=${envObj.project}",
"ARTIFACTS_REPOSITORY=${envObj.artifacts_repository}",
"DOCKER_REGISTRY_PREFIX=${envObj.docker_registry_prefix}",
]) {
body()
}
}
Jenkinsfile
withEnvConfig('staging') {
println "In block project=${env.PROJECT}, repo=${env.ARTIFACTS_REPOSITORY}"
}
println "Out of block project=${env.PROJECT}, repo=${env.ARTIFACTS_REPOSITORY}"
Inside of the body they are set to the values of withEnv
. Outside of the block, they are reset.
I much prefer this sort of pattern to modifying global state.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With