Skip to content

Commit 3be8a00

Browse files
committed
Allow overriding JAR manifest entries for reproducibility
With these changes, the `Build-Date`, `Build-Time`, and `Created-By` manifest entries can be taken from the released JARs and passed to the build in order to check for reproducibility: ./gradlew assemble \ -Pmanifest.buildTimestamp='2024-01-07 14:00:54.292+0100' \ -Pmanifest.createdBy='21.0.1 (BellSoft 21.0.1+12-LTS)' Closes #3559.
1 parent b0d3cd0 commit 3be8a00

File tree

5 files changed

+42
-24
lines changed

5 files changed

+42
-24
lines changed

gradle.properties

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ platformVersion = 1.10.2-SNAPSHOT
99
vintageGroup = org.junit.vintage
1010
vintageVersion = 5.10.2-SNAPSHOT
1111

12-
defaultBuiltBy = JUnit Team
13-
1412
# We need more metaspace due to apparent memory leak in Asciidoctor/JRuby
1513
# The exports are needed due to https://github.com/diffplug/spotless/issues/834
1614
org.gradle.jvmargs=-Xmx1g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError \

gradle/plugins/build-parameters/build.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,15 @@ buildParameters {
6868
description = "Sign artifacts before publishing them to Maven repos"
6969
}
7070
}
71+
group("manifest") {
72+
string("buildTimestamp") {
73+
description = "Overrides the value of the 'Build-Date' and 'Build-Time' jar manifest entries (e.g. '2023-11-05 17:49:13.996+0100')."
74+
}
75+
string("builtBy") {
76+
description = "Overrides the value of the 'Built-By' jar manifest entry"
77+
}
78+
string("createdBy") {
79+
description = "Overrides the value of the 'Created-By' jar manifest entry"
80+
}
81+
}
7182
}

gradle/plugins/common/src/main/kotlin/junitbuild.build-metadata.gradle.kts

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1-
import java.time.Instant
21
import java.time.OffsetDateTime
3-
import java.time.ZoneOffset
42
import java.time.format.DateTimeFormatter
3+
import java.time.format.DateTimeFormatterBuilder
54

6-
val buildTimeAndDate =
7-
if (System.getenv().containsKey("SOURCE_DATE_EPOCH")) {
8-
9-
// SOURCE_DATE_EPOCH is a UNIX timestamp for pinning build metadata against
10-
// in order to achieve reproducible builds
11-
//
12-
// More details - https://reproducible-builds.org/docs/source-date-epoch/
13-
val sourceDateEpoch = System.getenv("SOURCE_DATE_EPOCH").toLong()
5+
plugins {
6+
id("junitbuild.build-parameters")
7+
}
148

15-
Instant.ofEpochSecond(sourceDateEpoch).atOffset(ZoneOffset.UTC)
9+
val dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE
10+
val timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSSZ")
1611

17-
} else {
18-
OffsetDateTime.now()
12+
val buildTimeAndDate = buildParameters.manifest.buildTimestamp
13+
.map {
14+
DateTimeFormatterBuilder()
15+
.append(dateFormatter)
16+
.appendLiteral(' ')
17+
.append(timeFormatter)
18+
.toFormatter()
19+
.parse(it)
1920
}
21+
.orNull
22+
?: OffsetDateTime.now()
2023

21-
val buildDate: String by extra { DateTimeFormatter.ISO_LOCAL_DATE.format(buildTimeAndDate) }
22-
val buildTime: String by extra { DateTimeFormatter.ofPattern("HH:mm:ss.SSSZ").format(buildTimeAndDate) }
24+
val buildDate: String by extra { dateFormatter.format(buildTimeAndDate) }
25+
val buildTime: String by extra { timeFormatter.format(buildTimeAndDate) }
2326
val buildRevision: String by extra {
2427
providers.exec {
2528
commandLine("git", "rev-parse", "--verify", "HEAD")
2629
}.standardOutput.asText.get()
2730
}
28-
val builtByValue by extra { project.findProperty("builtBy") ?: project.property("defaultBuiltBy") }

gradle/plugins/common/src/main/kotlin/junitbuild.java-library-conventions.gradle.kts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ plugins {
99
idea
1010
checkstyle
1111
id("junitbuild.base-conventions")
12+
id("junitbuild.build-parameters")
1213
id("junitbuild.jacoco-java-conventions")
1314
}
1415

@@ -17,7 +18,6 @@ val modularProjects: List<Project> by rootProject.extra
1718
val buildDate: String by rootProject.extra
1819
val buildTime: String by rootProject.extra
1920
val buildRevision: Any by rootProject.extra
20-
val builtByValue: String by rootProject.extra
2121

2222
val extension = extensions.create<JavaLibraryExtension>("javaLibrary")
2323

@@ -203,8 +203,9 @@ tasks.withType<Jar>().configureEach {
203203
tasks.jar {
204204
manifest {
205205
attributes(
206-
"Created-By" to "${System.getProperty("java.version")} (${System.getProperty("java.vendor")} ${System.getProperty("java.vm.version")})",
207-
"Built-By" to builtByValue,
206+
"Created-By" to (buildParameters.manifest.createdBy.orNull
207+
?: "${System.getProperty("java.version")} (${System.getProperty("java.vendor")} ${System.getProperty("java.vm.version")})"),
208+
"Built-By" to buildParameters.manifest.builtBy.orElse("JUnit Team"),
208209
"Build-Date" to buildDate,
209210
"Build-Time" to buildTime,
210211
"Build-Revision" to buildRevision,

gradle/scripts/checkBuildReproducibility.sh

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,24 @@
22

33
rm -rf checksums*
44

5-
export SOURCE_DATE_EPOCH=$(date +%s)
5+
BUILD_TIMESTAMP=$(date -Iseconds)
66

77
function calculate_checksums() {
88
OUTPUT=$1
99

10-
./gradlew --no-build-cache clean assemble --parallel -Porg.gradle.java.installations.auto-download=false -Dscan.tag.Reproducibility
10+
./gradlew \
11+
--no-build-cache \
12+
-Porg.gradle.java.installations.auto-download=false \
13+
-Dscan.tag.Reproducibility \
14+
-Pmanifest.buildTimestamp="${BUILD_TIMESTAMP}" \
15+
clean \
16+
assemble
1117

1218
find . -name '*.jar' \
1319
| grep '/build/libs/' \
1420
| grep --invert-match 'javadoc' \
1521
| sort \
16-
| xargs sha256sum > ${OUTPUT}
22+
| xargs sha256sum > "${OUTPUT}"
1723
}
1824

1925

0 commit comments

Comments
 (0)