Get absolute path to workspace directory in Jenkins Pipeline plugin - jenkins

I'm currently doing some evaluation on the Jenkins Pipeline plugin (formerly know as Workflow plugin).
Reading the documentation I found out that I currently cannot retriev the workspace path using
env.WORKSPACE:
The following variables are currently unavailable inside a workflow script:
NODE_LABELS
WORKSPACE
SCM-specific variables such as SVN_REVISION
Is there any other way how to get the absolute path to the current workspace? I need this running some test which in turn gets some parameter (absolute path to some executable file).
I already tried using new File("").absolutePath() inside a #NonCPS section but looks like the non-CPS stuff gets always executed on the master.
Does anybody have a clue how to get this path without running some batch script which stores the path into some file which later on can be read in again?

Since version 2.5 of the Pipeline Nodes and Processes Plugin (a component of the Pipeline plugin, installed by default), the WORKSPACE environment variable is available again. This version was released on 2016-09-23, so it should be available on all up-to-date Jenkins instances.
Example
node('label'){
// now you are on slave labeled with 'label'
def workspace = WORKSPACE
// ${workspace} will now contain an absolute path to job workspace on slave
workspace = env.WORKSPACE
// ${workspace} will still contain an absolute path to job workspace on slave
// When using a GString at least later Jenkins versions could only handle the env.WORKSPACE variant:
echo "Current workspace is ${env.WORKSPACE}"
// the current Jenkins instances will support the short syntax, too:
echo "Current workspace is $WORKSPACE"
}

Note: this solution works only if the slaves have the same directory structure as the master. pwd() will return the workspace directory on the master due to JENKINS-33511.
I used to do it using pwd() functionality of pipeline plugin. So, if you need to get a workspace on slave, you may do smth like this:
node('label'){
//now you are on slave labeled with 'label'
def workspace = pwd()
//${workspace} will now contain an absolute path to job workspace on slave
}

"WORKSPACE" environment variable works for the latest version of Jenkins Pipeline. You can use this in your Jenkins file: "${env.WORKSPACE}"
Sample use below:
def files = findFiles glob: '**/reports/*.json'
for (def i=0; i<files.length; i++) {
jsonFilePath = "${files[i].path}"
jsonPath = "${env.WORKSPACE}" + "/" + jsonFilePath
echo jsonPath
hope that helps!!

For me WORKSPACE was a valid property of the pipeline itself. So when I handed over this to a Groovy method as parameter context from the pipeline script itself, I was able to access the correct value using "... ${context.WORKSPACE} ..."
(on Jenkins 2.222.3, Build Pipeline Plugin 1.5.8, Pipeline: Nodes and Processes 2.35)

Related

How to use the "Extensible choice parameter" in a jenkins freestyle job located on the slave to show files

I have a freestyle job and a parameterized build.
I want to populate an Extensible Choice with all xml file names inside my workspace.
Both the job and the workspace are running on the slave.
The textbox Base Directory says that every relative path has JENKINS_HOME as root, and that is the Jenkins location on the master. Something like C:/ has the same outcome.
I have the same problem with the Active Choice Parameter.
I don't know how to get access to my workspace, with the groovy script for my parameter.
I've tried the following:
def list = []
def dir = new File("C:/<path>")
dir.eachFileRecurse (FileType.FILES) { file ->
list << file
}
It results in a FileNotFoundException. When I try to input a path to the master, it works fine.
I labeled the slave and the job correctly (The job will only be executed on the slave).
Does anyone has a solution?

Jenkins Pipeline returns wrong workspace path

I have a Jenkins pipeline with a pipeline script stored in a repository. This pipeline is working well with Jenkins 2.114. After installing a new Jenkins 2.187 on a new machine with all corresponding plugins, I am facing a problem of wrong current directory path returned from pwd() function on this new installation.
Within the pipeline script I am calling pwd() in order to get the current work-space path (the current OS working directory). The returned path is wrong, it even does not exist. env.WORKSPACE returns exactly the same wrong path.
The pipeline creates two folders in the work-space:
{Jenkins_Workspace}/{item_full_name}#script and {Jenkins_Workspace}/{item_full_name}#3.
The returned value from pwd() is {Jenkins_Workspace}/{item_full_name}#2 . env.WORKSPCE gives the same path {Jenkins_Workspace}/{item_full_name}#2.
{Jenkins_Workspace}/{item_full_name}#2 does not exist.
It is strange that Jenkins appends #{number} to the workspace. It is a very simple pipeline, which does not execute other projects. It is just one job being executed, i.e. no concurrency.
My configuration:
Jenkins: 2.187
Pipeline: 2.6
OS: Windows Server 2016
Jre: 1.8.0_144-b01
Jenkins home: C:/Jenkins
Jenkins workspace: modified in config.xml to <workspace>D:/Workspace/${ITEM_FULL_NAME}</workspace>
Any ideas what can be reason for this problem are highly appreciated.

groovy script loaded from jenkinsfile not found

currently I have an "all inclusive" jenkinsfile which contains various functions.
In order to re-use those functions in other jenkinsfiles I want to put them into separate groovy scripts and load them from the jenkinsfile(s).
scmHandler.groovy:
#!groovy
def handleCheckout() {
if (env.gitlabMergeRequestId) {
echo 'Merge request detected. Merging...'
}
...
}
return this;
in jenkinsfile I do:
...
def scmHandler = load ("test/scmHandler.groovy")
scmHandler.handleCheckout()
I tried to follow the instructions from here but jenkins is constantly complaining that there is no such file scmHandler.groovy an I get:
java.io.FileNotFoundException: d:\jenkins\workspace\myJenkinsJob\test\scmHandler.groovy
Both jenkinsfile and scmHandler.groovy reside in a test/ subdir of the workspace in the git repo of the project to boild and are checked out correctly on master:
/var/lib/jenkins/jobs/myJenkinsJob/workspace#script/test/scmHandler.groovy
However I cannot find them on the slave node where the jenkinsfile executes the build steps inside a node {}. There I only see old versions of the jenkinsfile since the (separated) checkout step is not executed yet.
How do I correctly access the handleCheckout.groovy? What am I miss here?
Actually I find this a neat way to "include" external groovy files without using a separate library.
Use checkout scm before loading scmHandler.groovy
checkout scm
def scmHandler = load ("test/scmHandler.groovy")
scmHandler.handleCheckout()

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);
}

Best way to configure jenkins job running on different slaves

I want to run a Jenkins job on 4 different slaves (windows, linux, solaris, Mac). Instead of making 4 different jobs I want to have a single job. I can use a Node parameter to execute on different slaves. My job runs a script which uses Jenkins workspace of slave and a few other scripts. My script is in a different folder on each slave, and other required scripts are in a different folder. So now I have created 4 different jobs for each slave and hard-coded Jenkins workspace and other required scripts path.
Is there any way so that I can put all paths in some JSON-like structure and depending on slave will pick those paths? So that I will have 1 job only.
Please suggest, Thanks in advance!
my idea is to use e.g "Execute system Groovy script" to get slave value and then use if statement to assigne proper path and create parameter visible in Environment Variables:
import hudson.model.Computer
import hudson.model.StringParameterValue
import hudson.model.ParametersAction
//get slave name
def slaveName = Computer.currentComputer().getNode().name
def path
//choose path
if(slaveName.equals("slave01")){
path = "C:"
}
if(slaveName.equals("slave02")){
path = "/root"
}
if(slaveName.equals("slave03")){
path = "D:"
}
//pass path as env. variable
build.addAction(new ParametersAction(new StringParameterValue('path', path)))
then you can use variable path in command:
echo %path%
or use Conditional BuildStep Plugin to set separable steps for each operation system and control when each step should be executed
Jenkins is designed to check out files from a version control system (Subversion, Git, whatever) and run tasks. Instead of trying to manage separate files on separate slaves, you should put your scripts in some form of version control and let Jenkins check out the files in the workspace as part of its build process.

Resources