-
-
Notifications
You must be signed in to change notification settings - Fork 126
[JENKINS-49635] Support new VirtualFile.toExternalURL API #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
5fb3d84
7562986
6ba60da
75b73bf
a2abb37
781d409
d323514
b3a8a3c
a01cdb6
c072ff8
f44835b
3959063
d19b231
ce7a8ac
2170267
d2bd052
c9d28b0
af6af8d
f9f8b16
c660832
eed2d6f
ae43469
5d47212
d5baf3a
2e4d5d0
5882dbd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| buildPlugin(jenkinsVersions: [null, '2.32.3']) | ||
| buildPlugin() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,20 +4,17 @@ | |
| import hudson.AbortException; | ||
| import hudson.FilePath; | ||
| import hudson.model.Run; | ||
| import jenkins.model.ArtifactManager; | ||
| import jenkins.util.VirtualFile; | ||
|
|
||
| import hudson.remoting.VirtualChannel; | ||
| import java.io.File; | ||
| import java.io.IOException; | ||
| import java.io.InputStream; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Collection; | ||
| import java.util.Map; | ||
| import java.util.Map.Entry; | ||
| import jenkins.MasterToSlaveFileCallable; | ||
| import jenkins.util.VirtualFile; | ||
|
|
||
| /** | ||
| * @author Kohsuke Kawaguchi | ||
| */ | ||
| public class ArtifactUnarchiverStepExecution extends SynchronousNonBlockingStepExecution<List<FilePath>> { | ||
| public class ArtifactUnarchiverStepExecution extends SynchronousNonBlockingStepExecution<Void> { | ||
|
||
|
|
||
| @SuppressFBWarnings(value="SE_TRANSIENT_FIELD_NOT_RESTORED", justification="Only used when starting.") | ||
| private transient final Map<String,String> mapping; | ||
|
|
@@ -31,48 +28,74 @@ public class ArtifactUnarchiverStepExecution extends SynchronousNonBlockingStepE | |
| } | ||
|
|
||
| @Override | ||
| protected List<FilePath> run() throws Exception { | ||
| protected Void run() throws Exception { | ||
| // where to copy artifacts from? | ||
| Run<?, ?> r = getContext().get(Run.class); // TODO consider an option to override this (but in what format?) | ||
|
|
||
| ArtifactManager am = r.getArtifactManager(); | ||
| VirtualFile root = r.getArtifactManager().root(); | ||
| FilePath target = getContext().get(FilePath.class); | ||
| if (target.isRemote()) { | ||
| VirtualFile rootR = root.asRemotable(); | ||
| if (rootR != null) { | ||
| return target.act(new Copy(mapping, target, rootR)); | ||
| } else { | ||
| return new Copy(mapping, target, root).invoke(null, null); | ||
| } | ||
| } else { | ||
| return new Copy(mapping, target, root).invoke(null, null); | ||
| } | ||
| } | ||
|
|
||
| private static class Copy extends MasterToSlaveFileCallable<Void> { | ||
|
|
||
| List<FilePath> files = new ArrayList<>(); | ||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| for (Entry<String, String> e : mapping.entrySet()) { | ||
| FilePath dst = new FilePath(getContext().get(FilePath.class), e.getValue()); | ||
| String src = e.getKey(); | ||
| String[] all = am.root().list(src); | ||
| if (all.length == 0) { | ||
| throw new AbortException("no artifacts to unarchive in " + src); | ||
| } else if (all.length == 1 && all[0].equals(src)) { | ||
| // the source is a file | ||
| if (dst.isDirectory()) | ||
| dst = dst.child(getFileName(all[0])); | ||
| private final Map<String, String> _mapping; | ||
| private final FilePath target; | ||
| private final VirtualFile root; | ||
|
|
||
| files.add(copy(am.root().child(all[0]), dst)); | ||
| } else { | ||
| // copy into a directory | ||
| for (String path : all) { | ||
| files.add(copy(am.root().child(path), dst.child(path))); | ||
| Copy(Map<String, String> _mapping, FilePath target, VirtualFile root) { | ||
| this._mapping = _mapping; | ||
| this.target = target; | ||
| this.root = root; | ||
| } | ||
|
|
||
| @Override public Void invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { | ||
| for (Entry<String, String> e : _mapping.entrySet()) { | ||
| FilePath dst = new FilePath(target, e.getValue()); | ||
| String src = e.getKey(); | ||
| Collection<String> all = root.list(src, null, false); | ||
| if (all.isEmpty()) { | ||
| throw new AbortException("no artifacts to unarchive in " + src); | ||
| } else if (all.size() == 1 && all.iterator().next().equals(src)) { | ||
| // the source is a file | ||
| if (dst.isDirectory()) { | ||
| dst = dst.child(getFileName(all.iterator().next())); | ||
| } | ||
|
|
||
| copy(root.child(all.iterator().next()), dst); | ||
| } else { | ||
| // copy into a directory | ||
| for (String path : all) { | ||
| copy(root.child(path), dst.child(path)); | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| return files; | ||
| } | ||
|
|
||
| private FilePath copy(VirtualFile src, FilePath dst) throws IOException, InterruptedException { | ||
| private static void copy(VirtualFile src, FilePath dst) throws IOException, InterruptedException { | ||
| try (InputStream in = src.open()) { | ||
| dst.copyFrom(in); | ||
| } | ||
| return dst; | ||
| } | ||
|
|
||
| /** | ||
| * Grabs the file name portion out of a path name. | ||
| */ | ||
| private String getFileName(String s) { | ||
| private static String getFileName(String s) { | ||
| int idx = s.lastIndexOf('/'); | ||
| if (idx>=0) s=s.substring(idx+1); | ||
| idx = s.lastIndexOf('\\'); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,26 @@ | ||
| package org.jenkinsci.plugins.workflow.steps; | ||
|
|
||
| import java.util.Arrays; | ||
| import jenkins.model.ArtifactManagerConfiguration; | ||
| import jenkins.util.VirtualFile; | ||
| import org.apache.commons.io.IOUtils; | ||
| import org.apache.commons.lang.StringUtils; | ||
| import org.jenkinsci.plugins.workflow.DirectArtifactManagerFactory; | ||
| import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; | ||
| import org.jenkinsci.plugins.workflow.job.WorkflowJob; | ||
| import org.jenkinsci.plugins.workflow.job.WorkflowRun; | ||
| import org.junit.Assert; | ||
| import static org.junit.Assert.*; | ||
| import org.junit.ClassRule; | ||
| import org.junit.Rule; | ||
| import org.junit.Test; | ||
| import org.jvnet.hudson.test.BuildWatcher; | ||
| import org.jvnet.hudson.test.Issue; | ||
| import org.jvnet.hudson.test.JenkinsRule; | ||
|
|
||
| /** | ||
| * @author Kohsuke Kawaguchi | ||
| */ | ||
| public class ArtifactArchiverStepTest extends Assert { | ||
| public class ArtifactArchiverStepTest { | ||
|
|
||
| @ClassRule public static BuildWatcher watcher = new BuildWatcher(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this used for?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just so that the test log includes the log from the build run at line 90. |
||
|
|
||
| @Rule public JenkinsRule j = new JenkinsRule(); | ||
|
|
||
| /** | ||
|
|
@@ -74,5 +78,15 @@ public void archive() throws Exception { | |
| j.assertLogContains("one/two", b); | ||
| } | ||
|
|
||
| } | ||
| @Issue("JENKINS-49635") | ||
| @Test | ||
| public void directDownload() throws Exception { | ||
| ArtifactManagerConfiguration.get().getArtifactManagerFactories().add(new DirectArtifactManagerFactory()); | ||
| j.createSlave("remote1", null, null); | ||
| j.createSlave("remote2", null, null); | ||
| WorkflowJob p = j.jenkins.createProject(WorkflowJob.class, "p"); | ||
| p.setDefinition(new CpsFlowDefinition("node('remote1') {writeFile file: 'x', text: 'contents'; archiveArtifacts 'x'}; node('remote2') {unarchive mapping: [x: 'x']; echo(/loaded ${readFile('x')}/)}", true)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, because that behavior is not being defined in this PR—it would be overridden in the plugin providing the |
||
| j.assertLogContains("loaded contents", j.buildAndAssertSuccess(p)); | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2.107.1 please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the baseline is newer than that.