Enable Maven reproducible builds
- configure Maven to run build reproducibly [1] - use UTC timestamp of checked out commit as build timestamp - add git-describe, git-commit-id, git-commit-id, git-tags, git-remote-origin-url to MANIFEST.MF files - configure cyclonedx-maven-plugin to also use UTC timestamp of checked out commit - for packaging build use tycho-buildtimestamp-jgit [2] to ensure version uses the timestamp of the last commit - SBOMs are not reproducible by design [3] they should have a build timestamp matching the time when the build was executed and a serial number which is a unique UUID per build run. Hence exclude them from comparison [4]. - Use gmavenplus-plugin to format build timestamps. Maven expects build timestamp in ISO-8601 format, to replace the qualifier in versions the timestamp format must be compatible with rules for OSGi version numbers. Didn't find a way to read the properties set by the git-commit-id-maven-plugin from another plugin. Hence use JGit in a groovy script to get the commit time of the current HEAD and provide it in these two formats. TODO: packaging build (features and p2 repository) is not yet binary reproducible since that's not yet supported by Tycho [5], artefacts have reproducible version numbers but file lastModified timestamps are not yet reproducible. Test plan for Maven build: - build using mvn clean install" - verify second build is reproducible: mvn -T1 clean verify artifact:compare verification seems not to be thread-safe, hence run it with a single thread using option -T1 For packaging build (still fails due to non-reproducible file timestamps): - build using mvn -f org.eclipse.jgit.packaging/pom.xml clean install - verify second build is reproducible: mvn -T1 -f org.eclipse.jgit.packaging/pom.xml clean verify artifact:compare [1] https://maven.apache.org/guides/mini/guide-reproducible-builds.html [2] https://wiki.eclipse.org/Tycho/Reproducible_Version_Qualifiers [3] https://github.com/CycloneDX/cyclonedx-maven-plugin/issues/84 [4] https://maven.apache.org/plugins/maven-artifact-plugin/compare-mojo.html [5] https://github.com/eclipse-tycho/tycho/issues/233 Change-Id: I0202f55a1b6ae0edd922cfef638beb39d2ce9417
This commit is contained in:
parent
97afcb050b
commit
6007371e3a
|
@ -69,7 +69,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true" />
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}" />
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}" />
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -91,7 +91,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
<java.version>11</java.version>
|
||||
<tycho-version>4.0.2</tycho-version>
|
||||
<target-platform>jgit-4.17</target-platform>
|
||||
<project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp>
|
||||
</properties>
|
||||
|
||||
<pluginRepositories>
|
||||
|
@ -223,7 +224,6 @@
|
|||
<outputFormat>json</outputFormat>
|
||||
<outputName>cyclonedx</outputName>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<outputTimestamp>${project.build.outputTimestamp}</outputTimestamp>
|
||||
<verbose>false</verbose>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
@ -235,6 +235,26 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>get-the-git-infos</id>
|
||||
<goals>
|
||||
<goal>revision</goal>
|
||||
</goals>
|
||||
<phase>initialize</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<generateGitPropertiesFile>false</generateGitPropertiesFile>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<dateFormat>yyyy-MM-dd'T'HH:mm:ss'Z'</dateFormat>
|
||||
<dateFormatTimeZone>UTC</dateFormatTimeZone>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
|
@ -255,6 +275,30 @@
|
|||
<encoding>ISO-8859-1</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Implementation-Title>JGit ${project.artifactId}</Implementation-Title>
|
||||
<Implementation-Version>${project.version}</Implementation-Version>
|
||||
<Implementation-Vendor>Eclipse.org - JGit</Implementation-Vendor>
|
||||
<Implementation-Vendor-Id>org.eclipse.jgit</Implementation-Vendor-Id>
|
||||
<Implementation-Vendor-URL>${jgit-url}</Implementation-Vendor-URL>
|
||||
<git-describe>${git.commit.id.describe}</git-describe>
|
||||
<git-commit-id>${git.commit.id}</git-commit-id>
|
||||
<git-commit-time>${git.commit.time}</git-commit-time>
|
||||
<git-tags>${git.tags}</git-tags>
|
||||
<git-remote-origin-url>${git.remote.origin.url}</git-remote-origin-url>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<!-- TODO: uncomment this in order to skip empty artifact of test modules as soon as bug 416299 is fixed
|
||||
<skipIfEmpty>true</skipIfEmpty>
|
||||
-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>target-platform-configuration</artifactId>
|
||||
|
@ -318,6 +362,22 @@
|
|||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-packaging-plugin</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-buildtimestamp-jgit</artifactId>
|
||||
<version>${tycho-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<timestampProvider>jgit</timestampProvider>
|
||||
<jgit.ignore>
|
||||
pom.xml
|
||||
.polyglot.build.properties
|
||||
target/
|
||||
</jgit.ignore>
|
||||
<format>yyyyMMddHHmm</format>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
|
@ -353,6 +413,15 @@
|
|||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-artifact-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<ignore>**/*cyclonedx.json</ignore>
|
||||
<reproducible>true</reproducible>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true" />
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}" />
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}" />
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true" />
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}" />
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}" />
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true" />
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}" />
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}" />
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
<target>
|
||||
<copy file="META-INF/SOURCE-MANIFEST.MF" tofile="${source-bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${source-bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
|
128
pom.xml
128
pom.xml
|
@ -113,10 +113,11 @@
|
|||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>
|
||||
<java.version>11</java.version>
|
||||
<bundle-manifest>${project.build.directory}/META-INF/MANIFEST.MF</bundle-manifest>
|
||||
|
||||
<project.build.outputTimestamp>${commit.time.iso}</project.build.outputTimestamp>
|
||||
|
||||
<jgit-last-release-version>6.7.0.202309050840-r</jgit-last-release-version>
|
||||
<ant-version>1.10.14</ant-version>
|
||||
<apache-sshd-version>2.10.0</apache-sshd-version>
|
||||
|
@ -191,6 +192,11 @@
|
|||
<Implementation-Vendor>Eclipse.org - JGit</Implementation-Vendor>
|
||||
<Implementation-Vendor-Id>org.eclipse.jgit</Implementation-Vendor-Id>
|
||||
<Implementation-Vendor-URL>${jgit-url}</Implementation-Vendor-URL>
|
||||
<git-describe>${git.commit.id.describe}</git-describe>
|
||||
<git-commit-id>${git.commit.id}</git-commit-id>
|
||||
<git-commit-time>${git.commit.time}</git-commit-time>
|
||||
<git-tags>${git.tags}</git-tags>
|
||||
<git-remote-origin-url>${git.remote.origin.url}</git-remote-origin-url>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<!-- TODO: uncomment this in order to skip empty artifact of test modules as soon as bug 416299 is fixed
|
||||
|
@ -358,6 +364,20 @@
|
|||
<artifactId>license-tool-plugin</artifactId>
|
||||
<version>1.0.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.cyclonedx</groupId>
|
||||
<artifactId>cyclonedx-maven-plugin</artifactId>
|
||||
<version>2.7.9</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-artifact-plugin</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<ignore>**/*cyclonedx.json</ignore>
|
||||
<reproducible>true</reproducible>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
|
@ -398,7 +418,7 @@
|
|||
<target if="${translate-qualifier}">
|
||||
<copy file="META-INF/MANIFEST.MF" tofile="${bundle-manifest}" overwrite="true"/>
|
||||
<replace file="${bundle-manifest}">
|
||||
<replacefilter token=".qualifier" value=".${maven.build.timestamp}"/>
|
||||
<replacefilter token=".qualifier" value=".${commit.time.version}"/>
|
||||
</replace>
|
||||
</target>
|
||||
</configuration>
|
||||
|
@ -570,7 +590,6 @@
|
|||
<plugin>
|
||||
<groupId>org.cyclonedx</groupId>
|
||||
<artifactId>cyclonedx-maven-plugin</artifactId>
|
||||
<version>2.7.9</version>
|
||||
<configuration>
|
||||
<projectType>library</projectType>
|
||||
<schemaVersion>1.4</schemaVersion>
|
||||
|
@ -586,6 +605,7 @@
|
|||
<outputName>cyclonedx</outputName>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<verbose>false</verbose>
|
||||
<detectUnusedForOptionalScope>true</detectUnusedForOptionalScope>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
|
@ -596,6 +616,108 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.github.git-commit-id</groupId>
|
||||
<artifactId>git-commit-id-maven-plugin</artifactId>
|
||||
<version>6.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>get-the-git-infos</id>
|
||||
<goals>
|
||||
<goal>revision</goal>
|
||||
</goals>
|
||||
<phase>initialize</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<generateGitPropertiesFile>false</generateGitPropertiesFile>
|
||||
<injectAllReactorProjects>true</injectAllReactorProjects>
|
||||
<dateFormatTimeZone>UTC</dateFormatTimeZone>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmavenplus</groupId>
|
||||
<artifactId>gmavenplus-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy</artifactId>
|
||||
<version>4.0.15</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.groovy</groupId>
|
||||
<artifactId>groovy-ant</artifactId>
|
||||
<version>4.0.15</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-dynamic-properties</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<bindAllProjectProperties>true</bindAllProjectProperties>
|
||||
<bindAllSessionUserProperties>true</bindAllSessionUserProperties>
|
||||
<scripts>
|
||||
<script><![CDATA[
|
||||
@Grapes([
|
||||
@Grab(group='org.eclipse.jgit', module='org.eclipse.jgit', version='6.7.0.202309050840-r')
|
||||
])
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import org.eclipse.jgit.lib.Constants
|
||||
import org.eclipse.jgit.lib.ObjectId
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.lib.RepositoryBuilder
|
||||
import org.eclipse.jgit.revwalk.RevCommit
|
||||
import org.eclipse.jgit.revwalk.RevObject
|
||||
import org.eclipse.jgit.revwalk.RevTag
|
||||
import org.eclipse.jgit.revwalk.RevWalk
|
||||
|
||||
try {
|
||||
RepositoryBuilder rb = new RepositoryBuilder().setGitDir().readEnvironment().findGitDir()
|
||||
if (rb.getGitDir() == null) {
|
||||
throw new Exception("Can't find .git directory")
|
||||
}
|
||||
Repository repo = rb.build()
|
||||
ObjectId objectId = repo.resolve(Constants.HEAD)
|
||||
try (RevWalk rw = new RevWalk(repo)) {
|
||||
RevObject obj = rw.parseAny(objectId)
|
||||
while (obj instanceof RevTag) {
|
||||
obj = ((RevTag) obj).getObject()
|
||||
rw.parseBody(obj)
|
||||
}
|
||||
|
||||
switch (obj.getType()) {
|
||||
case Constants.OBJ_COMMIT:
|
||||
RevCommit c = (RevCommit) obj
|
||||
Instant time = c.getCommitterIdent().getWhenAsInstant()
|
||||
DateTimeFormatter iso8601Fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneId.of("UTC"))
|
||||
DateTimeFormatter versionFmt = DateTimeFormatter.ofPattern("yyyyMMddHHmm").withZone(ZoneId.of("UTC"))
|
||||
String isoTime = iso8601Fmt.format(time)
|
||||
String versionTime = versionFmt.format(time)
|
||||
project.properties.setProperty("commit.time.iso", isoTime)
|
||||
project.properties.setProperty("commit.time.version", versionTime)
|
||||
break
|
||||
default:
|
||||
throw new Exception("Didn't expect " + obj.name() + ", " + obj.getType())
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
]]></script>
|
||||
</scripts>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
Loading…
Reference in New Issue