setting environment variable in jenkins scripted pipeline - jenkins

Im trying to set a environment variable(VIRTUALENV) in Jenkins - stage(check_style) and use that in the shell but it throws a error.
withEnv(['VIRTUAL_ENV=${env.WORKSPACE}/venv']){
stage ('Check_style') {
sh """
export PATH=${VIRTUAL_ENV}/bin:${PATH}
make flake8 | tee report/flake8.log || true
"""
}
}
Error:-
PATH=${env.WORKSPACE}/venv/bin:/usr/bin:/bin:/usr/sbin:/sbin: bad substitution

withEnv(["VIRTUAL_ENV=${env.WORKSPACE}/venv"]) should work

Related

unable to override env PATH variable in Jenkins

In Jenkins Server, there are two global environment variables defined. It's in Manage Jenkins -> Configure System -> Global Properties -> Environment variables
Name: MAVEN_HOME
Value: /var/home/tools/hudson.tasks.Maven_MavenInstallation/maven3.5.2
Name: PATH+EXTRA
$PATH:/usr/local/bin:$MAVEN_HOME/bin
I see that PATH+EXTRA will add the MAVEN PATH to the PATH environment variable. This is how my existing Server set up is. Now I need to update Jenkins with Maven 3.8.2, so I downloaded Maven 3.8.2 in the server using Manage Jenkins -> Global Tool Configuration -> Maven Installations. Now I am trying to override the global MAVEN_HOME and PATH to point to MAVEN_3.8.2 path.
In the Jenkins pipeline script
def maven_version = 'maven_3.8.2'
pipeline {
agent any
stages {
stage ('build') {
steps {
withEnv(["PATH+MAVEN=${tool maven_version}/bin"]) {
echo "PATH is: $PATH"
echo env.PATH
echo env.MAVEN_HOME
sh 'env'
sh 'mvn --version'
}
}
}
}
}
Results:
echo "PATH is: $PATH" =>
/var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.8.2/bin:/opt/java/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2/bin:/opt/java/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo env.PATH => /var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.8.2/bin:/opt/java/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2/bin:/opt/java/jdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo env.MAVEN_HOME =>
/var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2
sh 'env' => prints all the environment variables. Noticed following:
MAVEN_HOME=/var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2
PATH=$PATH:/usr/local/bin:/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2/bin:/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.8.2/bin:/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/var/jenkins_home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2/bin:/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Why is the PATH is being appending with Maven 3.5.2 in the front of the path. How can I let PATH point to Maven 3.8.2?
sh 'mvn --version' => Apache Maven 3.5.2
Maven home: /var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.5.2
How do I get the mvn --version result with maven3.8.2?
Note: I also tried with free style project, and used following commands to override the values but the mvn --version is always printing 3.5.2. Any idea if it is a bug with Jenkins unable to override the path or is there any way to do it?
export MAVEN_HOME=/var/home/tools/hudson.tasks.Maven_MavenInstallation/maven_3.8.2
export PATH=$PATH:$MAVEN_HOME/bin
The format you used to modify the PATH variable uses concatenation that prepends the new value to the existing one. It means that
PATH+MAVEN=${tool maven_version}/bin
is an equivalent of:
PATH=${tool maven_version}/bin:$PATH
You can solve this issue by overriding the PATH variable explicitly and putting the new path at the end of the variable. Try to test the pipeline like this one:
def maven_version = 'maven_3.8.2'
pipeline {
agent any
stages {
stage ('build') {
steps {
withEnv(["PATH=${tool maven_version}/bin:$PATH"]) {
echo "PATH is: $PATH"
echo env.PATH
echo env.MAVEN_HOME
sh 'env'
sh 'mvn --version'
}
}
}
}
}

Jenkins pipeline sh step returns error "process apparently never started"

I am stuck in trying to get a Jenkinsfile to work. It keeps failing on sh step and gives the following error
process apparently never started in /home/jenkins/workspace
...
(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)
I have tried adding
withEnv(['PATH+EXTRA=/usr/sbin:/usr/bin:/sbin:/bin'])
before sh step in groovy file
also tried to add
/bin/sh
in Manage Jenkins -> Configure System in the shell section
I have also tried replacing the sh line in Jenkinsfile with the following:
sh "docker ps;"
sh "echo 'hello';"
sh ./build.sh;"
sh ```
#!/bin/sh
echo hello
```
This is the part of Jenkinsfile which i am stuck on
node {
stage('Build') {
echo 'this works'
sh 'echo "this does not work"'
}
}
expected output is "this does not work" but it just hangs and returns the error above.
what am I missing?
It turns out that the default workingDir value for default jnlp k8s slave nodes is now set to /home/jenkins/agent and I was using the old value /home/jenkins
here is the config that worked for me
containerTemplate(name: 'jnlp', image: 'lachlanevenson/jnlp-slave:3.10-1-alpine', args: '${computer.jnlpmac} ${computer.name}', workingDir: '/home/jenkins/agent')
It is possible to get the same trouble with the malformed PATH environment variable. This prevents the sh() method of the Pipeline plugin to call the shell executable. You can reproduce it on a simple pipeline like this:
node('myNode') {
stage('Test') {
withEnv(['PATH=/something_invalid']) {
/* it hangs and fails later with "process apparently never started" */
sh('echo Hello!')
}
}
}
There is variety of ways to mangle PATH. For example you use withEnv(getEnv()) { sh(...) } where getEnv() is your own method which evaluates the list of environment variables depending on the OS and other conditions. If you make a mistake in the getEnv() method and PATH gets overwritten you get it reproduced.

Defining a variable in shell script portion of Jenkins Pipeline

I'm trying to dynamically define a variable I use later in a some shell commands of my Jenkins pipeline and it's throwing an exception. I even tried to predefine the variable from an environment section to no avail. Is this a prohibited operation? My other variable myVar seems to work fine, but it's a constant through the pipeline.
pipeline {
agent any
environment {
py2Ana=""
myVar="ABCDE"
}
stages {
stage('Stage1') {
steps {
sh """
echo myVar=$myVar
echo Find Anaconda2 Python installation...
py2Ana=`which -a python | grep --max-count=1 anaconda2`
if [[ -z "$py2Ana" ]]; then
echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
exit 1 # terminate and indicate error
fi
"""
}
}
}
Exception
groovy.lang.MissingPropertyException: No such property: py2Ana for class: groovy.lang.Binding
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:242)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:288)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:292)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:268)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at WorkflowScript.run(WorkflowScript:21)
As #jxramos stated, Jenkins is trying to resolve the variables in the script. It interprets any $string as a variable that needs substitution.
The solution is to escape the $ of the in-script variables, as follows:
pipeline {
agent any
stages {
stage('test stage'){
steps {
sh """#!/bin/bash
myvar=somevalue
echo "The value is \$myvar"
"""
}
}
}
}
There appears to be a variable substitution precedence that Jenkins enforces in a preprocessing step if you will. In other words there's no delayed expansion as one would find in the Windows batch file behavior with setlocal ENABLEDELAYEDEXPANSION. This explains what's going on, and here's the test pipeline I used to determine this:
pipeline {
agent any
environment {
py2Ana="DEFAULT"
}
stages {
stage('Stage1') {
steps {
sh """
echo py2Ana=$py2Ana
py2Ana=Initialized
echo py2Ana Initialized=$py2Ana
"""
}
}
}
}
This yields the following console output...
Started by user unknown or anonymous
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] node
[Pipeline] {
[Pipeline] withEnv
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Stage1)
[Pipeline] sh
[TestPipeline] Running shell script
+ echo py2Ana=DEFAULT
py2Ana=DEFAULT
+ py2Ana=Initialized
+ echo py2Ana Initialized=DEFAULT
py2Ana Initialized=DEFAULT
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Another restriction that this poses is that you truly cannot use dynamic variables in the sh portion of the Jenkins declarative pipeline script since Jenkins will first attempt to resolve all variables before execution. Thus the following will always yield an error
sh """
for filename in /tmp/**; do
echo filename=$filename
done
"""
The error being...
groovy.lang.MissingPropertyException: No such property: filename for class: groovy.lang.Binding
One would need to define a script dynamically (after figuring out a way to escape the $ to write to file), or already have it in the source, to be executed.
The error itself seems really to be caused by the assignment of an empty string.
However: Do you really need that environment variable to be defined in the Jenkinsfile?
To me it looks like you just want to set and read the variable from within the shell script. But the way it's coded the if [[ -z "$py2Ana" ]]; then would never pick up the value set by the shell script - it would always want to use a property from the Jenkinsfile - which didn't work.
You could use if [[ -z "${env.py2Ana}" ]]; then for the if condition which would fix that error but it still would not pick up the value set by the previous line but always read the empty string set in the Jenkinsfile.
To solve this you could either enclose the string in single quotes for the whole string like (maybe you even want to get rid of the myVar then)...:
pipeline {
agent any
stages {
stage('Stage1') {
steps {
sh '''
echo Find Anaconda2 Python installation...
py2Ana=`which -a python | grep --max-count=1 anaconda2`
if [[ -z "$py2Ana" ]]; then
echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
exit 1 # terminate and indicate error
fi
'''
}
}
}
}
... or add a backslash right before $py2Ana like:
pipeline {
agent any
stages {
stage('Stage1') {
steps {
sh """
echo Find Anaconda2 Python installation...
py2Ana=`which -a python | grep --max-count=1 anaconda2`
if [[ -z "\$py2Ana" ]]; then
echo ERROR: must have a valid Anaconda 2 distribution installed and on the PATH for this job.
exit 1 # terminate and indicate error
fi
"""
}
}
}
}
Either way without referencing env.py2Ana in the code I doubt the environment block in the Jenkinsfile still would make sense - that's why I removed it from the examples.
Just add a value to py2Ana
environment {
py2Ana="1234"
myVar="ABCDE"
}
It doesn't create the variable in environment if you pass a empty string :)

Passing parameter in Jenkinsfile to a shell command within a Docker container

I have a Jenkinsfile with a String parameter env_vars. With this parameter I want to set custom environment variables which I want to set later with a shell command within the started Docker container. It is important to set such environment variables on runtime.
This is my simple Jenkinsfile:
pipeline {
options {
timestamps()
}
agent {
node {
label 'master'
}
}
parameters {
string(name: 'env_vars', defaultValue: 'MY_USER_PASSWORD=abc MY_USER_NAME=def', description: 'the ENV variables to set before starting the tests')
}
stages {
stage ('TESTS') {
steps {
script {
withDockerRegistry([credentialsId: 'XXX', url: 'http://example.com']) {
withDockerContainer(image: 'myDockerImage:latest') {
withCredentials([string(credentialsId: 'cred1', variable: 'cred1'), string(credentialsId: 'cred2', variable: 'cred2')]) {
sh '''
# here we go to run npm
${env_vars} npm run test -- chrome --tag=enabled
'''
}
}
}
}
}
}
}
}
And this error I will get in Jenkins:
/var/lib/jenkins/jenkins3/jobs/zTestMG/workspace#tmp/durable-40340d0e/script.sh: line 4: MY_USER_PASSWORD=abc: command not found
One possible workaround is using eval for the shell command:
eval "${env_vars} npm run test -- chrome --tag=enabled"
But I don't want to use eval, because later I have to evaluate the result of the npm run command. And when using eval I will get new problems.
How can I solve the problem to use the String parameter in the shell command within the Docker container?
I have found a possible solution for me. I replace my shell command in two different once:
export ${env_vars}
npm run ${run_script_method} -- ${browser} --tag=${tags}

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

Resources