This is an automated email from the ASF dual-hosted git repository.
lhotari pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar.git
The following commit(s) were added to refs/heads/master by this push:
new fccb3e475c2 [improve][build] Keep release build info stable with a
snapshot file (#26014)
fccb3e475c2 is described below
commit fccb3e475c2b7632eb26bbad9ac3bccaf329396f
Author: Lari Hotari <[email protected]>
AuthorDate: Sat Jun 13 08:16:48 2026 +0300
[improve][build] Keep release build info stable with a snapshot file
(#26014)
---
gradle.properties | 12 ++--
pulsar-common/build.gradle.kts | 80 ++++++++++++++++------
.../main/java/org/apache/pulsar/PulsarVersion.java | 2 +-
3 files changed, 69 insertions(+), 25 deletions(-)
diff --git a/gradle.properties b/gradle.properties
index d370ce90209..4ddf1bce2bc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -37,7 +37,11 @@
systemProp.org.gradle.internal.publish.checksums.insecure=true
# default `false` in CI is important because changing the metadata would
invalidate
# the build cache entries that downstream jobs reuse.
#
-# Release builds must include the real metadata — pass
`-Ppulsar.includeBuildInfo=true`
-# on the gradle command line, or set `pulsar.includeBuildInfo=true` in
-# `~/.gradle/gradle.properties` before running the release build.
-pulsar.includeBuildInfo=false
+# Release builds must include the real metadata — pass
`-PpulsarIncludeBuildInfo=true`
+# on the gradle command line, or export the
`ORG_GRADLE_PROJECT_pulsarIncludeBuildInfo=true`
+# environment variable before running the release build. To keep the captured
metadata
+# identical across the separate Gradle invocations of a release, also point the
+# `pulsarBuildInfoFile` property (e.g. via
`ORG_GRADLE_PROJECT_pulsarBuildInfoFile`) at a
+# snapshot file outside the working tree: the metadata is captured into the
file on the
+# first invocation and reused from it afterwards.
+pulsarIncludeBuildInfo=false
diff --git a/pulsar-common/build.gradle.kts b/pulsar-common/build.gradle.kts
index b3aa7c1bf2d..6e192df5a64 100644
--- a/pulsar-common/build.gradle.kts
+++ b/pulsar-common/build.gradle.kts
@@ -32,17 +32,29 @@ plugins {
// git metadata only invalidate this module's processResources / jar tasks and
do NOT trigger
// a recompile of pulsar-common or any downstream module's compileJava.
//
-// Set `pulsar.includeBuildInfo=false` (e.g. in `~/.gradle/gradle.properties`)
to skip generation
-// entirely during development. PulsarVersion then returns placeholder values
at runtime.
-val includeBuildInfo = providers.gradleProperty("pulsar.includeBuildInfo")
+// `pulsarIncludeBuildInfo` (default `false` in the root gradle.properties)
controls whether the
+// git/build metadata is captured at all. Release builds enable it with
+// `-PpulsarIncludeBuildInfo=true` or the
`ORG_GRADLE_PROJECT_pulsarIncludeBuildInfo=true`
+// environment variable. When disabled, PulsarVersion returns placeholder
values at runtime.
+val includeBuildInfo = providers.gradleProperty("pulsarIncludeBuildInfo")
.map { it.toBoolean() }
.orElse(true)
+// `pulsarBuildInfoFile` (optional) points to a snapshot file that keeps the
captured build
+// metadata identical across separate Gradle invocations (the release process
runs several).
+// If the file exists, its entries are used as-is; otherwise the metadata is
captured and
+// written to the file so that subsequent invocations reuse it. Without the
snapshot, values
+// such as `git.build.time` change on every capture and invalidate the build
outputs.
+// A relative path is resolved against the root project directory.
+val buildInfoFile = providers.gradleProperty("pulsarBuildInfoFile")
+ .map { rootDir.resolve(it) }
+
val generatePulsarBuildInfo by tasks.registering {
description = "Generates pulsar-version.properties with version and
(optionally) git/build metadata."
val outputFile =
layout.buildDirectory.file("generated-resources/buildinfo/org/apache/pulsar/pulsar-version.properties")
val projectVersion = project.version.toString()
val includeBuildInfoValue = includeBuildInfo
+ val buildInfoFileValue = buildInfoFile.orNull
// Lazy providers — evaluated at execution time only (no impact on
configuration cache).
val gitCommitId = providers.exec {
@@ -68,33 +80,61 @@ val generatePulsarBuildInfo by tasks.registering {
inputs.property("version", projectVersion)
inputs.property("includeBuildInfo", includeBuildInfoValue)
+ // The snapshot file contents take part in up-to-date checking so that
pointing
+ // `pulsarBuildInfoFile` at a different snapshot regenerates the resource.
+ inputs.property("buildInfoFileContents",
providers.fileContents(layout.file(buildInfoFile)).asText.orElse(""))
outputs.file(outputFile)
doLast {
- val entries = linkedMapOf<String, String>()
- entries["version"] = projectVersion
- if (includeBuildInfoValue.get()) {
- entries["git.commit.id"] = gitCommitId.getOrElse("")
- entries["git.dirty"] = gitDirty.getOrElse("true")
- entries["git.branch"] = gitBranch.getOrElse("")
- entries["git.build.user.email"] = gitUserEmail.getOrElse("")
- entries["git.build.user.name"] = gitUserName.getOrElse("")
- entries["git.build.host"] = InetAddress.getLocalHost().hostName
- entries["git.build.time"] =
-
ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"))
- }
-
- val outFile = outputFile.get().asFile
- outFile.parentFile.mkdirs()
// Hand-rolled .properties writer so we don't get the
non-deterministic timestamp comment
// that java.util.Properties.store always emits. Values from
git/InetAddress are ASCII
// identifiers, so backslash escaping is sufficient.
- outFile.writeText(buildString {
+ fun formatProperties(entries: Map<String, String>) = buildString {
append("# Pulsar build info\n")
entries.forEach { (key, value) ->
append(key).append('=').append(value.replace("\\",
"\\\\")).append('\n')
}
- })
+ }
+
+ val entries = linkedMapOf<String, String>()
+ entries["version"] = projectVersion
+ if (includeBuildInfoValue.get()) {
+ val buildInfoEntries = linkedMapOf<String, String>()
+ if (buildInfoFileValue != null && buildInfoFileValue.exists()) {
+ // Reuse the previously captured snapshot so that the metadata
stays identical
+ // across the multiple Gradle invocations of a release build.
+ buildInfoFileValue.readLines()
+ .filter { it.isNotBlank() && !it.startsWith("#") }
+ .forEach { line ->
+ val separator = line.indexOf('=')
+ if (separator > 0) {
+ val key = line.substring(0, separator)
+ // the version always comes from the project,
never from the snapshot
+ if (key != "version") {
+ buildInfoEntries[key] =
line.substring(separator + 1).replace("\\\\", "\\")
+ }
+ }
+ }
+ } else {
+ buildInfoEntries["git.commit.id"] = gitCommitId.getOrElse("")
+ buildInfoEntries["git.dirty"] = gitDirty.getOrElse("true")
+ buildInfoEntries["git.branch"] = gitBranch.getOrElse("")
+ buildInfoEntries["git.build.user.email"] =
gitUserEmail.getOrElse("")
+ buildInfoEntries["git.build.user.name"] =
gitUserName.getOrElse("")
+ buildInfoEntries["git.build.host"] =
InetAddress.getLocalHost().hostName
+ buildInfoEntries["git.build.time"] =
+
ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"))
+ if (buildInfoFileValue != null) {
+ buildInfoFileValue.parentFile?.mkdirs()
+
buildInfoFileValue.writeText(formatProperties(buildInfoEntries))
+ }
+ }
+ entries += buildInfoEntries
+ }
+
+ val outFile = outputFile.get().asFile
+ outFile.parentFile.mkdirs()
+ outFile.writeText(formatProperties(entries))
}
}
diff --git a/pulsar-common/src/main/java/org/apache/pulsar/PulsarVersion.java
b/pulsar-common/src/main/java/org/apache/pulsar/PulsarVersion.java
index ea144cdf359..ae9a0281af7 100644
--- a/pulsar-common/src/main/java/org/apache/pulsar/PulsarVersion.java
+++ b/pulsar-common/src/main/java/org/apache/pulsar/PulsarVersion.java
@@ -29,7 +29,7 @@ import java.util.regex.Pattern;
*
* <p>Values are loaded from {@code
/org/apache/pulsar/pulsar-version.properties}, a resource
* generated by the build only when the build info is included (controlled by
the
- * {@code pulsar.includeBuildInfo} Gradle property). During development the
resource is typically
+ * {@code pulsarIncludeBuildInfo} Gradle property). During development the
resource is typically
* absent, in which case this class returns {@link #UNKNOWN} placeholders.
*/
public class PulsarVersion {