From a412b906ff2dad359f6e4567a2fe359334fe2e62 Mon Sep 17 00:00:00 2001 From: Apoorv Mittal Date: Thu, 4 Apr 2024 10:56:08 +0100 Subject: [PATCH] KAFKA-16359: Corrected manifest file for kafka-clients (#15532) The issue KAFKA-16359 reported inclusion of kafka-clients runtime dependencies in MANIFEST.MF Class-Path. The root cause is the issue defined here with the usage of shadow plugin. Looking into the specifics of plugin and documentation, specifies that any dependency marked as shadow will be treated as following by the shadow plugin: 1. Adds the dependency as runtime dependency in resultant pom.xml - code here 2. Adds the dependency as Class-Path in MANIFEST.MF as well - code here Resolution We do need the runtime dependencies available in the pom (1 above) but not on manifest (2 above). Also there is no clear way to separate the behaviour as both above tasks relies on shadow configuration. To fix, I have defined another custom configuration named shadowed which is later used to populate the correct pom (the code is similar to what shadow plugin does to populate pom for runtime dependencies). Though this might seem like a workaround, but I think that's the only way to fix the issue. I have checked other SDKs which suffered with same issue and went with similar route to populate pom. Reviewers: Luke Chen , Reviewers: Mickael Maison , Gaurav Narula --- build.gradle | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index e7e5253afbdb..15b60301e5da 100644 --- a/build.gradle +++ b/build.gradle @@ -305,6 +305,24 @@ subprojects { } else { apply plugin: 'com.github.johnrengelman.shadow' project.shadow.component(mavenJava) + + // Fix for avoiding inclusion of runtime dependencies marked as 'shadow' in MANIFEST Class-Path. + // https://github.com/johnrengelman/shadow/issues/324 + afterEvaluate { + pom.withXml { xml -> + if (xml.asNode().get('dependencies') == null) { + xml.asNode().appendNode('dependencies') + } + def dependenciesNode = xml.asNode().get('dependencies').get(0) + project.configurations.shadowed.allDependencies.each { + def dependencyNode = dependenciesNode.appendNode('dependency') + dependencyNode.appendNode('groupId', it.group) + dependencyNode.appendNode('artifactId', it.name) + dependencyNode.appendNode('version', it.version) + dependencyNode.appendNode('scope', 'runtime') + } + } + } } afterEvaluate { @@ -1399,6 +1417,7 @@ project(':clients') { configurations { generator + shadowed } dependencies { @@ -1409,10 +1428,10 @@ project(':clients') { implementation libs.opentelemetryProto // libraries which should be added as runtime dependencies in generated pom.xml should be defined here: - shadow libs.zstd - shadow libs.lz4 - shadow libs.snappy - shadow libs.slf4jApi + shadowed libs.zstd + shadowed libs.lz4 + shadowed libs.snappy + shadowed libs.slf4jApi compileOnly libs.jacksonDatabind // for SASL/OAUTHBEARER bearer token parsing compileOnly libs.jacksonJDK8Datatypes @@ -1465,10 +1484,9 @@ project(':clients') { // dependencies excluded from the final jar, since they are declared as runtime dependencies dependencies { - exclude(dependency(libs.snappy)) - exclude(dependency(libs.zstd)) - exclude(dependency(libs.lz4)) - exclude(dependency(libs.slf4jApi)) + project.configurations.shadowed.allDependencies.each { + exclude(dependency(it.group + ':' + it.name + ':' + it.version)) + } // exclude proto files from the jar exclude "**/opentelemetry/proto/**/*.proto" exclude "**/google/protobuf/*.proto"