Unable to determine what the withEnv is doing in Jenkinsfile - jenkins

I have just started writing Jenkinsfile. I was viewing the following two URLs to learn how to build a Java application, push it to Nexus and then invoke Ansible to deploy.
Redhat Jenkinsfile description
Actual Jenkinsfile
In the second link the following is mentioned several times whose function I am unable to understand:
withEnv(["PATH+MAVEN=${tool 'm3'}/bin"])
What I can find from net is that withEnv is used to create/override a environment variables. But what is ${tool 'm3'}/bin doing? Normally the syntax of withEnv is VARIABLE_NAME=value/expression.

The ${} is substituting a command/variable into the GString. See groovy docs on string Interpolation
From the looks of it, it would be safe to assume tool 'm3' is returning the install path which then gets /bin appended.
So the end result would be
PATH+MAVEN=/my/path/to/m3/etc/bin

Additionally to #metalisticpain's answer, there's some background configuration to the tools directive on the Jenkins server itself that configures the installation paths to be used.
Let's say you have jdk-1.8.0 installed as a tool name on the Jenkins server, then it can be used in the Jenkinsfile as such in your example:
withEnv(["PATH+JDK=${tool 'jdk-1.8.0'}/bin"])
Taken from the documentation linked above:
The tool name must be pre-configured in Jenkins under Manage Jenkins → Global Tool → Configuration.

Related

How to extract Jenkinsfile by a custom script?

I've created a Jenkins job of type "Pipeline", and used an inline pipeline script. Now I'd like to put the script under version control and use the "Pipeline script from SCM" option (I think, I don't have to describe the merits of this).
However, our version control system (CA SCM) is not well supported in Jenkins: I couldn't make the plugin to check out anything.
We do have, however, some scripts for working with CA SCM that allow to check out things reliably.
So, my question is: Is it possible (and how) to have the Jenkinsfile under version control, do the check out for it by a custom script (e.g. using a .bat command) and then have the pipeline executed as if the Jenkinsfile had been extracted by the "Pipeline script from SCM" option?
I.e., as I understand it, I need a command in the pipeline plugin to execute a given Jenkinsfile.
You could try to use the feature "Prepare an environment for the build" from the "Environment Injector Plugin" (https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin) and provide a script file (or inlined content) to execute.

Environment variable in Jenkins Pipeline

Is there any environment variable available for getting the Jenkins Pipeline Title?
I know we can use $JOB_NAME to get title for a freestyle job,
but is there anything that can be used for getting Pipeline name?
You can access the same environment variables from groovy using the same names (e.g. JOB_NAME or env.JOB_NAME).
From the documentation:
Environment variables are accessible from Groovy code as env.VARNAME or simply as VARNAME. You can write to such properties as well (only using the env. prefix):
env.MYTOOL_VERSION = '1.33'
node {
sh '/usr/local/mytool-$MYTOOL_VERSION/bin/start'
}
These definitions will also be available via the REST API during the build or after its completion, and from upstream Pipeline builds using the build step.
For the rest of the documentation, click the "Pipeline Syntax" link from any Pipeline job
To avoid problems of side effects after changing env, especially using multiple nodes, it is better to set a temporary context.
One safe way to alter the environment is:
withEnv(['MYTOOL_HOME=/usr/local/mytool']) {
sh '$MYTOOL_HOME/bin/start'
}
This approach does not poison the env after the command execution.

How to re-use groovy script in Jenkins Groovy Post Build plugin?

I have some groovy code which I am planning to re-use in Jenkins Groovy Post Build plugin of multiple jobs. How can I achieve this? Is there a place I can store the script in a global variable and call that in the jobs where ever I need?
You can load any groovy file living on the Jenkins master within the groovy postbuild and execute it. For example, you could have a special directory on the c drive where all the common scripts live. I'll update my answer later with some code that shows you how to load the script in.
Update
Assuming you have a test.groovy file on your C: drive, it should be as simple as the following in Groovy Postbuild:
evaluate(new File("C:\\test.groovy"))
Please view the comment section of the Groovy Postbuild for more examples and possibly other ways.
Here is the solution that worked for me:
Installed Scriptler plugin for Jenkins and saved the Groovy script in that. Now the script is available in JENKINS_HOME/scriptler/scripts directory. This way we can avoid manual step of copying files to Jenkins master.
Used the groovy file in Post build:
def env = manager.build.getEnvironment(manager.listener) evaluate(new File(env['JENKINS_HOME'] + "\\scriptler\\scripts\\GroovyForPostBuild.groovy"))
This is a copy of my answer to this similar question on StackOverflow:
If you wish to have the Groovy script in your Code Repository, and loaded onto the Build / Test Slave in the workspace, then you need to be aware that Groovy Postbuild runs on the Master.
For us, the master is a Unix Server, while the Build/Test Slaves are Windows PCs on the local network. As a result, prior to using the script, we must open a channel from the master to the Slave, and use a FilePath to the file.
The following worked for us:
// Get an Instance of the Build object, and from there
// the channel from the Master to the Workspace
build = Thread.currentThread().executable
channel = build.workspace.channel;
// Open a FilePath to the script
fp = new FilePath(channel, build.workspace.toString() + "<relative path to the script in Unix notation>")
// Some have suggested that the "Not NULL" check is redundant
// I've kept it for completeness
if(fp != null)
{
// 'Evaluate' requires a string, so read the file contents to a String
script = fp.readToString();
// Execute the script
evaluate(script);
}

Jenkins Pipeline accessing environment variables

I'm trying to use DSL pipelines in Jenkins. I thought it'd be nice if I could use the project name as part of my script.
git credentialsId: 'ffffffff-ffff-ffff-ffff-ffffffffffffff',\
url: "${repo_root}/${JOB_NAME}.git"
I get the error:
groovy.lang.MissingPropertyException: \
No such property: JOB_NAME for class: groovy.lang.Binding
I thought I followed these directions, and they mention JOB_NAME as one of the variables.
I decided to try:
sh 'env'
in my DSL, and this prints out:
JOB_NAME = foo-bar
which is what I expect.
Another blog mentions:
Usage of environment variables
We have two ways to get their value. The properties passed by -D= during the startup we could read as System.getProperty("key") thanks to the Groovy's strong relation with Java.
Reading normal environment variables in Java way is the System.getenv("VARIABLE")...
Let's try this:
println "JOB_NAME = " + System.getenv('JOB_NAME');
Now, I get:
java.lang.NullPointerException: Cannot get property 'System' on null object
Null object? But, I can see that JOB_NAME is an environment variable!
How do I read in the $JOB_NAME into a DSL script in a Pipeline job. I am trying a Pipeline job, and when I get that working will make this a Multibranch Pipeline with a Jenkinsfile.
All environment variables are accessible using env, e.g. ${env.JOB_NAME}.
Okay this really vexed me for a while today. Ultimately, I was being done in by a couple of things:
Single-quoted strings in Groovy mean "don't evaluate variables," just like it does in bash
Using $ interpolation is completely unnecessary if you're just referencing the variable, so you can just do env.JOB_NAME.
This SO question proved to be the one that helped me crack the code: Jenkins Workflow Checkout Accessing BRANCH_NAME and GIT_COMMIT
Indeed just use ${env.JOB_NAME} to access a known variable.
However if you need to access environment variable where name is given by another variable (dynamic access), just use env["your-env-variable"].
I had the problem where I configured 3 environment variables (in Jenkins -> Administer -> Configure System -> Environment variables), let's name them ENV_VAR_1, ENV_VAR_2, ENV_VAR_3.
Now I want to dynamically access them, I can do as such :
def envVarName = "ENV_VAR_" + count // Suppose count is initialized in a loop somewhere above...
def value = env[envVarName] // Will be resolved to env["ENV_VAR_1"] depending on count value
My environment variables in Jenkins configuration look like this :
I had an issue with this not working. The globally set properties/environment variables were only available inside a node step. It's a bug in version 2.4 of Pipeline plugin. Upgrade to 2.5 if you face this issue and your global properties will be available anywhere in the script. I've posted this to the Jenkins wiki here with the test script I used.

Jenkins plugin cannot see variables set using the withEnv workflow step

I want the gradle plugin to pick up environment variables that are set in a withEnv step (or other wrapper-types). When I invoke gradle using a sh step the variable is found, but when I use the gradle plugin it is not.
The gradle plugin performs the equivalent of this:
EnvVars env = run.getEnvironment(taskListener);
launcher.launch().cmds(args).envs(env).stdout(gca)
.pwd(rootLauncher).join();
The javadoc for run.getEnvironment() states:
Returns the map that contains environmental variables to be used for
launching processes for this build. BuildSteps that invoke external
processes should use this. This allows BuildWrappers and other project
configurations (such as JDK selection) to take effect.
Unlike earlier getEnvVars(), this map contains the whole environment,
not just the overrides, so one can introspect values to change its
behavior.
If I debug the plugin I see that there are less than a dozen variables in the environment passed to the gradle invocation, none of which are the variables withEnv should be providing. To the best I could tell, the sh step uses a completely different extension point, and is straight up given an instance of EnvVars that appears to be much more complete. I'm fairly certain the problem isn't in withEnv, but I don't see how to fix the gradle plugin.
Am I using the wrong call? Or perhaps the wrong extension point?
Do not call Run.getEnvironment. Rather use the EnvVars passed to SimpleBuildStep.perform.

Resources