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

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

    Details

    • Type: Improvement
    • Status: Closed (View Workflow)
    • Priority: Major
    • Resolution: Fixed
    • Component/s: core
    • Labels:
      None
    • Environment:
      All platforms, Hudson 1.361.
    • Similar Issues:

      Description

      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.

        Attachments

        1. Parameters.jpg
          8 kB
          Steven G Brown
        2. Parameters (After).jpg
          3 kB
          Steven G Brown

          Activity

          Hide
          stevengbrown Steven G Brown 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
          
          Show
          stevengbrown Steven G Brown 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
          Hide
          scm_issue_link 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

          Show
          scm_issue_link 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

            People

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

              Dates

              • Created:
                Updated:
                Resolved: