You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by lh...@apache.org on 2026/08/14 13:12:16 UTC

(pulsar) branch master updated: [improve][build] Upgrade Shadow plugin to 9.6.1 and merge service descriptor files in shaded jars (#26333)

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 b0a260471fb2 [improve][build] Upgrade Shadow plugin to 9.6.1 and merge service descriptor files in shaded jars (#26333)
b0a260471fb2 is described below

commit b0a260471fb23ea9e7d0a7ab38aa26f621d94aea
Author: Lari Hotari <lh...@users.noreply.github.com>
AuthorDate: Fri Aug 14 16:12:11 2026 +0300

    [improve][build] Upgrade Shadow plugin to 9.6.1 and merge service descriptor files in shaded jars (#26333)
---
 build-logic/conventions/build.gradle.kts                |  3 +++
 .../main/kotlin/pulsar.shadow-conventions.gradle.kts    | 17 +++++++++++++++++
 gradle/libs.versions.toml                               |  2 +-
 microbench/build.gradle.kts                             |  7 +++++++
 pulsar-functions/runtime-all/build.gradle.kts           |  7 +++++++
 5 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/build-logic/conventions/build.gradle.kts b/build-logic/conventions/build.gradle.kts
index bc3d07a2be5d..46120a3102ed 100644
--- a/build-logic/conventions/build.gradle.kts
+++ b/build-logic/conventions/build.gradle.kts
@@ -22,6 +22,9 @@ plugins {
 }
 
 dependencies {
+    // The Shadow plugin brings its own log4j-core onto the build classpath; align it with the
+    // log4j version the rest of the build uses (`log4j2` in the version catalog).
+    implementation(platform(libs.log4j.bom))
     implementation(libs.plugins.shadow.get().let {
         "${it.pluginId}:${it.pluginId}.gradle.plugin:${it.version}"
     })
diff --git a/build-logic/conventions/src/main/kotlin/pulsar.shadow-conventions.gradle.kts b/build-logic/conventions/src/main/kotlin/pulsar.shadow-conventions.gradle.kts
index 7a760e58e818..9864c439d630 100644
--- a/build-logic/conventions/src/main/kotlin/pulsar.shadow-conventions.gradle.kts
+++ b/build-logic/conventions/src/main/kotlin/pulsar.shadow-conventions.gradle.kts
@@ -32,7 +32,24 @@ shadow {
 
 tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
     archiveClassifier.set("")
+    // ShadowJar's duplicatesStrategy is applied *before* the resource transformers run, so its
+    // EXCLUDE default drops every duplicate META-INF/services file and mergeServiceFiles() ends up
+    // keeping only the first provider file instead of merging them all. Keep EXCLUDE as the global
+    // strategy — class files bypass the transformers entirely (ShadowCopyAction handles them in a
+    // dedicated branch), so the strategy is the only thing deduplicating them — and let just the
+    // service descriptors through to the transformer.
     mergeServiceFiles()
+    // Paths owned by a resource transformer: ServiceFileTransformer (mergeServiceFiles) and the
+    // KotlinModuleMetadataTransformer that ShadowJar applies on its own.
+    val transformedPaths = listOf("META-INF/services/**", "META-INF/*.kotlin_module")
+    filesMatching(transformedPaths) {
+        duplicatesStrategy = DuplicatesStrategy.INCLUDE
+    }
+    // filesMatching {} actions are not part of the task's input fingerprint, so without this the
+    // build cache serves jars built under the old behaviour even after this block changes.
+    inputs.property("transformedPathsDuplicatesStrategy", "$transformedPaths=INCLUDE")
+    // Nothing should reach the archive twice; catch it if a future change makes it happen.
+    failOnDuplicateEntries.set(true)
 }
 
 tasks.named<Jar>("jar") {
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 9453c4459ace..9283cb3b6d97 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -177,7 +177,7 @@ thrift = "0.23.0"
 datasketches-memory = "4.1.0"
 datasketches-java = "7.0.1"
 # Shading
-shadow = "9.4.2"
+shadow = "9.6.1"
 
 [libraries]
 # SLF4J
diff --git a/microbench/build.gradle.kts b/microbench/build.gradle.kts
index 216486255c48..ab3a83b3b480 100644
--- a/microbench/build.gradle.kts
+++ b/microbench/build.gradle.kts
@@ -44,6 +44,13 @@ tasks.shadowJar {
     archiveClassifier.set("benchmarks")
     isZip64 = true
     mergeServiceFiles()
+    // See pulsar.shadow-conventions: the default EXCLUDE strategy drops duplicates of
+    // transformer-owned paths before the transformers can merge them.
+    val transformedPaths = listOf("META-INF/services/**", "META-INF/*.kotlin_module")
+    filesMatching(transformedPaths) {
+        duplicatesStrategy = DuplicatesStrategy.INCLUDE
+    }
+    inputs.property("transformedPathsDuplicatesStrategy", "$transformedPaths=INCLUDE")
     exclude("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA")
     manifest {
         attributes("Main-Class" to "org.openjdk.jmh.Main")
diff --git a/pulsar-functions/runtime-all/build.gradle.kts b/pulsar-functions/runtime-all/build.gradle.kts
index 0f7d3ccc368d..5967f1efbae6 100644
--- a/pulsar-functions/runtime-all/build.gradle.kts
+++ b/pulsar-functions/runtime-all/build.gradle.kts
@@ -44,6 +44,13 @@ dependencies {
 tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
     archiveFileName.set("java-instance.jar")
     mergeServiceFiles()
+    // See pulsar.shadow-conventions: the default EXCLUDE strategy drops duplicates of
+    // transformer-owned paths before the transformers can merge them.
+    val transformedPaths = listOf("META-INF/services/**", "META-INF/*.kotlin_module")
+    filesMatching(transformedPaths) {
+        duplicatesStrategy = DuplicatesStrategy.INCLUDE
+    }
+    inputs.property("transformedPathsDuplicatesStrategy", "$transformedPaths=INCLUDE")
     exclude("META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA")
 }