Groovy reports that a file doesn't exists when it really is present in the system
Solution 1
java.io.File
methods will refer to files on the master where Jenkins is running, and not in the current workspace on the slave machine (in case this job indeed runs on a slave machine).
To refer to files on the slave machine, you should use the readFile
method
def log = readFile("${WORKSPACE}/${LOG}");
Solution 2
Within a Jenkins pipeline, File log = new File("${WORKSPACE}/${LOG}");
doesn't work.
You can use readFile instead, e.g.:
def log = readFile "${WORKSPACE}/${LOG}"
Related videos on Youtube
Comments
-
Adri C.S. almost 2 years
Whenever a build of my Jenkins job finishes, I'm sending an email with the results using the
Editable Email Notification
plugin (a.k.a.Email-ext
plugin). Also, if a certain file is present in the system, I'm modifying the default content of the message to notify of the existence of that file.For that end, I'm using the
Pre-send Script
field of the plugin.Test job configuration:
Prepare an environment for the run
Properties Content
LOG="log.txt"
Build stage
Execute shell
#!/bin/bash touch ${WORKSPACE}/${LOG} echo "this is just a log" >> ${WORKSPACE}/${LOG}
Post-build Actions
Editable Email Notification
Pre-send ScriptFile log = new File("${WORKSPACE}/${LOG}"); logger.println(log.text);
When executing the build,
Jenkins
will create the file in the${WORKSPACE}
and fill it (I'm able to print the contents from the terminal in the Jenkins slave).But when trying to access it from the
Email
plugin, the exceptionjava.io.FileNotFoundException
is raised:java.io.FileNotFoundException: /home/jenkins/workspace/testJob/log.txt (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:146) at groovy.util.CharsetToolkit.<init>(CharsetToolkit.java:69) at org.codehaus.groovy.runtime.DefaultGroovyMethods.newReader(DefaultGroovyMethods.java:16958) at org.codehaus.groovy.runtime.DefaultGroovyMethods.getText(DefaultGroovyMethods.java:16006) at org.codehaus.groovy.runtime.dgm$381.doMethodInvoke(Unknown Source) at org.codehaus.groovy.reflection.GeneratedMetaMethod$Proxy.doMethodInvoke(GeneratedMetaMethod.java:70) at groovy.lang.MetaClassImpl$GetBeanMethodMetaProperty.getProperty(MetaClassImpl.java:3500) at org.codehaus.groovy.runtime.callsite.GetEffectivePojoPropertySite.getProperty(GetEffectivePojoPropertySite.java:61) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227) at Script1.run(Script1.groovy:59) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:580) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618) at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589) at hudson.plugins.emailext.ExtendedEmailPublisher.executePresendScript(ExtendedEmailPublisher.java:450) at hudson.plugins.emailext.ExtendedEmailPublisher.sendMail(ExtendedEmailPublisher.java:311) at hudson.plugins.emailext.ExtendedEmailPublisher._perform(ExtendedEmailPublisher.java:297) at hudson.plugins.emailext.ExtendedEmailPublisher.perform(ExtendedEmailPublisher.java:244) at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20) at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:782) at hudson.model.AbstractBuild$AbstractBuildExecution.performAllBuildSteps(AbstractBuild.java:723) at hudson.model.Build$BuildExecution.cleanUp(Build.java:195) at hudson.model.Run.execute(Run.java:1785) at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43) at hudson.model.ResourceController.execute(ResourceController.java:98) at hudson.model.Executor.run(Executor.java:410)
I'm at a loss as why
Groovy
is complaining about the missing file, whereas if I instead print the path withlogger.println(log.getPath());
it will print it successfully.
NOTE: The
logger
variable in thePre-send Script
is provided by the notification plugin to access directly the build log.-
fishi0x01 over 7 yearsIs it possible that the post-build action gets executed on the jenkins master rather than on the slave? The logger object might be shared across the nodes, which is why the
log.getPath()
returns a path, but the file itself might not be present on the master node. -
Adri C.S. about 7 years@fishi Indeed, it seems that the post-build action is executed in the Slave. I printed the
hostname
of the machine instead of creating files and it reported the Master's. The question remains as how could I be able to access that file from the Master... -
fishi0x01 about 7 yearsOne option would be to copy the file to the master. If you use Jenkins pipeline scripts you could use stash/unstash. But judging from the question it seems you are not using Jenkins pipeline. In that case you could have a look at Copy to slave plugin (even though the name suggests otherwise, you can also copy from slave to master with it).
-
Adri C.S. about 7 years@fishi You are right. I'm not using the pipeline, but I will take a look into it, to see if it would be possible to modify the job to adopt it. Otherwise, I will go with the
Copy to slave
plugin approach.
-
-
Adri C.S. over 6 yearsNope. That didn't work. As @MorLajb suggested, it seems to be running on the master.
-
Ian D. Rossi over 6 yearsYeah, what a pain in the butt. Would be so much better if Pipelines could just be pure Groovy.
-
Tacahiroy almost 6 yearsYes, this is an expected behaviour of Jenkins: issues.jenkins-ci.org/browse/JENKINS-37577
-
Prathamesh dhanawade over 4 yearsAnd how would we create/write to the file ?? example I have a list that I want to write to file which is easily done by File.append() ??
-
Jakub Kukul over 4 yearsA side note: this will work if the groovy code is within the Pipeline. If you want to read a file on a slave from a shared library, it's not really possible, as described here - issues.jenkins-ci.org/browse/JENKINS-56384.