Skip to content

Commit 6a07130

Browse files
committed
Add native OSGi bundle metadata to published jars
Wire the bnd Gradle plugin into the shared otel.java-conventions plugin so the semconv and semconv-incubating jars are published with OSGi manifest headers (Bundle-SymbolicName, Export-Package, Import-Package). This lets the artifacts be consumed directly in OSGi containers without external re-wrapping. Fixes #494
1 parent 627e0cb commit 6a07130

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

buildSrc/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ repositories {
99
}
1010

1111
dependencies {
12+
implementation("biz.aQute.bnd:biz.aQute.bnd.gradle:7.3.0")
1213
implementation("com.diffplug.spotless:spotless-plugin-gradle:8.8.0")
1314
implementation("ru.vyarus:gradle-animalsniffer-plugin:2.0.1")
1415
implementation("me.champeau.gradle:japicmp-gradle-plugin:0.4.6")

buildSrc/src/main/kotlin/io/opentelemetry/gradle/OtelJavaExtension.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55

66
package io.opentelemetry.gradle
77

8+
import org.gradle.api.provider.ListProperty
89
import org.gradle.api.provider.Property
910

1011
abstract class OtelJavaExtension {
1112
abstract val moduleName: Property<String>
13+
14+
/** Whether to generate OSGi bundle metadata. Enabled by default. */
15+
abstract val osgiEnabled: Property<Boolean>
16+
17+
/** Extra packages imported as optional (resolution:=optional), e.g. compileOnly deps. */
18+
abstract val osgiOptionalPackages: ListProperty<String>
1219
}

buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ plugins {
88
eclipse
99
idea
1010

11+
id("biz.aQute.bnd.builder")
1112
id("otel.spotless-conventions")
1213
}
1314

1415
val otelJava = extensions.create<OtelJavaExtension>("otelJava")
16+
otelJava.osgiEnabled.convention(true)
17+
otelJava.osgiOptionalPackages.convention(emptyList())
1518

1619
java {
1720
toolchain {
@@ -29,6 +32,13 @@ checkstyle {
2932
configProperties["rootDir"] = rootDir
3033
}
3134

35+
// normalize timestamps and file ordering in jars, making the outputs (including OSGi
36+
// manifests) reproducible. see open-telemetry/opentelemetry-java#4488
37+
tasks.withType<AbstractArchiveTask>().configureEach {
38+
isPreserveFileTimestamps = false
39+
isReproducibleFileOrder = true
40+
}
41+
3242
val testJavaVersion = gradle.startParameter.projectProperties.get("testJavaVersion")?.let(JavaVersion::toVersion)
3343

3444
tasks {
@@ -85,6 +95,30 @@ tasks {
8595
}
8696
}
8797

98+
afterEvaluate {
99+
if (otelJava.osgiEnabled.get()) {
100+
named<Jar>("jar") {
101+
// Configure OSGi metadata. semconv has no SPI / ServiceLoader needs, so this is the
102+
// trimmed form of opentelemetry-java's otel.java-conventions OSGi config.
103+
bundle {
104+
// Modules may declare optional imports (typically compileOnly deps). The trailing
105+
// "*" lets BND auto-import everything else (e.g. io.opentelemetry.api.*).
106+
val optionalPackages = otelJava.osgiOptionalPackages.get()
107+
val optionalImports =
108+
optionalPackages.joinToString(",") { "$it.*;resolution:=optional;version=\"\${@}\"" }
109+
val importPackages = if (optionalImports.isEmpty()) "*" else "$optionalImports,*"
110+
111+
bnd(
112+
mapOf(
113+
"-exportcontents" to "io.opentelemetry.*",
114+
"Import-Package" to importPackages,
115+
),
116+
)
117+
}
118+
}
119+
}
120+
}
121+
88122
withType<Jar>().configureEach {
89123
inputs.property("moduleName", otelJava.moduleName)
90124

0 commit comments

Comments
 (0)