jenkinsci / maven-hpi-plugin

Maven plugin for building Jenkins plugins
http://jenkinsci.github.io/maven-hpi-plugin/
Apache License 2.0
73 stars 87 forks source link

JAR and JPI creation is nondeterministic #598

Closed basil closed 7 months ago

basil commented 7 months ago

One issue blocking progress on jenkinsci/plugin-pom#919 is that we do not call MavenArchiver#configureReproducibleBuild as recommended in https://s.apache.org/reproducible-builds — though perhaps this could be fixed with something along the lines of

diff --git a/src/main/java/org/jenkinsci/maven/plugins/hpi/AbstractJenkinsManifestMojo.java b/src/main/java/org/jenkinsci/maven/plugins/hpi/AbstractJenkinsManifestMojo.java
index d7a63c3..f9575a9 100644
--- a/src/main/java/org/jenkinsci/maven/plugins/hpi/AbstractJenkinsManifestMojo.java
+++ b/src/main/java/org/jenkinsci/maven/plugins/hpi/AbstractJenkinsManifestMojo.java
@@ -42,6 +42,7 @@ import org.apache.maven.model.License;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
 import org.codehaus.plexus.archiver.jar.Manifest;
 import org.codehaus.plexus.archiver.jar.ManifestException;

@@ -64,6 +65,16 @@ public abstract class AbstractJenkinsManifestMojo extends AbstractHpiMojo {
     @Parameter(property = "hpi.compatibleSinceVersion")
     private String compatibleSinceVersion;

+    /**
+     * Timestamp for reproducible output archive entries, either formatted as ISO 8601
+     * <code>yyyy-MM-dd'T'HH:mm:ssXXX</code> or as an int representing seconds since the epoch (like
+     * <a href="https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>).
+     *
+     * @since TODO
+     */
+    @Parameter(defaultValue = "${project.build.outputTimestamp}")
+    private String outputTimestamp;
+
     /**
      * Optional - sandbox status of this plugin.
      */
@@ -79,6 +90,19 @@ public abstract class AbstractJenkinsManifestMojo extends AbstractHpiMojo {
     @Parameter
     protected String minimumJavaVersion;

+    /**
+     * @return an instance of {@link MavenArchiver} preconfigured for reproducible builds
+     *
+     * @since TODO
+     */
+    protected MavenArchiver newMavenArchiver(JarArchiver jarArchiver, File outputFile) {
+        MavenArchiver mavenArchiver = new MavenArchiver();
+        mavenArchiver.setArchiver(jarArchiver);
+        mavenArchiver.setOutputFile(outputFile);
+        mavenArchiver.configureReproducibleBuild(outputTimestamp);
+        return mavenArchiver;
+    }
+
     /**
      * Generates a manifest file to be included in the .hpi file
      */
diff --git a/src/main/java/org/jenkinsci/maven/plugins/hpi/HpiMojo.java b/src/main/java/org/jenkinsci/maven/plugins/hpi/HpiMojo.java
index 5876eba..34c2ae9 100644
--- a/src/main/java/org/jenkinsci/maven/plugins/hpi/HpiMojo.java
+++ b/src/main/java/org/jenkinsci/maven/plugins/hpi/HpiMojo.java
@@ -134,9 +134,7 @@ public class HpiMojo extends AbstractJenkinsManifestMojo {
             // create a jar file to be used when other plugins depend on this plugin.
             jarFile = getOutputFile(".jar");
             getLog().info("Generating jar " + jarFile.getAbsolutePath());
-            MavenArchiver archiver = new MavenArchiver();
-            archiver.setArchiver(jarArchiver);
-            archiver.setOutputFile(jarFile);
+            MavenArchiver archiver = newMavenArchiver(jarArchiver, jarFile);
             jarArchiver.addConfiguredManifest(manifest);
             File indexJelly = new File(getClassesDirectory(), "index.jelly");
             if (!indexJelly.isFile()) {
@@ -165,10 +163,7 @@ public class HpiMojo extends AbstractJenkinsManifestMojo {
         File hpiFile = getOutputFile(".hpi");
         getLog().info("Generating hpi " + hpiFile.getAbsolutePath());

-        MavenArchiver archiver = new MavenArchiver();
-
-        archiver.setArchiver(hpiArchiver);
-        archiver.setOutputFile(hpiFile);
+        MavenArchiver archiver = newMavenArchiver(hpiArchiver, hpiFile);

         hpiArchiver.addConfiguredManifest(manifest);
         hpiArchiver.addDirectory(getWebappDirectory(), getIncludes(), getExcludes());
diff --git a/src/main/java/org/jenkinsci/maven/plugins/hpi/JarMojo.java b/src/main/java/org/jenkinsci/maven/plugins/hpi/JarMojo.java
index 818c289..5278ef5 100644
--- a/src/main/java/org/jenkinsci/maven/plugins/hpi/JarMojo.java
+++ b/src/main/java/org/jenkinsci/maven/plugins/hpi/JarMojo.java
@@ -106,9 +106,7 @@ public class JarMojo extends AbstractJenkinsManifestMojo {

         // create a jar file to be used when other plugins depend on this plugin.
         File jarFile = getOutputFile(".jar");
-        MavenArchiver archiver = new MavenArchiver();
-        archiver.setArchiver(jarArchiver);
-        archiver.setOutputFile(jarFile);
+        MavenArchiver archiver = newMavenArchiver(jarArchiver, jarFile);
         jarArchiver.addConfiguredManifest(manifest);
         jarArchiver.addDirectory(getClassesDirectory());
         archiver.createArchive(session, project, archive);