Skip to content

Commit 69e65a6

Browse files
authored
Merge pull request #255 from mawinter69/issue-254
Ensure a stashedFile parameter is retained on a Jenkins restart while in the queue
2 parents 01de771 + 33e5640 commit 69e65a6

File tree

2 files changed

+77
-11
lines changed

2 files changed

+77
-11
lines changed

src/main/java/io/jenkins/plugins/file_parameters/StashedFileParameterValue.java

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,27 @@
2424

2525
package io.jenkins.plugins.file_parameters;
2626

27-
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2827
import hudson.EnvVars;
28+
import hudson.Extension;
2929
import hudson.FilePath;
3030
import hudson.Launcher;
3131
import hudson.Util;
32+
import hudson.model.ParametersAction;
33+
import hudson.model.Queue;
3234
import hudson.model.Run;
3335
import hudson.model.TaskListener;
36+
import hudson.model.queue.QueueListener;
3437
import java.io.File;
3538
import java.io.IOException;
3639
import java.io.InputStream;
37-
import java.nio.file.Files;
3840

41+
import java.nio.file.FileAlreadyExistsException;
42+
import java.nio.file.Files;
43+
import java.nio.file.Path;
44+
import java.util.List;
45+
import java.util.logging.Level;
46+
import java.util.logging.Logger;
47+
import jenkins.model.Jenkins;
3948
import org.apache.commons.fileupload.FileItem;
4049
import org.apache.commons.io.FileUtils;
4150
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
@@ -44,11 +53,12 @@
4453

4554
public final class StashedFileParameterValue extends AbstractFileParameterValue {
4655

56+
private static final Logger LOGGER = Logger.getLogger(StashedFileParameterValue.class.getName());
57+
4758
private static final long serialVersionUID = 1L;
4859

49-
@SuppressFBWarnings(value = "SE_TRANSIENT_FIELD_NOT_RESTORED", justification = "Doesn't make sense to persist it")
50-
private transient File tmp;
51-
60+
private String tmpFile;
61+
5262
@DataBoundConstructor public StashedFileParameterValue(String name, FileItem file) throws IOException {
5363
this(name, file.getInputStream());
5464
setFilename(file.getName());
@@ -57,14 +67,18 @@ public final class StashedFileParameterValue extends AbstractFileParameterValue
5767

5868
StashedFileParameterValue(String name, InputStream src) throws IOException {
5969
super(name);
60-
tmp = new File(Util.createTempDir(), name);
61-
tmp.deleteOnExit();
70+
File dir = new File(Jenkins.get().getRootDir(), "stashedFileParameterValueFiles");
71+
Files.createDirectories(dir.toPath());
72+
File tmpDir = Files.createTempDirectory(dir.toPath(), null).toFile();
73+
File tmp = new File(tmpDir, name);
6274
FileUtils.copyInputStreamToFile(src, tmp);
75+
tmpFile = tmp.getAbsolutePath();
6376
}
6477

6578
@Override public void buildEnvironment(Run<?, ?> build, EnvVars env) {
6679
super.buildEnvironment(build, env);
67-
if (tmp != null) {
80+
File tmp = tmpFile != null ? new File(tmpFile) : null;
81+
if (tmp != null && tmp.isFile()) {
6882
try {
6983
FlowExecutionOwner feo = build instanceof FlowExecutionOwner.Executable ? ((FlowExecutionOwner.Executable) build).asFlowExecutionOwner() : null;
7084
TaskListener listener = feo != null ? feo.getListener() : TaskListener.NULL;
@@ -75,8 +89,8 @@ public final class StashedFileParameterValue extends AbstractFileParameterValue
7589
throw new RuntimeException( x );
7690
}
7791
try {
78-
Files.deleteIfExists(tmp.toPath());
79-
tmp = null;
92+
FileUtils.deleteDirectory(tmp.getParentFile());
93+
tmpFile = null;
8094
} catch (IOException e) {
8195
throw new RuntimeException(e);
8296
}
@@ -88,4 +102,30 @@ public final class StashedFileParameterValue extends AbstractFileParameterValue
88102
return tempDir.child(name);
89103
}
90104

105+
@Extension
106+
public static class CancelledQueueListener extends QueueListener {
107+
108+
@Override
109+
public void onLeft(Queue.LeftItem li) {
110+
if (li.isCancelled()) {
111+
List<ParametersAction> actions = li.getActions(ParametersAction.class);
112+
actions.forEach(a -> {
113+
a.getAllParameters().stream()
114+
.filter(p -> p instanceof StashedFileParameterValue)
115+
.map(p -> (StashedFileParameterValue) p)
116+
.forEach(p -> {
117+
if (p.tmpFile != null) {
118+
File tmp = new File(p.tmpFile);
119+
try {
120+
FileUtils.deleteDirectory(tmp.getParentFile());
121+
} catch (IOException | IllegalArgumentException e) {
122+
LOGGER.log(Level.WARNING, "Unable to delete temporary file {0} for parameter {1} of task {2}",
123+
new Object[]{tmp.getAbsolutePath(), p.getName(), li.task.getName()});
124+
}
125+
}
126+
});
127+
});
128+
}
129+
}
130+
}
91131
}

src/test/java/io/jenkins/plugins/file_parameters/RestartTest.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import hudson.model.Node;
2929
import hudson.model.ParametersDefinitionProperty;
3030
import hudson.model.Queue;
31+
import hudson.model.Result;
3132
import hudson.model.queue.CauseOfBlockage;
3233
import hudson.model.queue.QueueTaskDispatcher;
3334
import jenkins.model.Jenkins;
@@ -92,7 +93,32 @@ void restBase64() throws Throwable {
9293
});
9394
}
9495

95-
@TestExtension("restBase64")
96+
@Test
97+
void stashedFileIsRetained() throws Throwable {
98+
rr.then(r -> {
99+
r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
100+
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to("admin"));
101+
WorkflowJob p = r.createProject(WorkflowJob.class, "p");
102+
p.addProperty(new ParametersDefinitionProperty(new StashedFileParameterDefinition("FILE")));
103+
p.setDefinition(new CpsFlowDefinition("node { unstash 'FILE' }", true));
104+
WebRequest req = new WebRequest(new URL(r.getURL() + "job/p/buildWithParameters"), HttpMethod.POST);
105+
File f = File.createTempFile("junit", null, tmp);
106+
FileUtils.write(f, "uploaded content here", "UTF-8");
107+
req.setEncodingType(FormEncodingType.MULTIPART);
108+
req.setRequestParameters(Collections.singletonList(new KeyDataPair("FILE", f, "myfile.txt", "text/plain", "UTF-8")));
109+
r.createWebClient().withBasicApiToken("admin").getPage(req);
110+
});
111+
rr.then(r -> {
112+
ExtensionList.lookupSingleton(Block.class).ready = true;
113+
WorkflowJob p = r.jenkins.getItemByFullName("p", WorkflowJob.class);
114+
r.waitUntilNoActivity();
115+
WorkflowRun b = p.getBuildByNumber(1);
116+
assertNotNull(b);
117+
assert(b.getResult().isBetterOrEqualTo(Result.SUCCESS));
118+
});
119+
}
120+
121+
@TestExtension({"restBase64", "stashedFileIsRetained"})
96122
public static final class Block extends QueueTaskDispatcher {
97123
private boolean ready;
98124
@Override

0 commit comments

Comments
 (0)