Skip to content

Commit

Permalink
Use reproducible version qualifiers when project.build.outputTimestam…
Browse files Browse the repository at this point in the history
…p property is set
  • Loading branch information
Zlika committed Dec 28, 2024
1 parent 0222e62 commit a8284ac
Show file tree
Hide file tree
Showing 23 changed files with 84 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<modules>
<module>reproducible.buildqualifier</module>
<module>reproducible.bundle</module>
<module>reproducible.bundle.feature</module>
<module>reproducible.iu</module>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Reproducible-buildqualifier
Bundle-SymbolicName: reproducible.buildqualifier
Bundle-Version: 1.0.0.qualifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

<artifactId>reproducible.buildqualifier</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package reproducible.buildqualifier;

public class PublicClass
{

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>reproducible.archive.timestamps</groupId>
<artifactId>reproducible.archive.timestamps.parent</artifactId>
<groupId>reproducible.build</groupId>
<artifactId>reproducible.build.parent</artifactId>
<version>1.0.0</version>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
package org.eclipse.tycho.test.reproducible;

import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
Expand All @@ -21,7 +25,7 @@
import org.junit.Assert;
import org.junit.Test;

public class ReproducibleArchiveTimestampsTest extends AbstractTychoIntegrationTest {
public class ReproducibleBuildTest extends AbstractTychoIntegrationTest {
// The ZipEntry.getLastModifiedTime() method uses the default timezone to
// convert date and time fields to Instant, so we also use the default timezone
// for the expected timestamp here.
Expand All @@ -30,17 +34,17 @@ public class ReproducibleArchiveTimestampsTest extends AbstractTychoIntegrationT
.toInstant(OffsetDateTime.now().getOffset());

/**
* Check that the timestamp of the files inside the produced archives is equal
* to the one specified in the "project.build.outputTimestamp" property of the
* pom file.
* Check that the build is reproducible.
*/
@Test
public void test() throws Exception {
Verifier verifier = getVerifier("reproducible-archive-timestamps");
Verifier verifier = getVerifier("reproducible-build");
verifier.executeGoals(List.of("clean", "verify"));
verifier.verifyErrorFreeLog();

// Check timestamps of files in archives
// Check that the timestamp of the files inside the produced archives is equal
// to the one specified in the "project.build.outputTimestamp" property of the
// pom file.
checkTimestamps(verifier.getBasedir() + "/reproducible.bundle/target/reproducible.bundle-1.0.0.jar");
checkTimestamps(verifier.getBasedir() + "/reproducible.bundle/target/reproducible.bundle-1.0.0-attached.jar");
checkTimestamps(verifier.getBasedir() + "/reproducible.bundle/target/reproducible.bundle-1.0.0-sources.jar");
Expand All @@ -51,6 +55,11 @@ public void test() throws Exception {
checkTimestamps(verifier.getBasedir() + "/reproducible.iu/target/reproducible.iu-1.0.0.zip");
checkTimestamps(verifier.getBasedir() + "/reproducible.repository/target/reproducible.repository-1.0.0.zip");
checkTimestamps(verifier.getBasedir() + "/reproducible.repository/target/p2-site.zip");

// Check that the build qualifier uses the timestamp specified in the
// "project.build.outputTimestamp" property of the pom file.
checkBuildQualifier(verifier.getBasedir()
+ "/reproducible.buildqualifier/target/reproducible.buildqualifier-1.0.0-SNAPSHOT.jar");
}

private void checkTimestamps(String file) throws IOException {
Expand All @@ -62,4 +71,12 @@ private void checkTimestamps(String file) throws IOException {
}
}
}

private void checkBuildQualifier(String file) throws IOException {
try (FileSystem fileSystem = FileSystems.newFileSystem(Path.of(file))) {
Path manifest = fileSystem.getPath("META-INF/MANIFEST.MF");
List<String> lines = Files.readAllLines(manifest);
Assert.assertTrue(lines.stream().anyMatch(l -> l.equals("Bundle-Version: 1.0.0.202301010000")));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
import static org.eclipse.tycho.TychoProperties.UNQUALIFIED_VERSION;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Date;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;

import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
Expand Down Expand Up @@ -120,6 +123,18 @@ public class BuildQualifierMojo extends AbstractVersionMojo {
@Parameter(property = "tycho.buildqualifier.provider")
protected String timestampProvider;

/**
* Timestamp for reproducible build qualifier, either formatted as ISO 8601
* extended offset date-time (e.g. in UTC such as '2011-12-03T10:15:30Z' or with
* an offset '2019-10-05T20:37:42+06:00'), or as an int representing seconds
* since the epoch (like <a href=
* "https://reproducible-builds.org/docs/source-date-epoch/">SOURCE_DATE_EPOCH</a>).
* This timestamp is only used if there is not custom build timestamp provider
* set.
*/
@Parameter(defaultValue = "${project.build.outputTimestamp}")
private String outputTimestamp;

@Parameter(property = "mojoExecution", readonly = true)
protected MojoExecution execution;

Expand Down Expand Up @@ -266,8 +281,12 @@ private String getUnqualifiedVersion() {
}

protected Date getBuildTimestamp() throws MojoExecutionException {
String hint = timestampProvider != null ? timestampProvider : DefaultBuildTimestampProvider.ROLE_HINT;
BuildTimestampProvider provider = timestampProviders.get(hint);
Optional<Instant> reproducibleTimestamp = MavenArchiver.parseBuildOutputTimestamp(outputTimestamp);
if (reproducibleTimestamp.isPresent() && (timestampProvider == null)) {
return Date.from(reproducibleTimestamp.get());
}
String hint = (timestampProvider != null) ? timestampProvider : DefaultBuildTimestampProvider.ROLE_HINT;
BuildTimestampProvider provider = timestampProviders.get(hint);
if (provider == null) {
throw new MojoExecutionException("Unable to lookup BuildTimestampProvider with hint='" + hint + "'");
}
Expand Down

0 comments on commit a8284ac

Please sign in to comment.