Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-6719

Allow file parameters to be downloaded from the build Parameters page.

    • Icon: Improvement Improvement
    • Resolution: Fixed
    • Icon: Major Major
    • core
    • None
    • All platforms, Hudson 1.361.

      For a build created with a file parameter, include a link to download this file on the Parameters page. For example, see screenshot Parameters (After).jpg.

      As of Hudson 1.361, "TODO" is displayed instead. See screenshot Parameters.jpg.

          [JENKINS-6719] Allow file parameters to be downloaded from the build Parameters page.

          StevenGBrown added a comment - - edited

          Implemented by the following patch. In detail:

          • The file parameter is copied into a directory under the build's root directory.
          • FileParameterValue serves this file in response to a Stapler request.
          • FileParameterValue's jelly.xml includes a link to this file, replacing the "TODO".
          • When a file parameter is not provided, or the build was created prior to applying this patch, no link will be displayed.

          The file parameter is already copied into the workspace, but this is not sufficient, since it will most likely be overridden by future builds. Therefore the file parameter is also copied under the build's root directory.

          Alternatively, it would be possible to store the file parameter within the build.xml file. I chose to store it as a separate file instead, which gives Hudson administrators the option of deleting file parameters which contain sensitive information or which use up too much disk space. Additionally, I do not want to reduce the readability of the build.xml file by including this data within it.

          Index: trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java
          ===================================================================
          --- trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java	(revision 31581)
          +++ trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java	(working copy)
          @@ -24,9 +24,12 @@
           package hudson.model;
           
           import org.kohsuke.stapler.DataBoundConstructor;
          +import org.kohsuke.stapler.StaplerRequest;
          +import org.kohsuke.stapler.StaplerResponse;
           import org.apache.commons.fileupload.FileItem;
           import org.apache.commons.fileupload.disk.DiskFileItem;
           import org.apache.commons.lang.StringUtils;
          +import org.apache.commons.io.FilenameUtils;
           import org.apache.commons.io.IOUtils;
           
           import hudson.tasks.BuildWrapper;
          @@ -40,6 +43,7 @@
           import java.io.OutputStream;
           import java.io.FileInputStream;
           import java.io.FileOutputStream;
          +import javax.servlet.ServletException;
           
           /**
            * {@link ParameterValue} for {@link FileParameterDefinition}.
          @@ -55,16 +59,23 @@
           public class FileParameterValue extends ParameterValue {
               private FileItem file;
           
          +    /**
          +     * The name of the originally uploaded file.
          +     */
          +    private final String originalFileName;
          +
               private String location;
           
               @DataBoundConstructor
               public FileParameterValue(String name, FileItem file) {
                   this(name, file, null);
               }
          +
               public FileParameterValue(String name, FileItem file, String description) {
                   super(name, description);
                   assert file!=null;
                   this.file = file;
          +        this.originalFileName = FilenameUtils.getName(file.getName());
               }
           
               public FileParameterValue(String name, File file, String desc) {
          @@ -76,14 +87,28 @@
                   this.location = location;
               }
           
          +    /**
          +     * Get the name of the originally uploaded file. If this
          +     * {@link FileParameterValue} was created prior to 1.362, this method will
          +     * return {@code null}.
          +     *
          +     * @return the name of the originally uploaded file
          +     */
          +    public String getOriginalFileName() {
          +        return originalFileName;
          +    }
          +
               @Override
               public BuildWrapper createBuildWrapper(AbstractBuild<?,?> build) {
                   return new BuildWrapper() {
          +            @Override
                       public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
                       	if (!StringUtils.isEmpty(file.getName())) {
          -            		listener.getLogger().println("Copying file to "+location);
          -            		build.getWorkspace().child(location).copyFrom(file);
          -            		file = null;
          +            	    listener.getLogger().println("Copying file to "+location);
          +                    FilePath locationFilePath = build.getWorkspace().child(location);
          +            	    locationFilePath.copyFrom(file);
          +            	    file = null;
          +                    locationFilePath.copyTo(new FilePath(getLocationUnderBuild(build)));
                       	}
                           return new Environment() {};
                       }
          @@ -121,10 +146,38 @@
           	
               @Override
               public String getShortDescription() {
          -    	return "(FileParameterValue) " + getName() + "='" + file.getName() + "'";
          +    	return "(FileParameterValue) " + getName() + "='" + originalFileName + "'";
               }
           
               /**
          +     * Serve this file parameter in response to a {@link StaplerRequest}.
          +     *
          +     * @param request
          +     * @param response
          +     * @throws ServletException
          +     * @throws IOException
          +     */
          +    public void doDynamic(StaplerRequest request, StaplerResponse response) throws ServletException, IOException {
          +        if (("/" + originalFileName).equals(request.getRestOfPath())) {
          +            AbstractBuild build = (AbstractBuild)request.findAncestor(AbstractBuild.class).getObject();
          +            File fileParameter = getLocationUnderBuild(build);
          +            if (fileParameter.isFile()) {
          +                response.serveFile(request, fileParameter.toURI().toURL());
          +            }
          +        }
          +    }
          +
          +    /**
          +     * Get the location under the build directory to store the file parameter.
          +     *
          +     * @param build the build
          +     * @return the location to store the file parameter
          +     */
          +    private File getLocationUnderBuild(AbstractBuild build) {
          +        return new File(build.getRootDir(), "fileParameters/" + location);
          +    }
          +
          +    /**
                * Default implementation from {@link File}.
                */
               public static final class FileItemImpl implements FileItem {
          Index: trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly
          ===================================================================
          --- trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly	(revision 31581)
          +++ trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly	(working copy)
          @@ -25,7 +25,9 @@
           <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
           	xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"
           	xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">
          -	<f:entry title="${it.name}">
          -    TODO
          -  </f:entry>
          +    <f:entry title="${it.name}">
          +        <j:if test="${it.originalFileName != null}">
          +            <a href="parameter/${it.name}/${it.originalFileName}">${it.originalFileName}</a>
          +        </j:if>
          +    </f:entry>
           </j:jelly>
          \ No newline at end of file
          

          StevenGBrown added a comment - - edited Implemented by the following patch. In detail: The file parameter is copied into a directory under the build's root directory. FileParameterValue serves this file in response to a Stapler request. FileParameterValue 's jelly.xml includes a link to this file, replacing the "TODO". When a file parameter is not provided, or the build was created prior to applying this patch, no link will be displayed. The file parameter is already copied into the workspace, but this is not sufficient, since it will most likely be overridden by future builds. Therefore the file parameter is also copied under the build's root directory. Alternatively, it would be possible to store the file parameter within the build.xml file. I chose to store it as a separate file instead, which gives Hudson administrators the option of deleting file parameters which contain sensitive information or which use up too much disk space. Additionally, I do not want to reduce the readability of the build.xml file by including this data within it. Index: trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java =================================================================== --- trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java (revision 31581) +++ trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java (working copy) @@ -24,9 +24,12 @@ package hudson.model; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItem; import org.apache.commons.lang.StringUtils; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import hudson.tasks.BuildWrapper; @@ -40,6 +43,7 @@ import java.io.OutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; +import javax.servlet.ServletException; /** * {@link ParameterValue} for {@link FileParameterDefinition}. @@ -55,16 +59,23 @@ public class FileParameterValue extends ParameterValue { private FileItem file; + /** + * The name of the originally uploaded file. + */ + private final String originalFileName; + private String location; @DataBoundConstructor public FileParameterValue(String name, FileItem file) { this(name, file, null); } + public FileParameterValue(String name, FileItem file, String description) { super(name, description); assert file!=null; this.file = file; + this.originalFileName = FilenameUtils.getName(file.getName()); } public FileParameterValue(String name, File file, String desc) { @@ -76,14 +87,28 @@ this.location = location; } + /** + * Get the name of the originally uploaded file. If this + * {@link FileParameterValue} was created prior to 1.362, this method will + * return {@code null}. + * + * @return the name of the originally uploaded file + */ + public String getOriginalFileName() { + return originalFileName; + } + @Override public BuildWrapper createBuildWrapper(AbstractBuild<?,?> build) { return new BuildWrapper() { + @Override public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { if (!StringUtils.isEmpty(file.getName())) { - listener.getLogger().println("Copying file to "+location); - build.getWorkspace().child(location).copyFrom(file); - file = null; + listener.getLogger().println("Copying file to "+location); + FilePath locationFilePath = build.getWorkspace().child(location); + locationFilePath.copyFrom(file); + file = null; + locationFilePath.copyTo(new FilePath(getLocationUnderBuild(build))); } return new Environment() {}; } @@ -121,10 +146,38 @@ @Override public String getShortDescription() { - return "(FileParameterValue) " + getName() + "='" + file.getName() + "'"; + return "(FileParameterValue) " + getName() + "='" + originalFileName + "'"; } /** + * Serve this file parameter in response to a {@link StaplerRequest}. + * + * @param request + * @param response + * @throws ServletException + * @throws IOException + */ + public void doDynamic(StaplerRequest request, StaplerResponse response) throws ServletException, IOException { + if (("/" + originalFileName).equals(request.getRestOfPath())) { + AbstractBuild build = (AbstractBuild)request.findAncestor(AbstractBuild.class).getObject(); + File fileParameter = getLocationUnderBuild(build); + if (fileParameter.isFile()) { + response.serveFile(request, fileParameter.toURI().toURL()); + } + } + } + + /** + * Get the location under the build directory to store the file parameter. + * + * @param build the build + * @return the location to store the file parameter + */ + private File getLocationUnderBuild(AbstractBuild build) { + return new File(build.getRootDir(), "fileParameters/" + location); + } + + /** * Default implementation from {@link File}. */ public static final class FileItemImpl implements FileItem { Index: trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly =================================================================== --- trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly (revision 31581) +++ trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly (working copy) @@ -25,7 +25,9 @@ <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project"> - <f:entry title="${it.name}"> - TODO - </f:entry> + <f:entry title="${it.name}"> + <j:if test="${it.originalFileName != null}"> + <a href="parameter/${it.name}/${it.originalFileName}">${it.originalFileName}</a> + </j:if> + </f:entry> </j:jelly> \ No newline at end of file

          Code changed in hudson
          User: : StevenGBrown
          Path:
          trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java
          trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly
          trunk/www/changelog.html
          http://jenkins-ci.org/commit/31852
          Log:
          [FIXED JENKINS-6719] File parameters can now be downloaded from the build Parameters page

          SCM/JIRA link daemon added a comment - Code changed in hudson User: : StevenGBrown Path: trunk/hudson/main/core/src/main/java/hudson/model/FileParameterValue.java trunk/hudson/main/core/src/main/resources/hudson/model/FileParameterValue/value.jelly trunk/www/changelog.html http://jenkins-ci.org/commit/31852 Log: [FIXED JENKINS-6719] File parameters can now be downloaded from the build Parameters page

            stevengbrown Steven G Brown
            stevengbrown Steven G Brown
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved: