From 6da253b8fff9a9d9cbbf65807efa7aeaddc9c9d3 Mon Sep 17 00:00:00 2001 From: Leonidas Spyropoulos Date: Wed, 2 Feb 2022 15:13:54 +0000 Subject: [PATCH] build: introduce support for reproducible builds (#1995) Reproducible builds is an initiative to create an independently-verifiable path from source to binary code [1]. This can be done by: - Make all archive tasks in gradle reproducible by ignoring timestamp on files [2] - Preserve the order in side the archives [2] - Ensure GlobalBuildInfoPlugin.java use [SOURCE_DATE_EPOCH] when available [SOURCE_DATE_EPOCH]: https://reproducible-builds.org/docs/source-date-epoch/ [1]: https://reproducible-builds.org/ [2]: https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives Signed-off-by: Leonidas Spyropoulos --- build.gradle | 8 ++++++++ .../gradle/info/GlobalBuildInfoPlugin.java | 2 +- .../java/org/opensearch/gradle/util/Util.java | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 4be3ce4e53cd0..91472a62a2bd9 100644 --- a/build.gradle +++ b/build.gradle @@ -274,6 +274,14 @@ allprojects { javadoc.options.addStringOption('Xdoclint:all,-missing', '-quiet') } + // support for reproducible builds + tasks.withType(AbstractArchiveTask).configureEach { + // ignore file timestamps + // be consistent in archive file order + preserveFileTimestamps = false + reproducibleFileOrder = true + } + project.afterEvaluate { // Handle javadoc dependencies across projects. Order matters: the linksOffline for // org.opensearch:opensearch must be the last one or all the links for the diff --git a/buildSrc/src/main/java/org/opensearch/gradle/info/GlobalBuildInfoPlugin.java b/buildSrc/src/main/java/org/opensearch/gradle/info/GlobalBuildInfoPlugin.java index 60afe8334f05d..ccd82372bb11b 100644 --- a/buildSrc/src/main/java/org/opensearch/gradle/info/GlobalBuildInfoPlugin.java +++ b/buildSrc/src/main/java/org/opensearch/gradle/info/GlobalBuildInfoPlugin.java @@ -121,7 +121,7 @@ public void apply(Project project) { params.setGradleJavaVersion(Jvm.current().getJavaVersion()); params.setGitRevision(gitInfo.getRevision()); params.setGitOrigin(gitInfo.getOrigin()); - params.setBuildDate(ZonedDateTime.now(ZoneOffset.UTC)); + params.setBuildDate(Util.getBuildDate(ZonedDateTime.now(ZoneOffset.UTC))); params.setTestSeed(getTestSeed()); params.setIsCi(System.getenv("JENKINS_URL") != null); params.setIsInternal(isInternal); diff --git a/buildSrc/src/main/java/org/opensearch/gradle/util/Util.java b/buildSrc/src/main/java/org/opensearch/gradle/util/Util.java index fc79d991211d6..71b1e5040340d 100644 --- a/buildSrc/src/main/java/org/opensearch/gradle/util/Util.java +++ b/buildSrc/src/main/java/org/opensearch/gradle/util/Util.java @@ -48,6 +48,9 @@ import java.io.UncheckedIOException; import java.net.URI; import java.net.URISyntaxException; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.Locale; import java.util.Optional; import java.util.function.Supplier; @@ -187,4 +190,17 @@ public String toString() { } }; } + + public static ZonedDateTime getBuildDate(ZonedDateTime defaultValue) { + final String sourceDateEpoch = System.getenv("SOURCE_DATE_EPOCH"); + if (sourceDateEpoch != null) { + try { + return ZonedDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(sourceDateEpoch)), ZoneOffset.UTC); + } catch (NumberFormatException e) { + throw new GradleException("Sysprop [SOURCE_DATE_EPOCH] must be of type [long]", e); + } + } else { + return defaultValue; + } + } }