diff --git a/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java b/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java index fba0cd8cddb..cdb7539d94a 100644 --- a/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java +++ b/all/src/test/java/io/opentelemetry/all/NoSharedInternalCodeTest.java @@ -52,7 +52,8 @@ class NoSharedInternalCodeTest { "opentelemetry-exporter-otlp-common", "opentelemetry-exporter-sender-grpc-managed-channel", "opentelemetry-exporter-sender-jdk", - "opentelemetry-exporter-sender-okhttp"); + "opentelemetry-exporter-sender-okhttp", + "opentelemetry-exporter-sender-okhttp4"); private static final String OTEL_BASE_PACKAGE = "io.opentelemetry"; private static final Logger logger = Logger.getLogger(NoSharedInternalCodeTest.class.getName()); diff --git a/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts b/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts index 48ce7c56d70..5de32779d04 100644 --- a/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts @@ -81,15 +81,20 @@ fun getClasspathForVersion(version: String): List { group = "virtual_group" try { return getAllPublishedModules().map { - val depModule = "io.opentelemetry:${it.base.archivesName.get()}:$version@jar" - val depJar = "${it.base.archivesName.get()}-$version.jar" - val configuration: Configuration = configurations.detachedConfiguration( - dependencies.create(depModule), - ) - files(configuration.files).filter { file -> - file.name.equals(depJar) - }.singleFile - }.toList() + try { + val depModule = "io.opentelemetry:${it.base.archivesName.get()}:$version@jar" + val depJar = "${it.base.archivesName.get()}-$version.jar" + val configuration: Configuration = configurations.detachedConfiguration( + dependencies.create(depModule), + ) + files(configuration.files).filter { file -> + file.name.equals(depJar) + }.singleFile + } catch (e: Exception) { + println("Failed to fetch artifact for version ${it.base.archivesName.get()}:$version. If this artifact is has not yet been published, ignore.") + null + } + }.toList().filterNotNull() } finally { group = existingGroup } @@ -135,6 +140,9 @@ if (!project.hasProperty("otel.release") && !project.name.startsWith("bom")) { newArchives.from(newArchive) oldArchives.from(oldArchive) + // Skip comparison for modules that have never been published (no old archive available). + enabled = oldArchive != null + // Only generate API diff for changes. onlyModified.set(true) diff --git a/dependencyManagement/build.gradle.kts b/dependencyManagement/build.gradle.kts index 4416ec6a98b..885910f6ea8 100644 --- a/dependencyManagement/build.gradle.kts +++ b/dependencyManagement/build.gradle.kts @@ -8,6 +8,7 @@ val dependencyVersions = hashMapOf() rootProject.extra["versions"] = dependencyVersions +val okhttp5Version = "5.3.2" val autoValueVersion = "1.11.1" val errorProneVersion = "2.47.0" val jmhVersion = "1.37" @@ -18,7 +19,6 @@ val opencensusVersion = "0.31.1" val prometheusServerVersion = "1.3.10" val armeriaVersion = "1.36.0" val junitVersion = "5.14.3" -val okhttpVersion = "5.3.2" val DEPENDENCY_BOMS = listOf( // for some reason boms show up as runtime dependencies in license and vulnerability scans @@ -29,7 +29,6 @@ val DEPENDENCY_BOMS = listOf( "com.fasterxml.jackson:jackson-bom:2.21.0", "com.google.guava:guava-bom:33.5.0-jre", "com.google.protobuf:protobuf-bom:4.33.5", - "com.squareup.okhttp3:okhttp-bom:$okhttpVersion", "com.squareup.okio:okio-bom:3.16.4", // applies to transitive dependencies of okhttp "io.grpc:grpc-bom:1.79.0", "io.netty:netty-bom:4.2.10.Final", @@ -47,7 +46,6 @@ val DEPENDENCIES = listOf( "com.linecorp.armeria:armeria-grpc:${armeriaVersion}", "com.linecorp.armeria:armeria-grpc-protocol:${armeriaVersion}", "com.linecorp.armeria:armeria-junit5:${armeriaVersion}", - "com.google.auto.value:auto-value:${autoValueVersion}", "com.google.auto.value:auto-value-annotations:${autoValueVersion}", "com.google.errorprone:error_prone_annotations:${errorProneVersion}", @@ -73,7 +71,7 @@ val DEPENDENCIES = listOf( "com.google.code.findbugs:jsr305:3.0.2", "com.google.guava:guava-beta-checker:1.0", "com.sun.net.httpserver:http:20070405", - "com.squareup.okhttp3:okhttp:$okhttpVersion", + "com.squareup.okhttp3:okhttp:${okhttp5Version}", "com.tngtech.archunit:archunit-junit5:1.4.1", "com.uber.nullaway:nullaway:0.13.1", "edu.berkeley.cs.jqf:jqf-fuzz:1.7", // jqf-fuzz version 1.8+ requires Java 11+ diff --git a/exporters/otlp/all/build.gradle.kts b/exporters/otlp/all/build.gradle.kts index 78616d46933..3fcbd5f16fa 100644 --- a/exporters/otlp/all/build.gradle.kts +++ b/exporters/otlp/all/build.gradle.kts @@ -40,47 +40,64 @@ dependencies { val testJavaVersion: String? by project +// Source files for testOkHttp4 are generated from testOkhttp5 by replacing version-specific +// references. Do not edit files under src/testOkhttp4 directly - edit testOkhttp5 instead. +val generateTestOkhttp4Sources by tasks.registering(Sync::class) { + from("src/testOkhttp5/java") + into(layout.buildDirectory.dir("generated/sources/testOkhttp4/java")) + filter { line: String -> + line.replace("sender.okhttp.internal", "sender.okhttp4.internal") + } + includeEmptyDirs = false +} + testing { suites { - listOf( - "LATEST", - "4.11.0" - ).forEach { - register("testOkHttpVersion$it") { - sources { - java { - setSrcDirs(listOf("src/testDefaultSender/java")) - } - } - dependencies { - implementation(project(":exporters:sender:okhttp")) - implementation(project(":exporters:otlp:testing-internal")) - - implementation(platform("com.squareup.okhttp3:okhttp-bom")) { - // Only impose dependency constraint if not testing the LATEST version, which is defined in /dependencyManagement/build.gradle.kts - if (!it.equals("LATEST")) { - version { - strictly(it) - } - } - } + register("testOkhttp5") { + dependencies { + implementation(project(":exporters:sender:okhttp")) + implementation(project(":exporters:otlp:testing-internal")) - implementation("com.squareup.okhttp3:okhttp") - implementation("io.grpc:grpc-stub") + implementation("com.squareup.okhttp3:okhttp") + implementation("io.grpc:grpc-stub") + } + targets { + all { + testTask { + systemProperty("expectedOkHttpMajorVersion", "5") + } } + } + } + register("testOkhttp4") { + sources.java.srcDir(generateTestOkhttp4Sources) + dependencies { + implementation(project(":exporters:sender:okhttp4")) + implementation(project(":exporters:otlp:testing-internal")) - targets { - all { - testTask { - // Only enable test suite for non-LATEST in GitHub CI (CI=true) - enabled = it.equals("LATEST") || "true".equals(System.getenv("CI")) - systemProperty("expected.okhttp.version", it) - } + // okhttp v4 is pinned explicitly because dependencyManagement manages okhttp v5 as the + // project-wide default. strictly() is required to override the v5 BOM constraint. + // This version must be kept in sync with the version declared in + // exporters/sender/okhttp4/build.gradle.kts. + implementation("com.squareup.okhttp3:okhttp") { version { strictly("4.12.0") } } + implementation("io.grpc:grpc-stub") + } + targets { + all { + testTask { + systemProperty("expectedOkHttpMajorVersion", "4") + systemProperty( + "io.opentelemetry.sdk.common.export.GrpcSenderProvider", + "io.opentelemetry.exporter.sender.okhttp4.internal.OkHttpGrpcSenderProvider" + ) + systemProperty( + "io.opentelemetry.sdk.common.export.HttpSenderProvider", + "io.opentelemetry.exporter.sender.okhttp4.internal.OkHttpHttpSenderProvider" + ) } } } } - register("testGrpcNetty") { dependencies { implementation(project(":exporters:sender:grpc-managed-channel")) diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/OkHttpVersionTest.java b/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/OkHttpVersionTest.java deleted file mode 100644 index 8798781bb3f..00000000000 --- a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/OkHttpVersionTest.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.exporter.otlp; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assumptions.assumeThat; - -import java.util.logging.Level; -import java.util.logging.Logger; -import okhttp3.OkHttp; -import org.junit.jupiter.api.Test; - -class OkHttpVersionTest { - - private static final Logger LOGGER = Logger.getLogger(OkHttpVersionTest.class.getName()); - - @Test - void expectedOkHttpVersion() { - String expectedVersion = System.getProperty("expected.okhttp.version"); - LOGGER.log(Level.WARNING, "Testing okhttp version " + expectedVersion); - assumeThat(expectedVersion.equals("LATEST")).isFalse(); - assertThat(OkHttp.VERSION).isEqualTo(expectedVersion); - } -} diff --git a/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/OkHttpVersionTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/OkHttpVersionTest.java new file mode 100644 index 00000000000..041e184df7b --- /dev/null +++ b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/OkHttpVersionTest.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.otlp; + +import static org.assertj.core.api.Assertions.assertThat; + +import okhttp3.OkHttp; +import org.junit.jupiter.api.Test; + +class OkHttpVersionTest { + @Test + void expectedOkHttpVersion() { + String expectedMajorVersion = System.getProperty("expectedOkHttpMajorVersion"); + assertThat(OkHttp.VERSION) + .withFailMessage( + "Expected OkHttp major version %s but got %s", expectedMajorVersion, OkHttp.VERSION) + .startsWith(expectedMajorVersion); + } +} diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterOkHttpSenderTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterOkHttpSenderTest.java similarity index 100% rename from exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterOkHttpSenderTest.java rename to exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/http/logs/OtlpHttpLogRecordExporterOkHttpSenderTest.java diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterOkHttpSenderTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterOkHttpSenderTest.java similarity index 100% rename from exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterOkHttpSenderTest.java rename to exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/http/metrics/OtlpHttpMetricExporterOkHttpSenderTest.java diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterOkHttpSenderTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterOkHttpSenderTest.java similarity index 100% rename from exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterOkHttpSenderTest.java rename to exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/http/trace/OtlpHttpSpanExporterOkHttpSenderTest.java diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterTest.java similarity index 100% rename from exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterTest.java rename to exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/logs/OtlpGrpcLogRecordExporterTest.java diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java similarity index 100% rename from exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java rename to exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/metrics/OtlpGrpcMetricExporterTest.java diff --git a/exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/traces/OtlpGrpcSpanExporterTest.java b/exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/traces/OtlpGrpcSpanExporterTest.java similarity index 100% rename from exporters/otlp/all/src/testDefaultSender/java/io/opentelemetry/exporter/otlp/traces/OtlpGrpcSpanExporterTest.java rename to exporters/otlp/all/src/testOkhttp5/java/io/opentelemetry/exporter/otlp/traces/OtlpGrpcSpanExporterTest.java diff --git a/exporters/otlp/testing-internal/build.gradle.kts b/exporters/otlp/testing-internal/build.gradle.kts index 1d6bff53854..61ff4b17327 100644 --- a/exporters/otlp/testing-internal/build.gradle.kts +++ b/exporters/otlp/testing-internal/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { api("io.opentelemetry.proto:opentelemetry-proto") api("org.junit.jupiter:junit-jupiter-api") - implementation("com.squareup.okhttp3:okhttp") + implementation("com.squareup.okhttp3:okhttp:5.3.2") implementation("org.junit.jupiter:junit-jupiter-params") implementation("com.linecorp.armeria:armeria-grpc") diff --git a/exporters/sender/okhttp/build.gradle.kts b/exporters/sender/okhttp/build.gradle.kts index 107270e9ada..c2d3f939b51 100644 --- a/exporters/sender/okhttp/build.gradle.kts +++ b/exporters/sender/okhttp/build.gradle.kts @@ -5,9 +5,13 @@ plugins { id("otel.animalsniffer-conventions") } -description = "OpenTelemetry OkHttp Senders" +description = "OpenTelemetry OkHttp5 Senders" otelJava.moduleName.set("io.opentelemetry.exporter.sender.okhttp.internal") +tasks.named("test") { + systemProperty("expectedOkHttpMajorVersion", "5") +} + dependencies { implementation(project(":exporters:common")) implementation(project(":sdk:common")) diff --git a/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpVersionTest.java b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpVersionTest.java new file mode 100644 index 00000000000..47d711ec589 --- /dev/null +++ b/exporters/sender/okhttp/src/test/java/io/opentelemetry/exporter/sender/okhttp/internal/OkHttpVersionTest.java @@ -0,0 +1,21 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.exporter.sender.okhttp.internal; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import okhttp3.OkHttp; +import org.junit.jupiter.api.Test; + +class OkHttpVersionTest { + @Test + void expectedOkHttpVersion() { + String expectedMajorVersion = System.getProperty("expectedOkHttpMajorVersion"); + assertTrue( + OkHttp.VERSION.startsWith(expectedMajorVersion), + "Expected OkHttp major version " + expectedMajorVersion + " but got " + OkHttp.VERSION); + } +} diff --git a/exporters/sender/okhttp4/build.gradle.kts b/exporters/sender/okhttp4/build.gradle.kts new file mode 100644 index 00000000000..a28ff4b4e0b --- /dev/null +++ b/exporters/sender/okhttp4/build.gradle.kts @@ -0,0 +1,66 @@ +plugins { + id("otel.java-conventions") + id("otel.publish-conventions") + + id("otel.animalsniffer-conventions") +} + +description = "OpenTelemetry OkHttp4 Senders" +otelJava.moduleName.set("io.opentelemetry.exporter.sender.okhttp4.internal") + +// Source files are generated from the okhttp (v5) module by replacing the package name. +// Do not edit files under src/ directly - edit the okhttp module instead. +val okhttpDir = project(":exporters:sender:okhttp").projectDir + +val generateMainSources by tasks.registering(Sync::class) { + from(okhttpDir.resolve("src/main/java")) + into(layout.buildDirectory.dir("generated/sources/okhttp4/main/java")) + filter { line: String -> line.replace("sender.okhttp.internal", "sender.okhttp4.internal") } + eachFile { path = path.replace("sender/okhttp/internal", "sender/okhttp4/internal") } + includeEmptyDirs = false +} + +val generateTestSources by tasks.registering(Sync::class) { + from(okhttpDir.resolve("src/test/java")) + into(layout.buildDirectory.dir("generated/sources/okhttp4/test/java")) + filter { line: String -> line.replace("sender.okhttp.internal", "sender.okhttp4.internal") } + eachFile { path = path.replace("sender/okhttp/internal", "sender/okhttp4/internal") } + includeEmptyDirs = false +} + +val generateMainResources by tasks.registering(Sync::class) { + from(okhttpDir.resolve("src/main/resources")) + into(layout.buildDirectory.dir("generated/sources/okhttp4/main/resources")) + filter { line: String -> line.replace("sender.okhttp.internal", "sender.okhttp4.internal") } + includeEmptyDirs = false +} + +sourceSets { + main { + java.srcDir(generateMainSources) + resources.srcDir(generateMainResources) + } + test { + java.srcDir(generateTestSources) + } +} + +tasks.named("test") { + systemProperty("expectedOkHttpMajorVersion", "4") +} + +dependencies { + implementation(project(":exporters:common")) + implementation(project(":sdk:common")) + + // okhttp v4 is pinned explicitly because dependencyManagement manages okhttp v5 as the + // project-wide default. strictly() is required to override the v5 BOM constraint. + // This version must be kept in sync with the version declared in + // exporters/otlp/all/build.gradle.kts (testOkhttp4 suite). + implementation("com.squareup.okhttp3:okhttp") { version { strictly("4.12.0") } } + + compileOnly("io.grpc:grpc-stub") + compileOnly("com.fasterxml.jackson.core:jackson-core") + + testImplementation("com.linecorp.armeria:armeria-junit5") +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e6fc58fb3d1..08d59b9469b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -41,6 +41,7 @@ include(":exporters:common:compile-stub") include(":exporters:sender:grpc-managed-channel") include(":exporters:sender:jdk") include(":exporters:sender:okhttp") +include(":exporters:sender:okhttp4") include(":exporters:logging") include(":exporters:logging-otlp") include(":exporters:otlp:all")