Environment in Jenkins Pipeline has no variables - jenkins

Because I couldn't use an environment variable that I thought should exist, I printed all the environment variables in my Jenkins Pipeline script:
node {
for(e in env) {
print "key = ${e.key}, value = ${e.value}"
}
}
This prints:
key = null, value = null
I'm very surprised by this.
Why are there no environment variables?

Seems to be a bug/limitation. If you look at the implementation, there is no support for iteration.
The following works as a workaround:
node {
for(e in env.getEnvironment()) {
print "key = ${e.key}, value = ${e.value}"
}
}

Related

Jenkins variable defined inside global variable(env variable)

I have defined an environment(global) variable in jenkins via configuration as
REPORT = "Test, ${CycleNumber},${JOB_NAME}"
I have 1 parameter defined in my pipeline called Cycle which has values new & update. Based on this cycle value CycleNumber should be updated and I tried it via groovy using script block in my pipeline as below
if(Cycle == "New")
{
CycleNumber = "12345"
}
else if (Cycle == "Update")
{
CycleNumber = "7890"
}
after this update if I do echo "${env.REPORT}" I get the value as "Test,,TestJob" where in the CycleNumber variable is not updated. Could you please let me know if there is a way to update this CycleNumber field ?
Don't rely on Groovy's String interpolation to replace the CycleNumber. You can have your own placeholder(e.g: _CYCLE_NUMBER_) in the environment variable which you can replace later in your flow. Take a look at the following example.
pipeline {
agent any
stages {
stage("Test") {
environment {
REPORT = "Test, _CYCLE_NUMBER_,${JOB_NAME}"
}
steps {
script {
def Cycle = 'New'
def CycleNumber = 'none'
if(Cycle == "New"){
CycleNumber = "12345"
} else if (Cycle == "Update") {
CycleNumber = "7890"
}
def newReport = "$REPORT".replace('_CYCLE_NUMBER_', CycleNumber)
echo "$newReport"
}
}
}
}
}
Also once you set the newReport variable, make sure you use the same variable. if you do "${env.REPORT}" you will always get the original value assigned the tne environment variable.
Here is an answer with a workaround here: Updating environment global variable in Jenkins pipeline from the stage level - is it possible?
TLDR:
You can't override a global environment variable that has been declared in environment(global), however you can use the withEnv() function to wrap your script block in your pipeline to reference the updated value, eg:
withEnv(['REPORT=...']) {
// do something with updated env.REPORT
}

How to pass a variable in Jenkins Credentials Helper Function

environment {
BRANCH_NAME = "${env.BRANCH_NAME}"
DEPLOYMENT_MACHINE = credentials('auto-deployment')
}
How to pass Variable to credentials Function like
environment {
BRANCH_NAME = "${env.BRANCH_NAME}"
DEPLOYMENT_MACHINE = credentials("${BRANCH_NAME}")
}
"${exp}" is Groovy String interpolation, it is an alternative to "" + exp + "".
thus you can simply do
def deploymentBranchCred = credential(env.BRANCH_NAME)
environment {
DEPLOYMENT_MACHINE = credentials("${env.BRANCH_NAME}")
BRANCH = "${env.BRANCH_NAME}"
}
It's Working Fine.! issue with BRANCH_NAME as declared again in the environment.

How to use env variable inside triggers section in jenkins pipeline?

Reading the properties file for the node label and triggerConfigURL, node label works, but I couldn't read and set triggerConfigURL from environment.
def propFile = "hello/world.txt" //This is present in workspace, and it works.
pipeline {
environment {
nodeProp = readProperties file: "${propFile}"
nodeLabel = "$nodeProp.NODE_LABEL"
dtcPath = "$nodeProp.DTC"
}
agent { label env.nodeLabel } // this works!! sets NODE_LABEL value from the properties file.
triggers {
gerrit dynamicTriggerConfiguration: 'true',
triggerConfigURL: env.dtcPath, // THIS DON'T WORK, tried "${env.dtcPath}" and few other notations too.
serverName: 'my-gerrit-server',
triggerOnEvents: [commentAddedContains('^fooBar$')]
}
stages {
stage('Print Env') {
steps {
script {
sh 'env' // This prints "dtcPath=https://path/of/the/dtc/file", so the dtcPath env is set.
}
}
}
After running the job, the configuration is as below:
Of the env and triggers clauses Jenkins runs one before the other, and it looks like you have experimentally proven that triggers run first and env second. It also looks like agent runs after env as well.
While I don't know why the programmers have made this specific decision, I think you are in a kind of a chicken-and-egg problem, where you want to define the pipeline using a file but can only read the file once the pipeline is defined and running.
Having said that, the following might work:
def propFile = "hello/world.txt"
def nodeProp = null
node {
nodeProp = readProperties file: propFile
}
pipeline {
environment {
nodeLabel = nodeProp.NODE_LABEL
dtcPath = nodeProp.DTC
}
agent { label env.nodeLabel }
triggers {
gerrit dynamicTriggerConfiguration: 'true',
triggerConfigURL: nodeProp.DTC,
//etc.

Conditional environment variables in Jenkins Declarative Pipeline

I'm trying to get a declarative pipeline that looks like this:
pipeline {
environment {
ENV1 = 'default'
ENV2 = 'default also'
}
}
The catch is, I'd like to be able to override the values of ENV1 or ENV2 based on an arbitrary condition. My current need is just to base it off the branch but I could imagine more complicated conditions.
Is there any sane way to implement this? I've seen some examples online that do something like:
stages {
stage('Set environment') {
steps {
script {
ENV1 = 'new1'
}
}
}
}
But I believe this isn't setting the actually environment variable, so much as it is setting a local variable which is overriding later calls to ENV1. The problem is, I need these environment variables read by a nodejs script, and those need to be real machine environment variables.
Is there any way to set environment variables to be dynamic in a jenkinsfile?
Maybe you can try Groovy's ternary-operator:
pipeline {
agent any
environment {
ENV_NAME = "${env.BRANCH_NAME == "develop" ? "staging" : "production"}"
}
}
or extract the conditional to a function:
pipeline {
agent any
environment {
ENV_NAME = getEnvName(env.BRANCH_NAME)
}
}
// ...
def getEnvName(branchName) {
if("int".equals(branchName)) {
return "int";
} else if ("production".equals(branchName)) {
return "prod";
} else {
return "dev";
}
}
But, actually, you can do whatever you want using the Groovy syntax (features that are supported by Jenkins at least)
So the most flexible option would be to play with regex and branch names...So you can fully support Git Flow if that's the way you do it at VCS level.
use withEnv to set environment variables dynamically for use in a certain part of your pipeline (when running your node script, for example). like this (replace the contents of an sh step with your node script):
pipeline {
agent { label 'docker' }
environment {
ENV1 = 'default'
}
stages {
stage('Set environment') {
steps {
sh "echo $ENV1" // prints default
// override with hardcoded value
withEnv(['ENV1=newvalue']) {
sh "echo $ENV1" // prints newvalue
}
// override with variable
script {
def newEnv1 = 'new1'
withEnv(['ENV1=' + newEnv1]) {
sh "echo $ENV1" // prints new1
}
}
}
}
}
}
Here is the correct syntax to conditionally set a variable in the environment section.
environment {
MASTER_DEPLOY_ENV = "TEST" // Likely set as a pipeline parameter
RELEASE_DEPLOY_ENV = "PROD" // Likely set as a pipeline parameter
DEPLOY_ENV = "${env.BRANCH_NAME == 'master' ? env.MASTER_DEPLOY_ENV : env.RELEASE_DEPLOY_ENV}"
CONFIG_ENV = "${env.BRANCH_NAME == 'master' ? 'MASTER' : 'RELEASE'}"
}
I managed to get this working by explicitly calling shell in the environment section, like so:
UPDATE_SITE_REMOTE_SUFFIX = sh(returnStdout: true, script: "if [ \"$GIT_BRANCH\" == \"develop\" ]; then echo \"\"; else echo \"-$GIT_BRANCH\"; fi").trim()
however I know that my Jenkins is on nix, so it's probably not that portable
Here is a way to set the environment variables with high flexibility, using maps:
stage("Environment_0") {
steps {
script {
def MY_MAP = [ME: "ASSAFP", YOU: "YOUR_NAME", HE: "HIS_NAME"]
env.var3 = "HE"
env.my_env1 = env.null_var ? "not taken" : MY_MAP."${env.var3}"
echo("env.my_env1: ${env.my_env1}")
}
}
}
This way gives a wide variety of options, and if it is not enough, map-of-maps can be used to enlarge the span even more.
Of course, the switching can be done by using input parameters, so the environment variables will be set according to the input parameters value.
pipeline {
agent none
environment {
ENV1 = 'default'
ENV2 = 'default'
}
stages {
stage('Preparation') {
steps {
script {
ENV1 = 'foo' // or variable
ENV2 = 'bar' // or variable
}
echo ENV1
echo ENV2
}
}
stage('Build') {
steps {
sh "echo ${ENV1} and ${ENV2}"
}
}
// more stages...
}
}
This method is more simple and looks better. Overridden environment variables will be applied to all other stages also.
I tried to do it in a different way, but unfortunately it does not entirely work:
pipeline {
agent any
environment {
TARGET = "${changeRequest() ? CHANGE_TARGET:BRANCH_NAME}"
}
stages {
stage('setup') {
steps {
echo "target=${TARGET}"
echo "${BRANCH_NAME}"
}
}
}
}
Strangely enough this works for my pull request builds (changeRequest() returning true and TARGET becoming my target branch name) but it does not work for my CI builds (in which case the branch name is e.g. release/201808 but the resulting TARGET evaluating to null)

How to set a dynamic variable as global variable in jenkins?

I need to set a global variable with the value build_{BUILD_NUMBER}(jenkins global variable), which is dynamic. How can I set this in jenkins global properties?
How can it recognize the build number I'm referring to ?
using a declarative pipeline, you can set an environment variable based on this other environment variable (BUILD_NUMBER) like this:
pipeline {
agent { label 'docker' }
environment {
MY_BUILD_IDENTIFIER = "build_${env.BUILD_NUMBER}"
}
stages {
stage('hot_stage') {
steps {
echo "MY_BUILD_IDENTIFIER: ${env.MY_BUILD_IDENTIFIER}"
}
}
}
}
produces output like this:
[Pipeline] echo
MY_BUILD_IDENTIFIER: build_153
Here is an example script, how to alter global environment variables:
nodes = Jenkins.instance.globalNodeProperties
nodes.getAll(hudson.slaves.EnvironmentVariablesNodeProperty.class)
if ( nodes.size() != 1 ) {
println("error: unexpected number of environment variable containers: ${nodes.size()}, expected: 1")
} else {
envVars = nodes[0].envVars
envVars[args[0]] = args[1]
Jenkins.instance.save()
println("okay")
}
reference:
https://gist.github.com/johnyzed/2af71090419af2b20c5a

Resources