diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c09bad4e..0d58b3065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixes +- Auto install and instrument sentry-okhttp instead of sentry-android-okhttp on v7+ ([#724](https://github.com/getsentry/sentry-android-gradle-plugin/pull/724)) - Fix source bundles with configuration cache on AGP 8+ ([#725](https://github.com/getsentry/sentry-android-gradle-plugin/pull/725)) ## 4.8.0 diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 3cfeaa667..c4da4f569 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -29,7 +29,7 @@ object LibsVersion { const val JUNIT = "4.13.2" const val ASM = "9.4" // compatibility matrix -> https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/instrumentation/InstrumentationContext#apiversion const val SQLITE = "2.1.0" - const val SENTRY = "6.31.0" + const val SENTRY = "7.0.0" } object Libs { @@ -50,6 +50,7 @@ object Libs { const val SENTRY = "io.sentry:sentry:${LibsVersion.SENTRY}" const val SENTRY_ANDROID = "io.sentry:sentry-android:${LibsVersion.SENTRY}" const val SENTRY_ANDROID_OKHTTP = "io.sentry:sentry-android-okhttp:${LibsVersion.SENTRY}" + const val SENTRY_OKHTTP = "io.sentry:sentry-okhttp:${LibsVersion.SENTRY}" // test val MOCKITO_KOTLIN = "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" diff --git a/plugin-build/build.gradle.kts b/plugin-build/build.gradle.kts index 5f9b50b5c..978bffd80 100644 --- a/plugin-build/build.gradle.kts +++ b/plugin-build/build.gradle.kts @@ -96,6 +96,7 @@ dependencies { testRuntimeOnly(files(androidSdkPath)) testImplementation(Libs.SENTRY_ANDROID) testImplementationAar(Libs.SENTRY_ANDROID_OKHTTP) + testImplementationAar(Libs.SENTRY_OKHTTP) // Needed to read contents from APK/Source Bundles testImplementation(Libs.ARSC_LIB) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AbstractInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AbstractInstallStrategy.kt index 99fb8fcee..2fa31ea96 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AbstractInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AbstractInstallStrategy.kt @@ -1,6 +1,7 @@ package io.sentry.android.gradle.autoinstall import io.sentry.android.gradle.util.SemVer +import io.sentry.android.gradle.util.debug import io.sentry.android.gradle.util.info import io.sentry.android.gradle.util.warn import org.gradle.api.artifacts.ComponentMetadataContext @@ -19,6 +20,8 @@ abstract class AbstractInstallStrategy : ComponentMetadataRule { protected open val minSupportedSentryVersion: SemVer = SemVer(0, 0, 0) + protected open val maxSupportedSentryVersion: SemVer = SemVer(0, 0, 0) + override fun execute(context: ComponentMetadataContext) { val autoInstallState = AutoInstallState.getInstance() if (!autoInstallState.enabled) { @@ -55,9 +58,30 @@ abstract class AbstractInstallStrategy : ComponentMetadataRule { val sentrySemVersion = SemVer.parse(autoInstallState.sentryVersion) if (sentrySemVersion < minSupportedSentryVersion) { logger.warn { - "$sentryModuleId won't be installed because the current version is " + - "lower than the minimum supported sentry version " + - "($autoInstallState.sentryVersion)" + "$sentryModuleId won't be installed because the current sentry version " + + "is lower than the minimum supported sentry version " + + "($minSupportedSentryVersion)" + } + return + } + } catch (ex: IllegalArgumentException) { + logger.warn { + "$sentryModuleId won't be installed because the provided " + + "sentry version(${autoInstallState.sentryVersion}) could not be " + + "processed as a semantic version." + } + return + } + } + + if (maxSupportedSentryVersion.major > 0) { + try { + val sentrySemVersion = SemVer.parse(autoInstallState.sentryVersion) + if (sentrySemVersion > maxSupportedSentryVersion) { + logger.debug { + "$sentryModuleId won't be installed because the current sentry version " + + "is higher than the maximum supported sentry version " + + "($maxSupportedSentryVersion)" } return } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstall.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstall.kt index cbc35cc15..04d701a26 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstall.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstall.kt @@ -7,6 +7,7 @@ import io.sentry.android.gradle.autoinstall.jdbc.JdbcInstallStrategy import io.sentry.android.gradle.autoinstall.kotlin.KotlinExtensionsInstallStrategy import io.sentry.android.gradle.autoinstall.log4j2.Log4j2InstallStrategy import io.sentry.android.gradle.autoinstall.logback.LogbackInstallStrategy +import io.sentry.android.gradle.autoinstall.okhttp.AndroidOkHttpInstallStrategy import io.sentry.android.gradle.autoinstall.okhttp.OkHttpInstallStrategy import io.sentry.android.gradle.autoinstall.override.WarnOnOverrideStrategy import io.sentry.android.gradle.autoinstall.quartz.QuartzInstallStrategy @@ -25,6 +26,7 @@ import org.gradle.api.artifacts.DependencySet internal const val SENTRY_GROUP = "io.sentry" private val strategies = listOf( + AndroidOkHttpInstallStrategy.Registrar, OkHttpInstallStrategy.Registrar, SQLiteInstallStrategy.Registrar, TimberInstallStrategy.Registrar, diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/AndroidOkHttpInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/AndroidOkHttpInstallStrategy.kt new file mode 100644 index 000000000..d85b63496 --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/AndroidOkHttpInstallStrategy.kt @@ -0,0 +1,43 @@ +package io.sentry.android.gradle.autoinstall.okhttp + +import io.sentry.android.gradle.SentryPlugin +import io.sentry.android.gradle.autoinstall.AbstractInstallStrategy +import io.sentry.android.gradle.autoinstall.InstallStrategyRegistrar +import io.sentry.android.gradle.util.SemVer +import javax.inject.Inject +import org.gradle.api.artifacts.dsl.ComponentMetadataHandler +import org.slf4j.Logger + +abstract class AndroidOkHttpInstallStrategy : AbstractInstallStrategy { + + constructor(logger: Logger) : super() { + this.logger = logger + } + + @Suppress("unused") // used by Gradle + @Inject // inject is needed to avoid Gradle error + constructor() : this(SentryPlugin.logger) + + override val sentryModuleId: String get() = SENTRY_ANDROID_OKHTTP_ID + + override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION + + override val minSupportedSentryVersion: SemVer get() = SemVer(4, 4, 0) + + override val maxSupportedSentryVersion: SemVer get() = SemVer(6, 9999, 9999) + + companion object Registrar : InstallStrategyRegistrar { + private const val OKHTTP_GROUP = "com.squareup.okhttp3" + private const val OKHTTP_ID = "okhttp" + internal const val SENTRY_ANDROID_OKHTTP_ID = "sentry-android-okhttp" + + private val MIN_SUPPORTED_VERSION = SemVer(3, 13, 0) + + override fun register(component: ComponentMetadataHandler) { + component.withModule( + "$OKHTTP_GROUP:$OKHTTP_ID", + AndroidOkHttpInstallStrategy::class.java + ) {} + } + } +} diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategy.kt index ba66bd80f..f0fdd2353 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategy.kt @@ -23,12 +23,12 @@ abstract class OkHttpInstallStrategy : AbstractInstallStrategy { override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION - override val minSupportedSentryVersion: SemVer get() = SemVer(4, 4, 0) + override val minSupportedSentryVersion: SemVer get() = SemVer(7, 0, 0) companion object Registrar : InstallStrategyRegistrar { private const val OKHTTP_GROUP = "com.squareup.okhttp3" private const val OKHTTP_ID = "okhttp" - internal const val SENTRY_OKHTTP_ID = "sentry-android-okhttp" + internal const val SENTRY_OKHTTP_ID = "sentry-okhttp" private val MIN_SUPPORTED_VERSION = SemVer(3, 13, 0) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt index 7ed0fa1a6..dac8f11f5 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt @@ -67,6 +67,7 @@ abstract class WarnOnOverrideStrategy : ComponentMetadataRule { SentryModules.SENTRY_ANDROID_FRAGMENT, SentryModules.SENTRY_ANDROID_NAVIGATION, SentryModules.SENTRY_ANDROID_TIMBER, + SentryModules.SENTRY_OKHTTP, SentryModules.SENTRY_KOTLIN_EXTENSIONS, SentryModules.SENTRY_GRAPHQL, SentryModules.SENTRY_JDBC, diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt index bd6879e05..3734eb8be 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/SpanAddingClassVisitorFactory.kt @@ -23,6 +23,8 @@ import io.sentry.android.gradle.instrumentation.util.isMinifiedClass import io.sentry.android.gradle.instrumentation.wrap.WrappingInstrumentable import io.sentry.android.gradle.services.SentryModulesService import io.sentry.android.gradle.util.SemVer +import io.sentry.android.gradle.util.SentryModules +import io.sentry.android.gradle.util.SentryVersions import io.sentry.android.gradle.util.info import java.io.File import org.gradle.api.internal.artifacts.DefaultModuleIdentifier @@ -85,6 +87,11 @@ abstract class SpanAddingClassVisitorFactory : "okhttp" ) val okHttpVersion = externalModules.getOrDefault(okHttpModule, SemVer()) + val sentryOkhttpVersion = sentryModules.getOrDefault( + SentryModules.SENTRY_OKHTTP, + SemVer() + ) + val useSentryAndroidOkHttp = sentryOkhttpVersion < SentryVersions.VERSION_OKHTTP SentryPlugin.logger.info { "Read sentry modules: $sentryModules" } @@ -104,10 +111,10 @@ abstract class SpanAddingClassVisitorFactory : sentryModulesService.isNewDatabaseInstrEnabled() || sentryModulesService.isOldDatabaseInstrEnabled() }, - OkHttpEventListener(okHttpVersion).takeIf { + OkHttpEventListener(useSentryAndroidOkHttp, okHttpVersion).takeIf { sentryModulesService.isOkHttpListenerInstrEnabled() }, - OkHttp().takeIf { + OkHttp(useSentryAndroidOkHttp).takeIf { sentryModulesService.isOkHttpInstrEnabled() }, WrappingInstrumentable().takeIf { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttp.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttp.kt index 825c03c36..67421186c 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttp.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttp.kt @@ -10,7 +10,7 @@ import io.sentry.android.gradle.instrumentation.okhttp.visitor.ResponseWithInter import org.objectweb.asm.ClassVisitor import org.objectweb.asm.MethodVisitor -class OkHttp : ClassInstrumentable { +class OkHttp(private val useSentryAndroidOkHttp: Boolean) : ClassInstrumentable { override val fqName: String get() = "RealCall" override fun getVisitor( @@ -22,7 +22,7 @@ class OkHttp : ClassInstrumentable { apiVersion = apiVersion, classVisitor = originalVisitor, className = fqName.substringAfterLast('.'), - methodInstrumentables = listOf(ResponseWithInterceptorChain()), + methodInstrumentables = listOf(ResponseWithInterceptorChain(useSentryAndroidOkHttp)), parameters = parameters ) @@ -33,7 +33,9 @@ class OkHttp : ClassInstrumentable { data.currentClassData.className == "okhttp3.RealCall" } -class ResponseWithInterceptorChain : MethodInstrumentable { +class ResponseWithInterceptorChain( + private val useSentryAndroidOkHttp: Boolean +) : MethodInstrumentable { override val fqName: String get() = "getResponseWithInterceptorChain" override fun getVisitor( @@ -46,7 +48,8 @@ class ResponseWithInterceptorChain : MethodInstrumentable { originalVisitor = originalVisitor, access = instrumentableContext.access, name = instrumentableContext.name, - descriptor = instrumentableContext.descriptor + descriptor = instrumentableContext.descriptor, + useSentryAndroidOkHttp = useSentryAndroidOkHttp ) override fun isInstrumentable(data: MethodContext): Boolean { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttpEventListener.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttpEventListener.kt index 8abd33943..98acd1243 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttpEventListener.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/OkHttpEventListener.kt @@ -11,7 +11,10 @@ import io.sentry.android.gradle.util.SemVer import org.objectweb.asm.ClassVisitor import org.objectweb.asm.MethodVisitor -class OkHttpEventListener(private val okHttpVersion: SemVer) : ClassInstrumentable { +class OkHttpEventListener( + private val useSentryAndroidOkHttp: Boolean, + private val okHttpVersion: SemVer +) : ClassInstrumentable { override val fqName: String get() = "okhttp3.OkHttpClient" override fun getVisitor( @@ -23,12 +26,18 @@ class OkHttpEventListener(private val okHttpVersion: SemVer) : ClassInstrumentab apiVersion = apiVersion, classVisitor = originalVisitor, className = fqName.substringAfterLast('.'), - methodInstrumentables = listOf(OkHttpEventListenerMethodInstrumentable(okHttpVersion)), + methodInstrumentables = listOf( + OkHttpEventListenerMethodInstrumentable( + useSentryAndroidOkHttp, + okHttpVersion + ) + ), parameters = parameters ) } class OkHttpEventListenerMethodInstrumentable( + private val useSentryAndroidOkHttp: Boolean, private val okHttpVersion: SemVer ) : MethodInstrumentable { override val fqName: String get() = "" @@ -42,7 +51,8 @@ class OkHttpEventListenerMethodInstrumentable( apiVersion = apiVersion, originalVisitor = originalVisitor, instrumentableContext = instrumentableContext, - okHttpVersion = okHttpVersion + okHttpVersion = okHttpVersion, + useSentryAndroidOkHttp = useSentryAndroidOkHttp ) override fun isInstrumentable(data: MethodContext): Boolean { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/OkHttpEventListenerMethodVisitor.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/OkHttpEventListenerMethodVisitor.kt index 01746d812..1c38789c1 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/OkHttpEventListenerMethodVisitor.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/OkHttpEventListenerMethodVisitor.kt @@ -10,7 +10,8 @@ class OkHttpEventListenerMethodVisitor( apiVersion: Int, originalVisitor: MethodVisitor, instrumentableContext: MethodContext, - private val okHttpVersion: SemVer + private val okHttpVersion: SemVer, + private val useSentryAndroidOkHttp: Boolean ) : AdviceAdapter( apiVersion, originalVisitor, @@ -19,6 +20,12 @@ class OkHttpEventListenerMethodVisitor( instrumentableContext.descriptor ) { + private val sentryOkHttpEventListener = if (useSentryAndroidOkHttp) { + "io/sentry/android/okhttp/SentryOkHttpEventListener" + } else { + "io/sentry/okhttp/SentryOkHttpEventListener" + } + override fun onMethodEnter() { super.onMethodEnter() // Add the following call at the beginning of the constructor with the Builder parameter: @@ -28,7 +35,7 @@ class OkHttpEventListenerMethodVisitor( visitVarInsn(Opcodes.ALOAD, 1) // Let's declare the SentryOkHttpEventListener variable - visitTypeInsn(Opcodes.NEW, "io/sentry/android/okhttp/SentryOkHttpEventListener") + visitTypeInsn(Opcodes.NEW, sentryOkHttpEventListener) // The SentryOkHttpEventListener constructor, which is called later, will consume the // element without pushing anything back to the stack ( returns void). @@ -62,7 +69,7 @@ class OkHttpEventListenerMethodVisitor( // Call SentryOkHttpEventListener constructor passing "eventListenerFactory" as parameter visitMethodInsn( Opcodes.INVOKESPECIAL, - "io/sentry/android/okhttp/SentryOkHttpEventListener", + sentryOkHttpEventListener, "", "(Lokhttp3/EventListener\$Factory;)V", false diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/ResponseWithInterceptorChainMethodVisitor.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/ResponseWithInterceptorChainMethodVisitor.kt index dfff1a8fb..854c7ae5e 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/ResponseWithInterceptorChainMethodVisitor.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/okhttp/visitor/ResponseWithInterceptorChainMethodVisitor.kt @@ -8,6 +8,7 @@ import org.objectweb.asm.commons.GeneratorAdapter import org.objectweb.asm.commons.Method class ResponseWithInterceptorChainMethodVisitor( + private val useSentryAndroidOkHttp: Boolean, api: Int, private val originalVisitor: MethodVisitor, access: Int, @@ -17,6 +18,12 @@ class ResponseWithInterceptorChainMethodVisitor( private var shouldInstrument = false + private val sentryOkInterceptor = if (useSentryAndroidOkHttp) { + Types.SENTRY_ANDROID_OKHTTP_INTERCEPTOR + } else { + Types.SENTRY_OKHTTP_INTERCEPTOR + } + override fun visitMethodInsn( opcode: Int, owner: String?, @@ -69,7 +76,7 @@ class ResponseWithInterceptorChainMethodVisitor( storeLocal(interceptorIndex) loadLocal(interceptorIndex) checkCast(Types.OKHTTP_INTERCEPTOR) - instanceOf(Types.SENTRY_OKHTTP_INTERCEPTOR) + instanceOf(sentryOkInterceptor) ifZCmp(EQ, whileLabel) loadLocal(interceptorIndex) val ifLabel = Label() @@ -83,10 +90,10 @@ class ResponseWithInterceptorChainMethodVisitor( originalVisitor.visitVarInsn(Opcodes.ALOAD, 1) checkCast(Types.COLLECTION) - newInstance(Types.SENTRY_OKHTTP_INTERCEPTOR) + newInstance(sentryOkInterceptor) dup() val sentryOkHttpCtor = Method.getMethod("void ()") - invokeConstructor(Types.SENTRY_OKHTTP_INTERCEPTOR, sentryOkHttpCtor) + invokeConstructor(sentryOkInterceptor, sentryOkHttpCtor) val addInterceptor = Method.getMethod("boolean add (Object)") invokeInterface(Types.COLLECTION, addInterceptor) pop() diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/Types.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/Types.kt index bc3a3eab5..c83c33e48 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/Types.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/Types.kt @@ -19,6 +19,8 @@ object Types { // OKHTTP val OKHTTP_INTERCEPTOR = Type.getType("Lokhttp3/Interceptor;") - val SENTRY_OKHTTP_INTERCEPTOR = + val SENTRY_ANDROID_OKHTTP_INTERCEPTOR = Type.getType("Lio/sentry/android/okhttp/SentryOkHttpInterceptor;") + val SENTRY_OKHTTP_INTERCEPTOR = + Type.getType("Lio/sentry/okhttp/SentryOkHttpInterceptor;") } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt index a6789c293..75aaaa392 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/services/SentryModulesService.kt @@ -91,15 +91,31 @@ abstract class SentryModulesService : SentryVersions.VERSION_FILE_IO ) && parameters.features.get().contains(InstrumentationFeature.FILE_IO) - fun isOkHttpListenerInstrEnabled(): Boolean = sentryModules.isAtLeast( - SentryModules.SENTRY_ANDROID_OKHTTP, - SentryVersions.VERSION_OKHTTP_LISTENER - ) && parameters.features.get().contains(InstrumentationFeature.OKHTTP) - - fun isOkHttpInstrEnabled(): Boolean = sentryModules.isAtLeast( - SentryModules.SENTRY_ANDROID_OKHTTP, - SentryVersions.VERSION_OKHTTP - ) && parameters.features.get().contains(InstrumentationFeature.OKHTTP) + fun isOkHttpListenerInstrEnabled(): Boolean { + val isSentryAndroidOkHttpListener = sentryModules.isAtLeast( + SentryModules.SENTRY_ANDROID_OKHTTP, + SentryVersions.VERSION_ANDROID_OKHTTP_LISTENER + ) + val isSentryOkHttpListener = sentryModules.isAtLeast( + SentryModules.SENTRY_OKHTTP, + SentryVersions.VERSION_OKHTTP + ) + return (isSentryAndroidOkHttpListener || isSentryOkHttpListener) && + parameters.features.get().contains(InstrumentationFeature.OKHTTP) + } + + fun isOkHttpInstrEnabled(): Boolean { + val isSentryAndroidOkHttp = sentryModules.isAtLeast( + SentryModules.SENTRY_ANDROID_OKHTTP, + SentryVersions.VERSION_ANDROID_OKHTTP + ) + val isSentryOkHttp = sentryModules.isAtLeast( + SentryModules.SENTRY_OKHTTP, + SentryVersions.VERSION_OKHTTP + ) + return (isSentryAndroidOkHttp || isSentryOkHttp) && + parameters.features.get().contains(InstrumentationFeature.OKHTTP) + } fun isComposeInstrEnabled(): Boolean = sentryModules.isAtLeast( diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt index 8a1a57c03..4b74b8eda 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/telemetry/SentryTelemetryService.kt @@ -11,6 +11,7 @@ import io.sentry.Sentry import io.sentry.SentryEvent import io.sentry.SentryLevel import io.sentry.SpanStatus +import io.sentry.TransactionOptions import io.sentry.android.gradle.SentryCliProvider import io.sentry.android.gradle.SentryPlugin import io.sentry.android.gradle.SentryPlugin.Companion.logger @@ -196,7 +197,9 @@ abstract class SentryTelemetryService : fun startRun(transactionName: String) { hub.startSession() - transaction = hub.startTransaction(transactionName, "build", true) + val options = TransactionOptions() + options.isBindToScope = true + transaction = hub.startTransaction(transactionName, "build", options) } fun endRun() { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt index ae060f286..a891e8b15 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/util/Versions.kt @@ -23,13 +23,14 @@ internal object GradleVersions { internal object SentryVersions { internal val VERSION_DEFAULT = SemVer() internal val VERSION_PERFORMANCE = SemVer(4, 0, 0) - internal val VERSION_OKHTTP = SemVer(5, 0, 0) + internal val VERSION_ANDROID_OKHTTP = SemVer(5, 0, 0) internal val VERSION_FILE_IO = SemVer(5, 5, 0) internal val VERSION_COMPOSE = SemVer(6, 7, 0) internal val VERSION_LOGCAT = SemVer(6, 17, 0) internal val VERSION_APP_START = SemVer(7, 1, 0) internal val VERSION_SQLITE = SemVer(6, 21, 0) - internal val VERSION_OKHTTP_LISTENER = SemVer(6, 20, 0) + internal val VERSION_ANDROID_OKHTTP_LISTENER = SemVer(6, 20, 0) + internal val VERSION_OKHTTP = SemVer(7, 0, 0) } internal object SentryModules { @@ -73,6 +74,10 @@ internal object SentryModules { "io.sentry", "sentry-android-timber" ) + internal val SENTRY_OKHTTP = DefaultModuleIdentifier.newId( + "io.sentry", + "sentry-okhttp" + ) internal val SENTRY_KOTLIN_EXTENSIONS = DefaultModuleIdentifier.newId( "io.sentry", "sentry-kotlin-extensions" diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/AndroidOkHttpInstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/AndroidOkHttpInstallStrategyTest.kt new file mode 100644 index 000000000..8f80d26ff --- /dev/null +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/AndroidOkHttpInstallStrategyTest.kt @@ -0,0 +1,106 @@ +package io.sentry.android.gradle.autoinstall.okhttp + +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.check +import com.nhaarman.mockitokotlin2.doAnswer +import com.nhaarman.mockitokotlin2.doReturn +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.never +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import io.sentry.android.gradle.autoinstall.AutoInstallState +import io.sentry.android.gradle.instrumentation.fakes.CapturingTestLogger +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.gradle.api.Action +import org.gradle.api.artifacts.ComponentMetadataContext +import org.gradle.api.artifacts.ComponentMetadataDetails +import org.gradle.api.artifacts.DirectDependenciesMetadata +import org.gradle.api.artifacts.ModuleVersionIdentifier +import org.gradle.api.artifacts.VariantMetadata +import org.junit.Test +import org.slf4j.Logger + +class AndroidOkHttpInstallStrategyTest { + class Fixture { + val logger = CapturingTestLogger() + val dependencies = mock() + val metadataDetails = mock() + val metadataContext = mock { + whenever(it.details).thenReturn(metadataDetails) + val metadata = mock() + doAnswer { + (it.arguments[0] as Action).execute(dependencies) + }.whenever(metadata).withDependencies(any>()) + + doAnswer { + // trigger the callback registered in tests + (it.arguments[0] as Action).execute(metadata) + }.whenever(metadataDetails).allVariants(any>()) + } + + fun getSut( + okHttpVersion: String = "4.9.3", + sentryVersion: String = "5.6.1" + ): AndroidOkHttpInstallStrategy { + val id = mock { + whenever(it.version).doReturn(okHttpVersion) + } + whenever(metadataDetails.id).thenReturn(id) + + with(AutoInstallState.getInstance()) { + this.enabled = true + this.sentryVersion = sentryVersion + } + return AndroidOkHttpInstallStrategyImpl(logger) + } + } + + private val fixture = Fixture() + + @Test + fun `when okhttp version is unsupported logs a message and does nothing`() { + val sut = fixture.getSut(okHttpVersion = "3.11.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-android-okhttp won't be installed because the current " + + "version is lower than the minimum supported version (3.13.0)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `when sentry version is unsupported logs a message and does nothing`() { + val sut = fixture.getSut(sentryVersion = "7.0.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-android-okhttp won't be installed because the current " + + "sentry version is higher than the maximum supported sentry version (6.9999.9999)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `installs sentry-android-okhttp with info message`() { + val sut = fixture.getSut() + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-android-okhttp was successfully installed with version: 5.6.1" + } + verify(fixture.dependencies).add( + check { + assertEquals("io.sentry:sentry-android-okhttp:5.6.1", it) + } + ) + } + + private class AndroidOkHttpInstallStrategyImpl( + logger: Logger + ) : AndroidOkHttpInstallStrategy(logger) +} diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategyTest.kt index c0f650d16..d0f505461 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategyTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/okhttp/OkHttpInstallStrategyTest.kt @@ -40,7 +40,8 @@ class OkHttpInstallStrategyTest { } fun getSut( - okHttpVersion: String = "4.9.3" + okHttpVersion: String = "4.9.3", + sentryVersion: String = "7.0.0" ): OkHttpInstallStrategy { val id = mock { whenever(it.version).doReturn(okHttpVersion) @@ -49,7 +50,7 @@ class OkHttpInstallStrategyTest { with(AutoInstallState.getInstance()) { this.enabled = true - this.sentryVersion = "5.6.1" + this.sentryVersion = sentryVersion } return OkHttpInstallStrategyImpl(logger) } @@ -64,24 +65,37 @@ class OkHttpInstallStrategyTest { assertTrue { fixture.logger.capturedMessage == - "[sentry] sentry-android-okhttp won't be installed because the current " + + "[sentry] sentry-okhttp won't be installed because the current " + "version is lower than the minimum supported version (3.13.0)" } verify(fixture.metadataDetails, never()).allVariants(any()) } @Test - fun `installs sentry-android-okhttp with info message`() { + fun `when sentry version is unsupported logs a message and does nothing`() { + val sut = fixture.getSut(sentryVersion = "6.33.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-okhttp won't be installed because the current sentry " + + "version is lower than the minimum supported sentry version (7.0.0)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `installs sentry-okhttp with info message`() { val sut = fixture.getSut() sut.execute(fixture.metadataContext) assertTrue { fixture.logger.capturedMessage == - "[sentry] sentry-android-okhttp was successfully installed with version: 5.6.1" + "[sentry] sentry-okhttp was successfully installed with version: 7.0.0" } verify(fixture.dependencies).add( check { - assertEquals("io.sentry:sentry-android-okhttp:5.6.1", it) + assertEquals("io.sentry:sentry-okhttp:7.0.0", it) } ) } diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/VisitorTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/VisitorTest.kt index e78f1a338..b569ca4aa 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/VisitorTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/VisitorTest.kt @@ -170,10 +170,14 @@ class VisitorTest( ChainedInstrumentable(listOf(WrappingInstrumentable(), RemappingInstrumentable())), null ), - arrayOf("okhttp/v3", "RealCall", OkHttp(), null), - arrayOf("okhttp/v4", "RealCall", OkHttp(), null), - arrayOf("okhttp/v3", "OkHttpClient", OkHttpEventListener(SemVer(3, 0, 0)), null), - arrayOf("okhttp/v4", "OkHttpClient", OkHttpEventListener(SemVer(4, 0, 0)), null), + arrayOf("okhttp/v3", "RealCall", OkHttp(true), null), + arrayOf("okhttp/v4", "RealCall", OkHttp(true), null), + arrayOf("okhttp/v3", "RealCall", OkHttp(false), null), + arrayOf("okhttp/v4", "RealCall", OkHttp(false), null), + arrayOf("okhttp/v3", "OkHttpClient", OkHttpEventListener(true, SemVer(3, 0, 0)), null), + arrayOf("okhttp/v4", "OkHttpClient", OkHttpEventListener(true, SemVer(4, 0, 0)), null), + arrayOf("okhttp/v3", "OkHttpClient", OkHttpEventListener(false, SemVer(3, 0, 0)), null), + arrayOf("okhttp/v4", "OkHttpClient", OkHttpEventListener(false, SemVer(4, 0, 0)), null), arrayOf("androidxCompose", "NavHostControllerKt", ComposeNavigation(), null), arrayOf("logcat", "LogcatTest", Logcat(), null), arrayOf("appstart", "MyApplication", Application(), null), diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/CapturingTestLogger.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/CapturingTestLogger.kt index 1eecd9fcf..26086835b 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/CapturingTestLogger.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/CapturingTestLogger.kt @@ -24,4 +24,9 @@ class CapturingTestLogger : BaseTestLogger() { capturedMessage = msg capturedThrowable = throwable } + + override fun debug(msg: String, throwable: Throwable?) { + capturedMessage = msg + capturedThrowable = throwable + } }