Rename a file - Jenkins - jenkins

As part of our pipeline I need to rename a file before it gets pushed up to GitHub. Previously this worked when running the Jenkins job on a master node, but now we run them on agents
def rename_build_file() {
print "Append Version Number to File"
// File without version
String myFile = "${WORKSPACE_PATH}/release-pipeline/project/dist/myFile.js
// File with version
String myFileNew = "${WORKSPACE_PATH}/release-pipeline/project/dist/myfile-1.0.js"
// Rename File
new File(myFile).renameTo(new File(myFileNew));
}
Within our JenkinsFile we call helper.rename_build_file() and this usually works
When i sshd onto the agent I found that I had to run sudo to manually change a filename (did not have to enter a password), am i to assume that when the Jenkins job is running it's not running as sudo
And if that's the case how could i do this running the job?
Thanks

When working with files across multiple agents, you should use pipeline's workflow steps like fileExists, readFile, and writeFile. You can use a combination of these steps to create a new file with the desired name in the current workspace.
def sourceFile = "release-pipeline/project/dist/myFile.js"
if (fileExists(file: sourceFile)) {
def newFile = "release-pipeline/project/dist/myFile-1.0.js"
writeFile(file: newFile, encoding: "UTF-8", text: readFile(file: sourceFile, encoding: "UTF-8"))
}

This can be done with the File Operations plugin:
pipeline {
agent any
stages {
stage('Rename') {
steps {
cleanWs()
fileOperations([fileCreateOperation(fileName: 'foo', fileContent: '')])
fileOperations([fileRenameOperation(destination: 'bar', source: 'foo')])
sh "ls -l"
}
}
}
}
The plugin has quite a list of supported file operations.

Related

Jenkins Shared Library resource not found

I have just started looking into a shared libarary with jenkins in order to combine a load of scripts and pipelines across multiple repos that are pretty much identical.
I have the shared lib loaded and working but when tryign to execute the scripts i the resources folder i keep geting not found errors:
../releaseTagging-EO2DMYOPJ6JGB6JT5Q2RSFJWJWWPALA7F25H7CQNYBEV4ITTEB6Q#tmp/build.sh: not found
I am creating a copy of the file using the following:
createTempLocation(String path) {
String tmpDir = pwd tmp: true
return tmpDir + File.separator + new File(path).getName()
}
and
copyGlobalLibraryScriptcall(String srcPath, String destPath = null) {
destPath = destPath ?: createTempLocation(srcPath)
writeFile file: destPath, text: libraryResource(srcPath)
echo "copyGlobalLibraryScript: copied ${srcPath} to ${destPath}"
sh "chmod +x ${destPath}"
echo "added executable permissions to ${destPath}"
return destPath
}
I am then calling the last function thusly:
runBuild(Map config) {
def script = copyGlobalLibraryScript('build.sh')
sh script
}
(i realise i can collapse the above function in to one line)
This in turn then gets called via (trimed the whole file to relevent part):
pipeline {
agent any
stages {
stage('Build') {
steps {
timestamps {
checkout scm
bbNotify( key: buildKey, name: BuildName) {
runBuild()
}
stash includes: '**', name: 'RelToSTAN'
}
}
}
}
This all fails with the error at the top of the question, however when sshing on to the build server i can find that file int he location specified.
I dont understand why Jenkins cannot find it and execute it.
The issue will be the following:
When using a java File object it‘ll always refer to some location on the Jenkins master. And of course it usually cannot run inside the sandbox.
On the other hand the readFile and writeFile methods always refer to some path on the build agent reserved by the node block where the call is encapsulated.
Long story short: Do not use the File class. Unfortunately you’ll need to create the temp path manually. But that shouldn’t be too hard.

Jenkins's Pipeline File Param [duplicate]

I'm putting together a Jenkins pipeline job which will take a file parameter. I can trigger the job and point it at a file however I can't find where the file has ended up (In an ordinary freestyle job it would be in the workspace).
Where has the uploaded file gone? Or do file parameters not currently work with pipelines?
There is currently an issue with pipeline and file parameter
(https://issues.jenkins-ci.org/browse/JENKINS-27413).
Solved it the following way:
node {
deleteDir()
stage("upload") {
def inputFile = input message: 'Upload file', parameters: [file(name: 'data.zip')]
new hudson.FilePath(new File("$workspace/data.zip")).copyFrom(inputFile)
inputFile.delete()
}
stage("checkout") {
echo fileExists('data.zip').toString()
}
}
I know the solution is not that beautiful because the pipeline gets interrupted for the upload but it works.
Further the "copyFrom" is necessary, because the input stores the "data.zip" in the jobs directory and not in the workspace (don't know why)
Found a WA (Strictly for text based file input)
We can use Jenkins multi-line string parameter and ask user to paste file contents to it.
And in our pipeline, write contents of this parameter using pipeline step writeFile, as :
stage('File Param WA') {
writeFile file: 'demo.yaml', text: params.DEMO_YAML
}
I tried using the solution provided by #Christoph Forster , but the input File was not getting copied anywhere in the workspace .
So I used the workaround as provided in
https://bitbucket.org/janvrany/jenkins-27413-workaround-library/src/6b7dada8ea37?at=default
The library provides a new library - unstashParam - that saves the file build parameter into a workspace. Works fine with text and yaml file .
I also tried using the solution by #Christoph Forster but I received a script security error when Groovy Sandbox is enable
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new hudson.FilePath java.io.File
However, it seems we can skip the file copying and deleting actions (and bypass the Groovy sandbox restriction) by simply requiring that the file is uploaded to the job workspace. Just add the workspace variable to the file name as follows:
stage("upload") {
def inputFile = input message: 'Upload file', parameters: [file(name: "$workspace/data.zip")]
}
I found a solution in the form of a global library here:
https://bitbucket.org/janvrany/jenkins-27413-workaround-library/src/default/
It contains calls to inner methods of Jenkins which are deprecated (I guess).
So I made my own version like this:
import hudson.FilePath
import hudson.model.ParametersAction
import hudson.model.FileParameterValue
import hudson.model.Executor
def call(String name, String fname = null) {
def paramsAction = currentBuild.rawBuild.getAction(ParametersAction.class);
if (paramsAction == null) {
error "unstashParam: No file parameter named '${name}'"
}
for (param in paramsAction.getParameters()) {
if (param.getName().equals(name)) {
if (! param instanceof FileParameterValue) {
error "unstashParam: not a file parameter: ${name}"
}
if (env['NODE_NAME'] == null) {
error "unstashParam: no node in current context"
}
if (env['WORKSPACE'] == null) {
error "unstashParam: no workspace in current context"
}
workspace = new FilePath(getComputer(env['NODE_NAME']), env['WORKSPACE'])
filename = fname == null ? param.getOriginalFileName() : fname
file = workspace.child(filename)
file.copyFrom(param.getFile())
return filename;
}
}
}
def getComputer(name){
for(computer in Jenkins.getInstance().getComputers()){
if(computer.getDisplayName() == name){
return computer.getChannel()
}
}
error "Cannot find computer for file parameter workaround"
}
You can insert it in a global library and then use it like:
library "file-workaround"
node {
def file_in_workspace = unstashParam "myFile"
sh "cat ${file_in_workspace}"
}
It's not pretty but it's working and as long as there is no official fix, it's my best shot.
Update
Turns out you might run into "No such file or directory". That's because nothing in the workaround triggers Jenkins to create the workspace directory. If that was triggered somewhere else in the pipeline good, otherwise you'll be scratching your head.
You might wanna throw a
touch "thisIsAFile"
in there
To handle an optional file parameter in pipeline (to handle the use case where no file should be accepted) you could use jenkinsci-unstashParam-library (add it in Jenkins>Manage Jenkins>Configure System>Global Pipeline Libraries https://github.com/janvrany/jenkinsci-unstashParam-library) with a try/catch in a script as this sample stage:
stage('upload') {
steps {
// delete workspace
cleanWs()
// handle file parameters in pipeline (JENKINS-27413)
script {
try {
// force workspace directory creation
sh "touch emptyFileToCreateWorkspace"
// https://stackoverflow.com/questions/59468464/fetching-uploaded-files-in-jenkins
def file_in_workspace = unstashParam 'MY_FILE.xlsx'
// https://unix.stackexchange.com/questions/125776/error-with-a-file-name-containing-parentheses
sh "mv '${file_in_workspace}' MY_FILE.xlsx"
}
catch (Exception e) {
echo e.getMessage()
echo "No file parameter, we will continue.."
}
}
}
}
File parameters provides 2 alternative parameters types for files (stashed for large files and base64 for small files).
Example, for base64File:
node {
sh 'echo $FILE | base64 -d'
withFileParameter('FILE') {
sh 'cat $FILE'
}
}
and stashedFile:
node {
unstash 'FILE'
sh 'cat FILE'
}
Tried what Christoph suggested and it didnt work for me. Here is what worked for me and the setup which I have, his should help others figure out what to do.
Problem:
I am executing my pipeline on dedicated nodes and use sanitized workspaces. After some research and troubleshooting I found out that by default the file upload only works with Master node. I realized this after digging through the file system and finding the file I am uploading in the workspace on the master
Solution:
stage('Upload Key') {
agent { label 'master' }
steps {
script {
// Uploads file via master node and stases it for other nodes to access
def inputFile = input message: 'Upload file', parameters: [file(name: "key.p12")]
new hudson.FilePath(new File("${workspace}/key.p12")).copyFrom(inputFile)
inputFile.delete()
}
stash name: 'key.p12' , includes: "key.p12"
}
}
stage('Register') {
steps {
ws (sanitizedWorkspaceName) {
echo "Registering"
unstash 'key.p12'
}
}
}
Execute the suggested file copy solution by Christoph. This stores the file in the job workspace on the master node
Allow the scripts in Manage Jenkins > In Process Script approval
use the stash step to stash the uploaded file
In the target stage "running on a different node" use the unstash
Hope this helps
I wasn't able to make Christoph's solution working if the file was uploaded on master node and needed on slave. The solution was to stash it on master and later unstash it on slave. Don't forget to remove the uploaded file on master node.
It's supported by the latest File Parameters plugin now. Please refer to: How to pass a file parameter to another build job in jenkins pipeline?

Jenkins Declarative Pipeline, run groovy script on slave agent

I have a Jenkins declarative pipeline I have been running on the Jenkins master and it works fine. However, now that I have moved to trying to execute this on a slave node, the groovy scripts which are called in the pipeline can not access the files in the workspace.
My jenkinsfile looks like this...
pipeline {
agent {
label {
label "windows"
customWorkspace "WS-${env.BRANCH_NAME}"
}
}
stages {
stage('InitialSetup') {
steps {
"${env.WORKSPACE}/JenkinsScripts/myScript.groovy"
}
}
}
I can see on the slave that it is creating the workspace, doing the checkout from git, and executing the script correctly. However, if something in the script try's to interact with the files in the workspace it fails.
If I have something simple like this...
def updateFile(String filename) {
echo env.NODE_NAME
filename = "${env.WORKSPACE}/path/to/file"
def myFile = new File(filename)
<do other things with the file>
}
...it says it can not find the file specified. It gives me the path it is looking for and I can confirm the file exists, and that the code runs when just building on the master.
Why can the script not find the files this way when in can just running on the master node? I added the "echo env.NODE_NAME" command into my groovy file and it says the script is executing on the correct node.
Thanks.
Turns out Groovy File commands are considered insecure, and although they will run on the master, they will not run on the slave. If you call them from a script that has the agent set to another node, it will still execute the command just fine, just on the master node, not the agent. Here's an excerpt of an article post https://support.cloudbees.com/hc/en-us/articles/230922508-Pipeline-Files-manipulation
The operation with File class are run on master, so only works if build is run on master, in this example I create a file and check if I can access it on a node with method exists, it does not exist because the new File(file) is executed on master, to check this I search for folder Users that exist on my master but not in the node.
stage 'file move wrong way'
//it only works on master
node('slave') {
def ws = pwd()
def context = ws + "/testArtifact"
def file = ws + '/file'
sh 'touch ' + file
sh 'ls ' + ws
echo 'File on node : ' + new File(file).exists()
echo 'Users : ' + new File('/Users').exists()
sh 'mv ' + file + ' ' + context
sh 'ls ' + ws
}
To execute file manipulation command we recommend to use native commands.
This is a simple example of operations in shell
stage 'Create file'
sh 'touch test.txt'
stage 'download file'
def out='$(pwd)/download/maven.tgz'
sh 'mkdir -p ./download'
sh 'curl -L http://ftp.cixug.es/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz -o ' + out
stage 'move/rename'
def newName = 'mvn.tgz'
sh 'mkdir -p $(pwd)/other'
sh 'mv ' + out + ' ' + newName
sh 'cp ' + newName + ' ' + out
}
I run into this same issue recently. I had a python file that runs and writes the results to a JSON file. I was trying to access the JSON file to retrieve the data from there. Here is the code I was using inside a stage block of a declarative pipeline:
script {
def jsonSlurper = new JsonSlurper()
def fileParsed = new File("parameters.json")
def dataJSON = jsonSlurper.parse(fileParsed)
}
As everyone stated already, the above was failing with FileNotFoundException because anything inside script{} will only run on master and not the agent.
To work around the issue, I have used the Pipeline Utility Steps plugin (reference: https://plugins.jenkins.io/pipeline-utility-steps/ -- How to use: https://www.jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#writejson-write-json-to-a-file-in-the-workspace)
The plugin will allow you to do any read/write operation on multiple file formats.
Here is an example of the code I used after installing the plugin:
script {
def props = readJSON file: 'parameters.json'
println("just read it..")
println(props)
}
Note: I was using jenkins 2.249.1
I have implemented the code which automatically installs Groovy on slave (for scripted pipeline). Perhaps this solution is a little bit cumbersome, but pipelines don't offer any other way to achieve the same functionality as "Execute Groovy Script" stuff from the old Jenkins, because the plugin https://wiki.jenkins.io/display/JENKINS/Groovy+plugin is not supported yet for pipeline.
import hudson.tools.InstallSourceProperty;
import hudson.tools.ToolProperty;
import hudson.tools.ToolPropertyDescriptor;
import hudson.tools.ToolDescriptor;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolInstaller;
import hudson.util.DescribableList;
import hudson.plugins.groovy.GroovyInstaller;
import hudson.plugins.groovy.GroovyInstallation;
/*
Installs Groovy on the node.
The idea was taken from: https://devops.lv/2016/12/05/jenkins-groovy-auto-installer/
and https://github.com/jenkinsci/jenkins-scripts/blob/master/scriptler/configMavenAutoInstaller.groovy
COMMENT 1: If we use this code directly (not as a separate method) then we get
java.io.NotSerializableException: hudson.plugins.groovy.GroovyInstaller
COMMENT 2: For some reason inst.getExecutable(channel) returns null. I use inst.forNode(node, null).getExecutable(channel) instead.
TODO: Check if https://jenkinsci.github.io/job-dsl-plugin/#method/javaposse.jobdsl.dsl.helpers.step.MultiJobStepContext.groovyCommand
works better.
*/
#NonCPS
def installGroovyOnSlave(String version) {
if ((version == null) || (version == "")) {
version = "2.4.7" // some default should be
}
/* Set up properties for our new Groovy installation */
def node = Jenkins.getInstance().slaves.find({it.name == env.NODE_NAME})
def proplist = new DescribableList<ToolProperty<?>, ToolPropertyDescriptor>()
def installers = new ArrayList<GroovyInstaller>()
def autoInstaller = new GroovyInstaller(version)
installers.add(autoInstaller)
def InstallSourceProperty isp = new InstallSourceProperty(installers)
proplist.add(isp)
def inst = new GroovyInstallation("Groovy", "", proplist)
/* Download and install */
autoInstaller.performInstallation(inst, node, null)
/* Define and add our Groovy installation to Jenkins */
def descriptor = Jenkins.getInstance().getDescriptor("hudson.plugins.groovy.Groovy")
descriptor.setInstallations(inst)
descriptor.save()
/* Output the current Groovy installation's path, to verify that it is ready for use */
def groovyInstPath = getGroovyExecutable(version)
println("Groovy " + version + " is installed in the node " + node.getDisplayName())
}
/* Returns the groovy executable path on the current node
If version is specified tries to find the specified version of groovy,
otherwise returns the first groovy installation that was found.
*/
#NonCPS
def getGroovyExecutable(String version=null) {
def node = Jenkins.getInstance().slaves.find({it.name == env.NODE_NAME})
def channel = node.getComputer().getChannel()
for (ToolInstallation tInstallation : Jenkins.getInstance().getDescriptor("hudson.plugins.groovy.Groovy").getInstallations()) {
if (tInstallation instanceof GroovyInstallation) {
if ((version == null) || (version == "")) {
// any version is appropriate for us
return tInstallation.forNode(node, null).getExecutable(channel)
}
// otherwise check for version
for (ToolProperty prop in tInstallation.getProperties()) {
if (prop instanceof InstallSourceProperty) {
for (ToolInstaller tInstaller: prop.installers) {
if (
(tInstaller instanceof GroovyInstaller) &&
(tInstaller.id.equals(version))
)
return tInstallation.forNode(node, null).getExecutable(channel)
}
}
}
}
}
return null
}
/* Wrapper function. Returns the groovy executable path as getGroovyExecutable()
but additionally tries to install if the groovy installation was not found.
*/
def getGroovy(String version=null) {
def installedGroovy = getGroovyExecutable(version)
if (installedGroovy != null) {
return installedGroovy
} else {
installGroovyOnSlave(version)
}
return getGroovyExecutable(version)
}
Just put these 3 methods to your pipeline script and you will be able to get the Groovy executable path with the help of the method getGroovy(). If it is not installed yet then the installation will be done automatically. You can test this code with the simple pipeline, like this:
// Main
parallel(
'Unix' : {
node ('build-unix') {
sh(getGroovy() + ' --version')
}
},
'Windows' : {
node ('build-win') {
bat(getGroovy() + ' --version')
}
}
)
For me the output was:
[build-unix] Groovy Version: 2.4.7 JVM: 1.8.0_222 Vendor: Private Build OS: Linux
[build-win] Groovy Version: 2.4.7 JVM: 11.0.1 Vendor: Oracle Corporation OS: Windows 10
To work with files on the slave workspace use the readFile, writeFile, findFiles etc steps.
Or if they are large as FloatingCoder said use native tooling; which may be running a groovy script.
A workaround could be load the library via sh command in Jenkinsfile.
So, if you use in Jenkinsfile:
sh 'groovy libraryName.groovy'
You can load the lib locally and in this way you can store File on the slave node.
Even without pipelines, there is no option to restrict a job based on slave agent label. So, I think, pipelines are only for master node execution.
Starting from release 2.4 of the Groovy plugin there is withGroovy step available which sets up the environment on the agent so that you can do sh 'groovy yourscript.groovy' with expected environments. It also enables limited interaction between Pipeline and groovy script.
See https://www.jenkins.io/doc/pipeline/steps/groovy/ for some details about the step.

File operations in Jenkins Pipeline

I have a pipeline flow defined as:
node("linux_label") {
println("hostname".execute().txt)
def filename = "${WORKSPACE}/submoduleinfo.txt"
stage("Submodule info") {
def submoduleString = sh script: "git -C ${WORKSPACE} submodule status > ${filename}", returnStdout: true
}
String fileContents = new File("$filename}").text
operateOnFile(fileContents)
}
At "new File" I will get an error saying no such file exists. after some troublehshooting I see that the hostname printout will output the jenkins master and not the node "linux_label" where the workspace resides.
Is this how Piepeline should work, i.e. all code that is not part of stage/steps/etc are executed on the jenkins master and not on the wanted node?
What would be a good workaround where I do an operation in one stage and want to operate on the file in the node {} domain?
That is how pipeline works. You can use readFile to read file from a workspace. Since you are using just a content of the file for your processing, this will work.
From tutorial:
readFile step loads a text file from the workspace and returns its
content (do not try to use java.io.File methods — these will refer to
files on the master where Jenkins is running, not in the current
workspace).
In one of our use case, we added some additional functions using Shared pipeline library.
Try this:
if (env['NODE_NAME'].equals("master")) {
return new hudson.FilePath(path);
} else {
return new hudson.FilePath(Jenkins.getInstance().getComputer(env['NODE_NAME']).getChannel(), path);
}

Jenkins Pipeline Job with file parameter

I'm putting together a Jenkins pipeline job which will take a file parameter. I can trigger the job and point it at a file however I can't find where the file has ended up (In an ordinary freestyle job it would be in the workspace).
Where has the uploaded file gone? Or do file parameters not currently work with pipelines?
There is currently an issue with pipeline and file parameter
(https://issues.jenkins-ci.org/browse/JENKINS-27413).
Solved it the following way:
node {
deleteDir()
stage("upload") {
def inputFile = input message: 'Upload file', parameters: [file(name: 'data.zip')]
new hudson.FilePath(new File("$workspace/data.zip")).copyFrom(inputFile)
inputFile.delete()
}
stage("checkout") {
echo fileExists('data.zip').toString()
}
}
I know the solution is not that beautiful because the pipeline gets interrupted for the upload but it works.
Further the "copyFrom" is necessary, because the input stores the "data.zip" in the jobs directory and not in the workspace (don't know why)
Found a WA (Strictly for text based file input)
We can use Jenkins multi-line string parameter and ask user to paste file contents to it.
And in our pipeline, write contents of this parameter using pipeline step writeFile, as :
stage('File Param WA') {
writeFile file: 'demo.yaml', text: params.DEMO_YAML
}
I tried using the solution provided by #Christoph Forster , but the input File was not getting copied anywhere in the workspace .
So I used the workaround as provided in
https://bitbucket.org/janvrany/jenkins-27413-workaround-library/src/6b7dada8ea37?at=default
The library provides a new library - unstashParam - that saves the file build parameter into a workspace. Works fine with text and yaml file .
I also tried using the solution by #Christoph Forster but I received a script security error when Groovy Sandbox is enable
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new hudson.FilePath java.io.File
However, it seems we can skip the file copying and deleting actions (and bypass the Groovy sandbox restriction) by simply requiring that the file is uploaded to the job workspace. Just add the workspace variable to the file name as follows:
stage("upload") {
def inputFile = input message: 'Upload file', parameters: [file(name: "$workspace/data.zip")]
}
I found a solution in the form of a global library here:
https://bitbucket.org/janvrany/jenkins-27413-workaround-library/src/default/
It contains calls to inner methods of Jenkins which are deprecated (I guess).
So I made my own version like this:
import hudson.FilePath
import hudson.model.ParametersAction
import hudson.model.FileParameterValue
import hudson.model.Executor
def call(String name, String fname = null) {
def paramsAction = currentBuild.rawBuild.getAction(ParametersAction.class);
if (paramsAction == null) {
error "unstashParam: No file parameter named '${name}'"
}
for (param in paramsAction.getParameters()) {
if (param.getName().equals(name)) {
if (! param instanceof FileParameterValue) {
error "unstashParam: not a file parameter: ${name}"
}
if (env['NODE_NAME'] == null) {
error "unstashParam: no node in current context"
}
if (env['WORKSPACE'] == null) {
error "unstashParam: no workspace in current context"
}
workspace = new FilePath(getComputer(env['NODE_NAME']), env['WORKSPACE'])
filename = fname == null ? param.getOriginalFileName() : fname
file = workspace.child(filename)
file.copyFrom(param.getFile())
return filename;
}
}
}
def getComputer(name){
for(computer in Jenkins.getInstance().getComputers()){
if(computer.getDisplayName() == name){
return computer.getChannel()
}
}
error "Cannot find computer for file parameter workaround"
}
You can insert it in a global library and then use it like:
library "file-workaround"
node {
def file_in_workspace = unstashParam "myFile"
sh "cat ${file_in_workspace}"
}
It's not pretty but it's working and as long as there is no official fix, it's my best shot.
Update
Turns out you might run into "No such file or directory". That's because nothing in the workaround triggers Jenkins to create the workspace directory. If that was triggered somewhere else in the pipeline good, otherwise you'll be scratching your head.
You might wanna throw a
touch "thisIsAFile"
in there
To handle an optional file parameter in pipeline (to handle the use case where no file should be accepted) you could use jenkinsci-unstashParam-library (add it in Jenkins>Manage Jenkins>Configure System>Global Pipeline Libraries https://github.com/janvrany/jenkinsci-unstashParam-library) with a try/catch in a script as this sample stage:
stage('upload') {
steps {
// delete workspace
cleanWs()
// handle file parameters in pipeline (JENKINS-27413)
script {
try {
// force workspace directory creation
sh "touch emptyFileToCreateWorkspace"
// https://stackoverflow.com/questions/59468464/fetching-uploaded-files-in-jenkins
def file_in_workspace = unstashParam 'MY_FILE.xlsx'
// https://unix.stackexchange.com/questions/125776/error-with-a-file-name-containing-parentheses
sh "mv '${file_in_workspace}' MY_FILE.xlsx"
}
catch (Exception e) {
echo e.getMessage()
echo "No file parameter, we will continue.."
}
}
}
}
File parameters provides 2 alternative parameters types for files (stashed for large files and base64 for small files).
Example, for base64File:
node {
sh 'echo $FILE | base64 -d'
withFileParameter('FILE') {
sh 'cat $FILE'
}
}
and stashedFile:
node {
unstash 'FILE'
sh 'cat FILE'
}
Tried what Christoph suggested and it didnt work for me. Here is what worked for me and the setup which I have, his should help others figure out what to do.
Problem:
I am executing my pipeline on dedicated nodes and use sanitized workspaces. After some research and troubleshooting I found out that by default the file upload only works with Master node. I realized this after digging through the file system and finding the file I am uploading in the workspace on the master
Solution:
stage('Upload Key') {
agent { label 'master' }
steps {
script {
// Uploads file via master node and stases it for other nodes to access
def inputFile = input message: 'Upload file', parameters: [file(name: "key.p12")]
new hudson.FilePath(new File("${workspace}/key.p12")).copyFrom(inputFile)
inputFile.delete()
}
stash name: 'key.p12' , includes: "key.p12"
}
}
stage('Register') {
steps {
ws (sanitizedWorkspaceName) {
echo "Registering"
unstash 'key.p12'
}
}
}
Execute the suggested file copy solution by Christoph. This stores the file in the job workspace on the master node
Allow the scripts in Manage Jenkins > In Process Script approval
use the stash step to stash the uploaded file
In the target stage "running on a different node" use the unstash
Hope this helps
I wasn't able to make Christoph's solution working if the file was uploaded on master node and needed on slave. The solution was to stash it on master and later unstash it on slave. Don't forget to remove the uploaded file on master node.
It's supported by the latest File Parameters plugin now. Please refer to: How to pass a file parameter to another build job in jenkins pipeline?

Resources