Environment variables get reset between gradle tasks (Jenkins) - jenkins

I need to pass environment variables to my executable and my unit tests. This works locally but not on Jenkins. On Jenkins, my environment variable gets reset in between gradle tasks
task setupEnv(type: Exec) {
commandLine 'export', "ABC=def"
}
test {
dependsOn 'setupEnv'
scanForTestClasses = false
include '**/*Test.*'
}
Note: I'm simplifying here for SO (I'm aware of the environment command in Gradle) but even with this simple example it works locally but not on Jenkins, meaning *Test.java files see nothing for System.getEnv("ABC"). I'm looking at how to not have Jenkins reset environment variables

There are two options to set dynamical env in pipeline. As a result these envs will be available globally (to all stages in the pipeline):
set it in a stage
stage('set date') {
steps {
script {
env.ANY_NAME_OF_THE_SCRIPT=sh(returnStdout: true, script: "date +%Y-%m-%d").trim()
}
}
}
set it in environment
pipeline {
agent {
label 'some_label'
}
environment {
HELLO = """${sh(
returnStdout: true,
script: 'echo hello'
).trim()}"""
}
}

Related

jenkins - overriding environment variables on agent

I want to be able to override default values per build, via "Run with parameters".
Currently, to enable someone to override environment variables on the agent I have this in my Jenkinsfile...
pipeline {
parameters {
string(name: 'build_tsc', defaultValue: '', description: 'Override the path to the tsc executable')
}
stages {
stage('Compiling') {
steps {
script {
if (params.build_tsc) {
echo "Compiling with tsc override: ${params.build_tsc}"
bat "${params.build_tsc}"
}
else if (!env.JENKINS_TSC) {
error("tsc not set on agent")
}
else {
echo "Compiling with agent tsc: ${env.JENKINS_TSC}"
bat "${env.JENKINS_TSC}"
}
}
}
}
}
}
Is there a better way?
You can override the values in the JENKINS UI Node configuration page:
${JENKINS_URL}/computer/{{NODE}}/configure:
We do this where specific nodes have different configurations and have a groovy job that updates them based on the labels we have assigned (eg: WL1035 vs WL1036) when we add nodes or change the configuration.
You can also install the Slave Setups plugin to perform Node Configuration at launch time:
The above assumes you wish to override a global ENV or tool configuration for all jobs on the node.

How to update Env vars from jenkins Powershell script

Hello Trying to update jenkins Env variables from Powershell script written in stage
pipeline {
agent { label 'master' }
environment {
def var1 = "default_value"
def var2 = "default var 2"
}
stages {
stage ('step-1') {
steps {
script {
powershell (returnStdout: true, script: '''
${env:var1} = "changed from powershell"
${env:var2} = "var2 changed from powershell"
''').trim()
}
}
}
stage ("step-2"){
steps {
echo var1
echo var2
}
}
}
}
I can access values but cannot change the same, Does Scope is limited to Powershell only?
By design, a subshell cannot modify the environment of its parent shell. Every powershell, sh, or bat step called within a Jenkinsfile spawns a new subshell to run the child processes. Therefore, any environment variable declared inside these steps are lost as soon as the child processes end and are not available to the pipeline Groovy script.
One way to do this currently in a Jenkinsfile is to assign the stdout of your subshell to a variable in the Groovy script itself.
script {
env.var1 = powershell(returnStdout: true, script: '<single command>').trim()
}
Evidently, this approach has serious limitations as you can run only one command at a time and that too, only if it would return an appropriate output to be used as a variable.
Another way is to write the values to a file and then read these values using Groovy script to set the environment variables downstream in your pipeline.
Edit
Based on your comment, if your stdout returns two distinct values as a string, you can try parsing them into separate values. For example:
script {
def output = powershell(returnStdout: true, script: '''
<command1>
<command2>
''')
println(output)
/*Prints:
value1
value2
*/
env.var1 = output.tokenize('\n')[0].trim() \\value1
env.var2 = output.tokenize('\n')[1].trim() \\value2
}

How to share environment variable value across different Jenkins Pipelines?

I have two Jenkins Pipelines :
Pipeline A : In a stage, I defined an environment variable called MAVEN_PROFILE (the user can choose a value from a list)
Pipeline B : I need to get the MAVEN_PROFILE environment variable value that was set in Pipeline A
I need two pipelines because I can't do it in a single Pipeline for process reason.
I saw there was some answers on how to share variable between stages within a single Pipeline but this not my case.
I want to share environment variable value between different Pipelines.
Pipeline A
pipeline {
agent any
...
stages {
stage('Profile Selection'){
steps {
script {
env.MAVEN_PROFILE = input message: 'Choose the profile :',
parameters: [choice(name: 'MAVEN_PROFILE',
choices: 'all\nserver\nclient', description: 'Profiles')]
}
}
}
stage(...){
steps {
script {
bat "mvn deploy -P ${env.MAVEN_PROFILE}"
}
}
}
... other stages
}
}
Pipeline B
pipeline {
agent any
...
stages {
... other stages
stage(...){
steps {
script {
bat "mvn release ... -P ${env.environmentVariableValueFromPipelineA}"
}
}
}
}
}
They're not running in the same environment, so they can't directly share environment variables. The easiest is probably to write these values to a file in the workspace in pipeline A, and read them back in in pipeline B. Something like this:
Pipeline A:
sh "echo ${MAVEN_PROFILE} > .MAVEN_PROFILE"
Pipeline B:
def MAVEN_PROFILE = sh(script: 'cat .MAVEN_PROFILE', returnStdout: true).trim()

iterate over environment variables in Jenkins Pipeline Groovy [duplicate]

Given a jenkins build pipeline, jenkins injects a variable env into the node{}. Variable env holds environment variables and values.
I want to print all env properties within the jenkins pipeline. However, I do no not know all env properties ahead of time.
For example, environment variable BRANCH_NAME can be printed with code
node {
echo ${env.BRANCH_NAME}
...
But again, I don't know all variables ahead of time. I want code that handles that, something like
node {
for(e in env){
echo e + " is " + ${e}
}
...
which would echo something like
BRANCH_NAME is myBranch2
CHANGE_ID is 44
...
I used Jenkins 2.1 for this example.
According to Jenkins documentation for declarative pipeline:
sh 'printenv'
For Jenkins scripted pipeline:
echo sh(script: 'env|sort', returnStdout: true)
The above also sorts your env vars for convenience.
Another, more concise way:
node {
echo sh(returnStdout: true, script: 'env')
// ...
}
cf. https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#code-sh-code-shell-script
The following works:
#NonCPS
def printParams() {
env.getEnvironment().each { name, value -> println "Name: $name -> Value $value" }
}
printParams()
Note that it will most probably fail on first execution and require you approve various groovy methods to run in jenkins sandbox. This is done in "manage jenkins/in-process script approval"
The list I got included:
BUILD_DISPLAY_NAME
BUILD_ID
BUILD_NUMBER
BUILD_TAG
BUILD_URL
CLASSPATH
HUDSON_HOME
HUDSON_SERVER_COOKIE
HUDSON_URL
JENKINS_HOME
JENKINS_SERVER_COOKIE
JENKINS_URL
JOB_BASE_NAME
JOB_NAME
JOB_URL
You can accomplish the result using sh/bat step and readFile:
node {
sh 'env > env.txt'
readFile('env.txt').split("\r?\n").each {
println it
}
}
Unfortunately env.getEnvironment() returns very limited map of environment variables.
Why all this complicatedness?
sh 'env'
does what you need (under *nix)
Cross-platform way of listing all environment variables:
if (isUnix()) {
sh env
}
else {
bat set
}
Here's a quick script you can add as a pipeline job to list all environment variables:
node {
echo(env.getEnvironment().collect({environmentVariable -> "${environmentVariable.key} = ${environmentVariable.value}"}).join("\n"))
echo(System.getenv().collect({environmentVariable -> "${environmentVariable.key} = ${environmentVariable.value}"}).join("\n"))
}
This will list both system and Jenkins variables.
I use Blue Ocean plugin and did not like each environment entry getting its own block. I want one block with all the lines.
Prints poorly:
sh 'echo `env`'
Prints poorly:
sh 'env > env.txt'
for (String i : readFile('env.txt').split("\r?\n")) {
println i
}
Prints well:
sh 'env > env.txt'
sh 'cat env.txt'
Prints well: (as mentioned by #mjfroehlich)
echo sh(script: 'env', returnStdout: true)
The pure Groovy solutions that read the global env variable don't print all environment variables (e. g. they are missing variables from the environment block, from withEnv context and most of the machine-specific variables from the OS). Using shell steps it is possible to get a more complete set, but that requires a node context, which is not always wanted.
Here is a solution that uses the getContext step to retrieve and print the complete set of environment variables, including pipeline parameters, for the current context.
Caveat: Doesn't work in Groovy sandbox. You can use it from a trusted shared library though.
def envAll = getContext( hudson.EnvVars )
echo envAll.collect{ k, v -> "$k = $v" }.join('\n')
Show all variable in Windows system and Unix system is different, you can define a function to call it every time.
def showSystemVariables(){
if(isUnix()){
sh 'env'
} else {
bat 'set'
}
}
I will call this function first to show all variables in all pipline script
stage('1. Show all variables'){
steps {
script{
showSystemVariables()
}
}
}
The easiest and quickest way is to use following url to print all environment variables
http://localhost:8080/env-vars.html/
The answers above, are now antiquated due to new pipeline syntax. Below prints out the environment variables.
script {
sh 'env > env.txt'
String[] envs = readFile('env.txt').split("\r?\n")
for(String vars: envs){
println(vars)
}
}
Includes both system and build environment vars:
sh script: "printenv", label: 'print environment variables'
if you really want to loop over the env list just do:
def envs = sh(returnStdout: true, script: 'env').split('\n')
envs.each { name ->
println "Name: $name"
}
I found this is the most easiest way:
pipeline {
agent {
node {
label 'master'
}
}
stages {
stage('hello world') {
steps {
sh 'env'
}
}
}
}
You can get all variables from your jenkins instance. Just visit:
${jenkins_host}/env-vars.html
${jenkins_host}/pipeline-syntax/globals
ref: https://www.jenkins.io/doc/pipeline/tour/environment/
node {
sh 'printenv'
}
You can use sh 'printenv'
stage('1') {
sh "printenv"
}
another way to get exactly the output mentioned in the question:
envtext= "printenv".execute().text
envtext.split('\n').each
{ envvar=it.split("=")
println envvar[0]+" is "+envvar[1]
}
This can easily be extended to build a map with a subset of env vars matching a criteria:
envdict=[:]
envtext= "printenv".execute().text
envtext.split('\n').each
{ envvar=it.split("=")
if (envvar[0].startsWith("GERRIT_"))
envdict.put(envvar[0],envvar[1])
}
envdict.each{println it.key+" is "+it.value}
I suppose that you needed that in form of a script, but if someone else just want to have a look through the Jenkins GUI, that list can be found by selecting the "Environment Variables" section in contextual left menu of every build
Select project => Select build => Environment Variables

How to set PATH in Jenkins Declarative Pipeline

In Jenkins scripted pipeline you can set PATH env variable like this :
node {
git url: 'https://github.com/jglick/simple-maven-project-with-tests.git'
withEnv(["PATH+MAVEN=${tool 'M3'}/bin"]) {
sh 'mvn -B verify'
}
}
Notice the PATH+MAVEN as explained here https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/#code-withenv-code-set-environment-variables :
A list of environment variables to set, each in the form
VARIABLE=value or VARIABLE= to unset variables otherwise defined. You
may also use the syntax PATH+WHATEVER=/something to prepend /something
to $PATH.
But I didn't find how to do it in declarative pipeline using environment syntax (as explained here : https://jenkins.io/doc/pipeline/tour/environment).
environment {
DISABLE_AUTH = 'true'
DB_ENGINE = 'sqlite'
}
Ideally I would like to update the PATH to use custom tools for all my stages.
It is possible with environment section:
pipeline {
agent { label 'docker' }
environment {
PATH = "/hot/new/bin:${env.PATH}"
}
stages {
stage ('build') {
steps {
echo "PATH is: ${env.PATH}"
}
}
}
}
See this answer for info.
As a workaround, you can define an environment variable and use it in the sh step:
pipeline {
environment {
MAVEN_HOME = tool('M3')
}
stages {
stage(Maven') {
sh '${MAVEN_HOME}/bin/mvn -B verify'
}
}
}
Check the following link, this explains how to configure your tools.
Using the declarative pipeline things become a bit different but overall it is easier to understand.
declarative-maven-project
Using the tool section in pipeline is only allowed for pre-installed Global Tools. Some tools are provided by plugins, but if it not exists I'am afraid you cannot use the environment setup via pipeline tool declaration.
I hope to be wrong!

Resources