From 83e3a538b15a3ff334fe7056d8c324951d734472 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 24 Oct 2022 08:04:33 +0200 Subject: [PATCH 01/23] Add auto-instrumentation for compose navigation --- .../TracingInstrumentationExtension.kt | 10 +- .../SpanAddingClassVisitorFactory.kt | 13 +++ .../androidx/compose/ComposeNavigation.kt | 18 ++++ .../util/MethodReplacingInstrumentable.kt | 97 +++++++++++++++++++ .../io/sentry/android/gradle/util/Versions.kt | 3 + 5 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt create mode 100644 plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt index 7a0986db..ed1e97eb 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt @@ -68,5 +68,13 @@ enum class InstrumentationFeature { * This feature uses bytecode manipulation and attaches SentryOkHttpInterceptor to all OkHttp * clients in the project. */ - OKHTTP + OKHTTP, + + /** + * When enabled the SDK will create breadcrumbs when navigating + * using [androidx.navigation.NavController]. + * This feature uses bytecode manipulation and adds an OnDestinationChangedListener to all + * navigation controllers used in Jetpack Compose. + */ + COMPOSE } 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 08dd1760..e7c104fd 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 @@ -6,6 +6,7 @@ import com.android.build.api.instrumentation.ClassData import com.android.build.api.instrumentation.InstrumentationParameters import io.sentry.android.gradle.SentryPlugin import io.sentry.android.gradle.extensions.InstrumentationFeature +import io.sentry.android.gradle.instrumentation.androidx.compose.ComposeNavigation import io.sentry.android.gradle.instrumentation.androidx.room.AndroidXRoomDao import io.sentry.android.gradle.instrumentation.androidx.sqlite.database.AndroidXSQLiteDatabase import io.sentry.android.gradle.instrumentation.androidx.sqlite.statement.AndroidXSQLiteStatement @@ -79,6 +80,9 @@ abstract class SpanAddingClassVisitorFactory : * from the sentry-android SDK. */ val instrumentables = listOfNotNull( + ComposeNavigation().takeIf { + isComposeInstrEnabled(sentryModules, parameters.get()) + }, AndroidXSQLiteDatabase().takeIf { isDatabaseInstrEnabled(sentryModules, parameters.get()) }, @@ -126,6 +130,15 @@ abstract class SpanAddingClassVisitorFactory : SentryVersions.VERSION_OKHTTP ) && parameters.features.get().contains(InstrumentationFeature.OKHTTP) + private fun isComposeInstrEnabled( + sentryModules: Map, + parameters: SpanAddingParameters + ): Boolean = + sentryModules.isAtLeast( + SentryModules.SENTRY_ANDROID_COMPOSE, + SentryVersions.VERSION_COMPOSE + ) && parameters.features.get().contains(InstrumentationFeature.COMPOSE) + private fun Map.isAtLeast(module: String, minVersion: SemVer): Boolean = getOrDefault(module, SentryVersions.VERSION_DEFAULT) >= minVersion diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt new file mode 100644 index 00000000..95645bfa --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt @@ -0,0 +1,18 @@ +package io.sentry.android.gradle.instrumentation.androidx.compose + +import io.sentry.android.gradle.instrumentation.util.MethodReplacingInstrumentable +import org.objectweb.asm.Opcodes + +/* ktlint-disable max-line-length */ +class ComposeNavigation : MethodReplacingInstrumentable( + listOf( + MethodReplacement( + Opcodes.INVOKESTATIC, + "androidx/navigation/compose/NavHostControllerKt", + "rememberNavController", + "([Landroidx/navigation/Navigator;Landroidx/compose/runtime/Composer;I)Landroidx/navigation/NavHostController;", + "io/sentry/compose/SentryNavigationIntegrationKt", + "rememberNavController" + ) + ) +) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt new file mode 100644 index 00000000..f0c323d4 --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt @@ -0,0 +1,97 @@ +package io.sentry.android.gradle.instrumentation.util + +import com.android.build.api.instrumentation.ClassContext +import io.sentry.android.gradle.instrumentation.ClassInstrumentable +import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.MethodVisitor + +open class MethodReplacingInstrumentable(private val replacements: List) : + ClassInstrumentable { + + override fun getVisitor( + instrumentableContext: ClassContext, + apiVersion: Int, + originalVisitor: ClassVisitor, + parameters: SpanAddingClassVisitorFactory.SpanAddingParameters + ): ClassVisitor { + return MethodReplacingClassVisitor(apiVersion, originalVisitor, replacements) + } + + override fun isInstrumentable(data: ClassContext): Boolean = !data.isSentryClass() + + data class MethodReplacement( + val originalOpcode: Int, + val originalOwner: String?, + val originalName: String?, + val originalDescriptor: String?, + + val newOwner: String?, + val newName: String? + ) +} + +class MethodReplacingClassVisitor( + private val apiVersion: Int, + originalVisitor: ClassVisitor, + replacements: List +) : ClassVisitor(apiVersion, originalVisitor) { + + private val replacementsMap = + replacements.associateBy { + fingerprintInstruction( + it.originalOpcode, + it.originalOwner, + it.originalName, + it.originalDescriptor, + ) + } + + override fun visitMethod( + access: Int, + name: String?, + descriptor: String?, + signature: String?, + exceptions: Array?, + ): MethodVisitor { + return object : MethodVisitor( + apiVersion, + super.visitMethod(access, name, descriptor, signature, exceptions) + ) { + override fun visitMethodInsn( + opcode: Int, + owner: String?, + name: String?, + descriptor: String?, + isInterface: Boolean + ) { + val replacement = + replacementsMap[ + fingerprintInstruction( + opcode, + owner, + name, + descriptor, + ) + ] + + val newName = replacement?.newName ?: name + val newOwner = replacement?.newOwner ?: owner + super.visitMethodInsn( + opcode, + newOwner, + newName, + descriptor, + isInterface + ) + } + } + } + + private fun fingerprintInstruction( + opcode: Int, + owner: String?, + name: String?, + descriptor: String?, + ) = "$opcode-$owner.$name-$descriptor" +} 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 7822af7a..e44996ff 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 @@ -15,11 +15,14 @@ internal object SentryVersions { internal val VERSION_PERFORMANCE = SemVer(4, 0, 0) internal val VERSION_OKHTTP = SemVer(5, 0, 0) internal val VERSION_FILE_IO = SemVer(5, 5, 0) + // TODO use correct version + internal val VERSION_COMPOSE = SemVer(1, 0, 0) } internal object SentryModules { internal const val SENTRY_ANDROID_CORE = "sentry-android-core" internal const val SENTRY_ANDROID_OKHTTP = "sentry-android-okhttp" + internal const val SENTRY_ANDROID_COMPOSE = "sentry-android-compose" } /** From bfbb977fc0243d47a95e10fa9a535f8adfb54c53 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Oct 2022 08:23:03 +0200 Subject: [PATCH 02/23] Switch to single ChainedInstrumentable, improve ComposeNavigation --- .../SpanAddingClassVisitorFactory.kt | 84 +++++++-------- .../androidx/compose/ComposeNavigation.kt | 88 +++++++++++++--- .../util/MethodReplacingInstrumentable.kt | 97 ------------------ .../io/sentry/android/gradle/util/Versions.kt | 3 +- .../gradle/instrumentation/VisitorTest.kt | 4 +- .../fakes/TestSpanAddingParameters.kt | 2 +- .../androidxCompose/NavHostControllerKt.class | Bin 0 -> 6618 bytes 7 files changed, 121 insertions(+), 157 deletions(-) delete mode 100644 plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt create mode 100644 plugin-build/src/test/resources/testFixtures/instrumentation/androidxCompose/NavHostControllerKt.class 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 e7c104fd..102e39a7 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 @@ -22,7 +22,6 @@ import io.sentry.android.gradle.util.SentryModules import io.sentry.android.gradle.util.SentryVersions import io.sentry.android.gradle.util.debug import io.sentry.android.gradle.util.info -import io.sentry.android.gradle.util.warn import java.io.File import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty @@ -59,15 +58,15 @@ abstract class SpanAddingClassVisitorFactory : val tmpDir: Property @get:Internal - var _instrumentables: List? + var _instrumentable: ClassInstrumentable? } - private val instrumentables: List + private val instrumentable: ClassInstrumentable get() { - val memoized = parameters.get()._instrumentables + val memoized = parameters.get()._instrumentable if (memoized != null) { SentryPlugin.logger.debug { - "Memoized: ${memoized.joinToString { it::class.java.simpleName }}" + "Memoized: $memoized" } return memoized } @@ -79,29 +78,41 @@ abstract class SpanAddingClassVisitorFactory : * version to [SentryVersions] if it involves runtime classes * from the sentry-android SDK. */ - val instrumentables = listOfNotNull( - ComposeNavigation().takeIf { - isComposeInstrEnabled(sentryModules, parameters.get()) - }, - AndroidXSQLiteDatabase().takeIf { - isDatabaseInstrEnabled(sentryModules, parameters.get()) - }, - AndroidXSQLiteStatement().takeIf { - isDatabaseInstrEnabled(sentryModules, parameters.get()) - }, - AndroidXRoomDao().takeIf { - isDatabaseInstrEnabled(sentryModules, parameters.get()) - }, - OkHttp().takeIf { isOkHttpInstrEnabled(sentryModules, parameters.get()) }, - ChainedInstrumentable( - listOf(WrappingInstrumentable(), RemappingInstrumentable()) - ).takeIf { isFileIOInstrEnabled(sentryModules, parameters.get()) } + val instrumentable = ChainedInstrumentable( + listOfNotNull( + AndroidXSQLiteDatabase().takeIf { + isDatabaseInstrEnabled(sentryModules, parameters.get()) + }, + AndroidXSQLiteStatement().takeIf { + isDatabaseInstrEnabled(sentryModules, parameters.get()) + }, + AndroidXRoomDao().takeIf { + isDatabaseInstrEnabled(sentryModules, parameters.get()) + }, + OkHttp().takeIf { isOkHttpInstrEnabled(sentryModules, parameters.get()) }, + WrappingInstrumentable().takeIf { + isFileIOInstrEnabled( + sentryModules, + parameters.get() + ) + }, + RemappingInstrumentable().takeIf { + isFileIOInstrEnabled( + sentryModules, + parameters.get() + ) + }, + ComposeNavigation().takeIf { + isComposeInstrEnabled(sentryModules, parameters.get()) + }, + ) ) + SentryPlugin.logger.info { - "Instrumentables: ${instrumentables.joinToString { it::class.java.simpleName }}" + "Instrumentable: $instrumentable" } - parameters.get()._instrumentables = ArrayList(instrumentables) - return instrumentables + parameters.get()._instrumentable = instrumentable + return instrumentable } private fun isDatabaseInstrEnabled( @@ -157,23 +168,14 @@ abstract class SpanAddingClassVisitorFactory : return nextClassVisitor } - return instrumentables.find { it.isInstrumentable(classContext) } - ?.getVisitor( - classContext, - instrumentationContext.apiVersion.get(), - nextClassVisitor, - parameters = parameters.get() - ) - ?: nextClassVisitor.also { - SentryPlugin.logger.warn { - """ - $className is not supported for instrumentation. - This is likely a bug, please file an issue at https://github.com/getsentry/sentry-android-gradle-plugin/issues - """.trimIndent() - } - } + return instrumentable.getVisitor( + classContext, + instrumentationContext.apiVersion.get(), + nextClassVisitor, + parameters = parameters.get() + ) } override fun isInstrumentable(classData: ClassData): Boolean = - instrumentables.any { it.isInstrumentable(classData.toClassContext()) } + instrumentable.isInstrumentable(classData.toClassContext()) } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt index 95645bfa..d7692f3f 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt @@ -1,18 +1,76 @@ package io.sentry.android.gradle.instrumentation.androidx.compose -import io.sentry.android.gradle.instrumentation.util.MethodReplacingInstrumentable -import org.objectweb.asm.Opcodes - -/* ktlint-disable max-line-length */ -class ComposeNavigation : MethodReplacingInstrumentable( - listOf( - MethodReplacement( - Opcodes.INVOKESTATIC, - "androidx/navigation/compose/NavHostControllerKt", - "rememberNavController", - "([Landroidx/navigation/Navigator;Landroidx/compose/runtime/Composer;I)Landroidx/navigation/NavHostController;", - "io/sentry/compose/SentryNavigationIntegrationKt", - "rememberNavController" +import com.android.build.api.instrumentation.ClassContext +import io.sentry.android.gradle.instrumentation.ClassInstrumentable +import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory +import io.sentry.android.gradle.instrumentation.wrap.Replacement +import org.objectweb.asm.ClassVisitor +import org.objectweb.asm.MethodVisitor +import org.objectweb.asm.Type +import org.objectweb.asm.commons.AdviceAdapter +import org.objectweb.asm.commons.Method + +open class ComposeNavigation : ClassInstrumentable { + + companion object { + private const val NAV_HOST_CONTROLLER_CLASSNAME = "androidx.navigation.NavHostController" + private const val REMEMBER_NAV_CONTROLLER_NAME = "rememberNavController" + + /* ktlint-disable max-line-length */ + val replacement = Replacement( + "Lio/sentry/compose/SentryNavigationIntegrationKt;", + "withSentryObservableEffect", + "(Landroidx/navigation/NavHostController;Landroidx/compose/runtime/Composer;I)Landroidx/navigation/NavHostController;" ) - ) -) + /* ktlint-enable max-line-length */ + } + + override fun getVisitor( + instrumentableContext: ClassContext, + apiVersion: Int, + originalVisitor: ClassVisitor, + parameters: SpanAddingClassVisitorFactory.SpanAddingParameters + ): ClassVisitor { + return object : ClassVisitor(apiVersion, originalVisitor) { + + override fun visitMethod( + access: Int, + name: String?, + descriptor: String?, + signature: String?, + exceptions: Array?, + ): MethodVisitor { + val methodVisitor = + originalVisitor.visitMethod(access, name, descriptor, signature, exceptions) + + return if (name == REMEMBER_NAV_CONTROLLER_NAME) { + object : AdviceAdapter(apiVersion, methodVisitor, access, name, descriptor) { + + override fun onMethodExit(opcode: Int) { + // NavHostController is the return value; + // thus it's already on top of stack + + // Composer $composer + loadArg(1) + + // int $changed + loadArg(2) + + invokeStatic( + Type.getType(replacement.owner), + Method(replacement.name, replacement.descriptor) + ) + super.onMethodExit(opcode) + } + } + } else { + methodVisitor + } + } + } + } + + override fun isInstrumentable(data: ClassContext): Boolean { + return data.currentClassData.className == NAV_HOST_CONTROLLER_CLASSNAME + } +} diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt deleted file mode 100644 index f0c323d4..00000000 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/util/MethodReplacingInstrumentable.kt +++ /dev/null @@ -1,97 +0,0 @@ -package io.sentry.android.gradle.instrumentation.util - -import com.android.build.api.instrumentation.ClassContext -import io.sentry.android.gradle.instrumentation.ClassInstrumentable -import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.MethodVisitor - -open class MethodReplacingInstrumentable(private val replacements: List) : - ClassInstrumentable { - - override fun getVisitor( - instrumentableContext: ClassContext, - apiVersion: Int, - originalVisitor: ClassVisitor, - parameters: SpanAddingClassVisitorFactory.SpanAddingParameters - ): ClassVisitor { - return MethodReplacingClassVisitor(apiVersion, originalVisitor, replacements) - } - - override fun isInstrumentable(data: ClassContext): Boolean = !data.isSentryClass() - - data class MethodReplacement( - val originalOpcode: Int, - val originalOwner: String?, - val originalName: String?, - val originalDescriptor: String?, - - val newOwner: String?, - val newName: String? - ) -} - -class MethodReplacingClassVisitor( - private val apiVersion: Int, - originalVisitor: ClassVisitor, - replacements: List -) : ClassVisitor(apiVersion, originalVisitor) { - - private val replacementsMap = - replacements.associateBy { - fingerprintInstruction( - it.originalOpcode, - it.originalOwner, - it.originalName, - it.originalDescriptor, - ) - } - - override fun visitMethod( - access: Int, - name: String?, - descriptor: String?, - signature: String?, - exceptions: Array?, - ): MethodVisitor { - return object : MethodVisitor( - apiVersion, - super.visitMethod(access, name, descriptor, signature, exceptions) - ) { - override fun visitMethodInsn( - opcode: Int, - owner: String?, - name: String?, - descriptor: String?, - isInterface: Boolean - ) { - val replacement = - replacementsMap[ - fingerprintInstruction( - opcode, - owner, - name, - descriptor, - ) - ] - - val newName = replacement?.newName ?: name - val newOwner = replacement?.newOwner ?: owner - super.visitMethodInsn( - opcode, - newOwner, - newName, - descriptor, - isInterface - ) - } - } - } - - private fun fingerprintInstruction( - opcode: Int, - owner: String?, - name: String?, - descriptor: String?, - ) = "$opcode-$owner.$name-$descriptor" -} 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 e44996ff..8d3de2a9 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 @@ -15,8 +15,7 @@ internal object SentryVersions { internal val VERSION_PERFORMANCE = SemVer(4, 0, 0) internal val VERSION_OKHTTP = SemVer(5, 0, 0) internal val VERSION_FILE_IO = SemVer(5, 5, 0) - // TODO use correct version - internal val VERSION_COMPOSE = SemVer(1, 0, 0) + internal val VERSION_COMPOSE = SemVer(6, 7, 0) } internal object SentryModules { 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 e477a15f..7f4ff493 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 @@ -1,6 +1,7 @@ package io.sentry.android.gradle.instrumentation import com.android.build.api.instrumentation.ClassContext +import io.sentry.android.gradle.instrumentation.androidx.compose.ComposeNavigation import io.sentry.android.gradle.instrumentation.androidx.room.AndroidXRoomDao import io.sentry.android.gradle.instrumentation.androidx.sqlite.database.AndroidXSQLiteDatabase import io.sentry.android.gradle.instrumentation.androidx.sqlite.statement.AndroidXSQLiteStatement @@ -137,7 +138,8 @@ class VisitorTest( null ), arrayOf("okhttp/v3", "RealCall", OkHttp(), null), - arrayOf("okhttp/v4", "RealCall", OkHttp(), null) + arrayOf("okhttp/v4", "RealCall", OkHttp(), null), + arrayOf("androidxCompose", "NavHostControllerKt", ComposeNavigation(), null) ) private fun roomDaoTestParameters(suffix: String = "") = arrayOf( diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt index ae17eee0..c9f23a86 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/instrumentation/fakes/TestSpanAddingParameters.kt @@ -33,5 +33,5 @@ class TestSpanAddingParameters( override val tmpDir: Property get() = DefaultProperty(PropertyHost.NO_OP, File::class.java).convention(inMemoryDir) - override var _instrumentables: List? = listOf() + override var _instrumentable: ClassInstrumentable? = null } diff --git a/plugin-build/src/test/resources/testFixtures/instrumentation/androidxCompose/NavHostControllerKt.class b/plugin-build/src/test/resources/testFixtures/instrumentation/androidxCompose/NavHostControllerKt.class new file mode 100644 index 0000000000000000000000000000000000000000..9444122b48b60a4b8eb57951bc63a99b1fa55676 GIT binary patch literal 6618 zcmcgwTXz%J75eHNz+`~l-`ok3%!uu)3gN>QtHxs+CKF+^sz5}X`h6eDH5@j`SzOU6=R-4X-X2!qGSvKD;e4|=jF_dJE=m!HZNslZu?b~v1Xn%iO>VsBw`~v-NC6wPo*LRY^KV}$!4liagF7*k1%w0b&r=) zdyz_);$|wUY{aMOWt>Y42N1zl5nHg0p{uFWld3dpoYzdNh`8rn468D{?lWe&ieK$o zd@2_vO4KlH%eyU0IYx3n<%{OB%6{p(4$WtXY<*9@`=|3aD6IBbq{k!5_(-CkmCb3@l9*pvwihFeU2*+e-c!3SDQL z8Nm5k)0Y)J7im^IQBCmV$knCh+Z$_U&mq|$=vf6qj8~Cr8U%MvmoQ7T-)p+z$FTPw znScG0;h|Jl!>D!d9ypNPl}L{7*%946NX=b|@kC;9aYoq3u)myX$K;|CCrUDT;m1cx zOJ&Mhi4;!A<61__8|Um%yk-tCtfp$UUfAen*h2+cr`cK9PUza4lI4_FtC;HcAW|Ym zaEPJ1se;;J0>-?)?pTs|BQ;d}l2hQIlDm+b^@BjSp^n*(N&1Ye69?!f!{BmAF72v$ z*E(<%# zP2v={@?nPi?En)|5h( zyBl-{a26jB@qW);*BU|rX^H`Z26G6-EiD9`bNG-54chX|leMnKAD z%kwfEDCfWGB-L%#b2I((G*hQV)4j9sQ$blgc2Xjh6Ni4j5@HCy&yZ z>0B|{mzN4tS&3R%+H`DhW=QpX|&ehc-5H6p+t4QqY;Figq0G-CodsOzzdus;v!zeOAH$ujdclsj!@7@#8H1p zk@8y3HQ@6iu5!h@m&#~^phOb1Nw)We^&zXyCW)%cilAd@9j{q@-SiY$6Y3~GMjl!$ z5)^~#F@##`tDw=EkCXXVsL0Y2lcz=|QlkuG4!)|Y*|B=LTB)dC#aG+#3a%|h{7C^{ ze|LN#P2Uu8ed)D^oc{J=`zWJo4dn~WcNto(fHBNC=N{|yT)z$^%jcZN>qNp$h)!G^ zqk*FM8onpu2EI?b94V8L4LYLKLotBo@EN|y|AODKM8;c}n2a9Q-M^H_hU>Gz7B;F@x`$6tEwh|zO699*~@ z4uo1lo?cJLJPQ7W4)_-S4KU(tL=Bed$0M{a36?-U4*qnfEf=(q#@)9 z>h4nvv1>)FR;%;1sVSk?d<3Fws^yPtJ+`)Ux}29KgEq%&>&lEa>+}UArDf^u>Tx>M zPZaq9@f67XR`RU$9 z|3A=wwU`&+&JzF6o; z=%IN`#5!7T^eLTnzVJA?&1IuVWDoyP}z<}t z^dXej!*dtH**^PJpj*@&!DJUH+JStxN zk*=NayaN@YfKLl(X96A-a9BW#0G%-k$VMx6JISTB7{+!yj3K)3!(Kc_*BtiaaU8%E zx<5~+(if=jCHnIiPg8IQgT&12b*gc3xT1&`1^@Acm6WvFN?PzI>I;+2S-OJ~ z`HFqNZr|Ugy9d9r8Yu6#gGKF{CKjnX38l zLi8w>_0*Dct*{s!7ZY0&I|llO65^izEyJZa#U1_lkZ8n|oVR|a+&@EKV6FQke5F#rGn literal 0 HcmV?d00001 From e287b187a46e983896f67dd697a609b77da89236 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Oct 2022 08:28:46 +0200 Subject: [PATCH 03/23] Add auto-install feature for Compose instrumentation --- .../android/gradle/autoinstall/AutoInstall.kt | 6 ++- .../gradle/autoinstall/AutoInstallState.kt | 9 +++- .../compose/ComposeInstallStrategy.kt | 41 +++++++++++++++++++ .../TracingInstrumentationExtension.kt | 3 +- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt 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 0119a959..20ab810f 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 @@ -1,5 +1,7 @@ package io.sentry.android.gradle.autoinstall +import io.sentry.android.gradle.autoinstall.compose.ComposeInstallStrategy +import io.sentry.android.gradle.autoinstall.compose.ComposeInstallStrategy.Registrar.SENTRY_COMPOSE_ID import io.sentry.android.gradle.autoinstall.fragment.FragmentInstallStrategy import io.sentry.android.gradle.autoinstall.fragment.FragmentInstallStrategy.Registrar.SENTRY_FRAGMENT_ID import io.sentry.android.gradle.autoinstall.okhttp.OkHttpInstallStrategy @@ -18,7 +20,8 @@ private const val SENTRY_ANDROID_CORE_ID = "sentry-android-core" private val strategies = listOf( OkHttpInstallStrategy.Registrar, TimberInstallStrategy.Registrar, - FragmentInstallStrategy.Registrar + FragmentInstallStrategy.Registrar, + ComposeInstallStrategy.Registrar ) fun Project.installDependencies(extension: SentryPluginExtension) { @@ -34,6 +37,7 @@ fun Project.installDependencies(extension: SentryPluginExtension) { installOkHttp = !dependencies.isModuleAvailable(SENTRY_OKHTTP_ID) installTimber = !dependencies.isModuleAvailable(SENTRY_TIMBER_ID) installFragment = !dependencies.isModuleAvailable(SENTRY_FRAGMENT_ID) + installCompose = !dependencies.isModuleAvailable(SENTRY_COMPOSE_ID) } } } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstallState.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstallState.kt index 123fbb88..d561498b 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstallState.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/AutoInstallState.kt @@ -22,11 +22,16 @@ class AutoInstallState private constructor() : Serializable { @set:Synchronized var installTimber: Boolean = false + @get:Synchronized + @set:Synchronized + var installCompose: Boolean = false + override fun toString(): String { return "AutoInstallState(sentryVersion='$sentryVersion', " + "installOkHttp=$installOkHttp, " + "installFragment=$installFragment, " + - "installTimber=$installTimber)" + "installTimber=$installTimber," + + "installCompose=$installCompose)" } override fun equals(other: Any?): Boolean { @@ -39,6 +44,7 @@ class AutoInstallState private constructor() : Serializable { if (installOkHttp != other.installOkHttp) return false if (installFragment != other.installFragment) return false if (installTimber != other.installTimber) return false + if (installCompose != other.installCompose) return false return true } @@ -48,6 +54,7 @@ class AutoInstallState private constructor() : Serializable { result = 31 * result + installOkHttp.hashCode() result = 31 * result + installFragment.hashCode() result = 31 * result + installTimber.hashCode() + result = 31 * result + installCompose.hashCode() return result } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt new file mode 100644 index 00000000..8fa824c4 --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt @@ -0,0 +1,41 @@ +package io.sentry.android.gradle.autoinstall.compose + +import io.sentry.android.gradle.SentryPlugin +import io.sentry.android.gradle.autoinstall.AbstractInstallStrategy +import io.sentry.android.gradle.autoinstall.AutoInstallState +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 ComposeInstallStrategy : 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 moduleId: String get() = SENTRY_COMPOSE_ID + + override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installCompose + + override val minSupportedVersion: SemVer get() = MIN_SUPPORTED_VERSION + + companion object Registrar : InstallStrategyRegistrar { + private const val COMPOSE_GROUP = "androidx.compose.runtime" + private const val COMPOSE_ID = "runtime" + internal const val SENTRY_COMPOSE_ID = "sentry-compose-android" + private val MIN_SUPPORTED_VERSION = SemVer(1, 0, 0) + + override fun register(component: ComponentMetadataHandler) { + component.withModule( + "$COMPOSE_GROUP:$COMPOSE_ID", + ComposeInstallStrategy::class.java + ) {} + } + } +} diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt index ed1e97eb..6e782090 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/extensions/TracingInstrumentationExtension.kt @@ -42,7 +42,8 @@ open class TracingInstrumentationExtension @Inject constructor(objects: ObjectFa setOf( InstrumentationFeature.DATABASE, InstrumentationFeature.FILE_IO, - InstrumentationFeature.OKHTTP + InstrumentationFeature.OKHTTP, + InstrumentationFeature.COMPOSE, ) ) } From 8a9df30aa258bfc942667b3637644f87db0b5dcb Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Oct 2022 10:07:43 +0200 Subject: [PATCH 04/23] Add jetpack compose navigation instrumentation example --- buildSrc/src/main/java/Dependencies.kt | 10 ++- .../build.gradle.kts | 14 ++++ .../src/main/AndroidManifest.xml | 5 ++ .../instrumentation/ui/ComposeActivity.kt | 83 +++++++++++++++++++ .../instrumentation/ui/MainActivity.kt | 4 + .../src/main/res/menu/main.xml | 7 ++ plugin-build/build.gradle.kts | 3 +- 7 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 52815d06..fb22c359 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -2,8 +2,8 @@ import org.gradle.util.VersionNumber object BuildPluginsVersion { val AGP = System.getenv("VERSION_AGP") ?: "7.3.0" - const val DOKKA = "1.6.10" - const val KOTLIN = "1.6.10" + const val DOKKA = "1.7.20" + const val KOTLIN = "1.7.20" const val AAR_2_JAR = "0.6" const val KTLINT = "10.2.1" // do not upgrade to 0.18.0, it does not generate the pom-default.xml and module.json under @@ -52,6 +52,12 @@ object Samples { const val recyclerView = "androidx.recyclerview:recyclerview:1.2.0" const val lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" const val appcompat = "androidx.appcompat:appcompat:1.2.0" + + const val composeRuntime = "androidx.compose.runtime:runtime:1.2.1" + const val composeNavigation = "androidx.navigation:navigation-compose:2.5.2" + const val composeActivity = "androidx.activity:activity-compose:1.4.0" + const val composeFoundation = "androidx.compose.foundation:foundation:1.2.1" + const val composeFoundationLayout = "androidx.compose.foundation:foundation-layout:1.2.1" } object Coroutines { diff --git a/examples/android-instrumentation-sample/build.gradle.kts b/examples/android-instrumentation-sample/build.gradle.kts index 9a767546..7683150e 100644 --- a/examples/android-instrumentation-sample/build.gradle.kts +++ b/examples/android-instrumentation-sample/build.gradle.kts @@ -42,6 +42,14 @@ android { jvmTarget = JavaVersion.VERSION_1_8.toString() } namespace = "io.sentry.samples.instrumentation" + + buildFeatures { + compose = true + } + + composeOptions { + kotlinCompilerExtensionVersion = "1.3.2" + } } // useful, when we want to modify room-generated classes, and then compile them into .class files @@ -55,6 +63,12 @@ dependencies { implementation(Samples.AndroidX.lifecycle) implementation(Samples.AndroidX.appcompat) + implementation(Samples.AndroidX.composeRuntime) + implementation(Samples.AndroidX.composeActivity) + implementation(Samples.AndroidX.composeFoundation) + implementation(Samples.AndroidX.composeFoundationLayout) + implementation(Samples.AndroidX.composeNavigation) + implementation(Samples.Coroutines.core) implementation(Samples.Coroutines.android) diff --git a/examples/android-instrumentation-sample/src/main/AndroidManifest.xml b/examples/android-instrumentation-sample/src/main/AndroidManifest.xml index e849c17b..aac329eb 100644 --- a/examples/android-instrumentation-sample/src/main/AndroidManifest.xml +++ b/examples/android-instrumentation-sample/src/main/AndroidManifest.xml @@ -12,6 +12,11 @@ + + diff --git a/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt b/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt new file mode 100644 index 00000000..103c16f3 --- /dev/null +++ b/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt @@ -0,0 +1,83 @@ +package io.sentry.samples.instrumentation.ui + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicText +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController + +class ComposeActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + val navController = rememberNavController() + + NavHost( + navController = navController, + startDestination = Destination.Home.route + ) { + val pillShape = RoundedCornerShape(50) + + composable(Destination.Home.route) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + BasicText( + modifier = Modifier + .border(2.dp, Color.Gray, pillShape) + .clip(pillShape) + .clickable { + navController.navigate(Destination.Details.route) + } + .padding(24.dp), + text = "Home. Tap to go to Details." + ) + } + } + composable(Destination.Details.route) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + BasicText( + modifier = Modifier + .border(2.dp, Color.Gray, pillShape) + .clip(pillShape) + .clickable { + navController.popBackStack() + } + .padding(24.dp), + text = "Details. Tap or press back to return." + ) + } + } + } + } + } + + sealed class Destination( + val route: String + ) { + object Home : Destination("home") + object Details : Destination("details") + } +} diff --git a/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/MainActivity.kt b/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/MainActivity.kt index 3819b171..b98716fb 100644 --- a/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/MainActivity.kt +++ b/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/MainActivity.kt @@ -53,6 +53,10 @@ class MainActivity : ComponentActivity() { startActivity(Intent(this, EditActivity::class.java)) return@setOnMenuItemClickListener true } + if (it.itemId == R.id.action_compose) { + startActivity(Intent(this, ComposeActivity::class.java)) + return@setOnMenuItemClickListener true + } return@setOnMenuItemClickListener false } } diff --git a/examples/android-instrumentation-sample/src/main/res/menu/main.xml b/examples/android-instrumentation-sample/src/main/res/menu/main.xml index a3a9ce6d..7b7628c0 100644 --- a/examples/android-instrumentation-sample/src/main/res/menu/main.xml +++ b/examples/android-instrumentation-sample/src/main/res/menu/main.xml @@ -9,4 +9,11 @@ android:title="Add" app:showAsAction="ifRoom" tools:ignore="HardcodedText" /> + + diff --git a/plugin-build/build.gradle.kts b/plugin-build/build.gradle.kts index 7cb58507..e2635a43 100644 --- a/plugin-build/build.gradle.kts +++ b/plugin-build/build.gradle.kts @@ -76,14 +76,13 @@ tasks.withType().configureEach { } tasks.withType().configureEach { - sourceCompatibility = JavaVersion.VERSION_11.toString() - targetCompatibility = JavaVersion.VERSION_11.toString() classpath += files(sourceSets["main"].groovy.classesDirectory) kotlinOptions { jvmTarget = JavaVersion.VERSION_11.toString() freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=enable") languageVersion = "1.4" + apiVersion = "1.4" } } From 71199233c35a542db8df213f969b6994e2056c11 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Oct 2022 14:30:03 +0200 Subject: [PATCH 05/23] Fix wrong classname for NavHostController .compose.NavHostControllerKt contains an extension function for .NavHostController class --- .../instrumentation/androidx/compose/ComposeNavigation.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt index d7692f3f..cf232a7a 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt @@ -13,7 +13,7 @@ import org.objectweb.asm.commons.Method open class ComposeNavigation : ClassInstrumentable { companion object { - private const val NAV_HOST_CONTROLLER_CLASSNAME = "androidx.navigation.NavHostController" + private const val NAV_HOST_CONTROLLER_CLASSNAME = "androidx.navigation.compose.NavHostControllerKt" private const val REMEMBER_NAV_CONTROLLER_NAME = "rememberNavController" /* ktlint-disable max-line-length */ From cc886adea2117362d36da35da4702084d3ebf432 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 27 Oct 2022 14:52:18 +0200 Subject: [PATCH 06/23] Add Changelog for compose navigation instrumentation --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c66056fd..93cc4de3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Add auto-instrumentation for compose navigation ([#392](https://github.com/getsentry/sentry-android-gradle-plugin/pull/392)) + ### Fixes - Ignore minified classes from any instrumentation ([#389](https://github.com/getsentry/sentry-android-gradle-plugin/pull/389)) From f13c47cc16d5141bedf0c48cd3a262db2b9c53cd Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 31 Oct 2022 13:16:46 +0100 Subject: [PATCH 07/23] Revert to Kotlin 1.6.10 plugin version, adapt compose accordingly --- buildSrc/src/main/java/Dependencies.kt | 6 +++--- examples/android-instrumentation-sample/build.gradle.kts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index fb22c359..8f852a09 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -2,8 +2,8 @@ import org.gradle.util.VersionNumber object BuildPluginsVersion { val AGP = System.getenv("VERSION_AGP") ?: "7.3.0" - const val DOKKA = "1.7.20" - const val KOTLIN = "1.7.20" + const val DOKKA = "1.6.10" + const val KOTLIN = "1.6.10" const val AAR_2_JAR = "0.6" const val KTLINT = "10.2.1" // do not upgrade to 0.18.0, it does not generate the pom-default.xml and module.json under @@ -53,7 +53,7 @@ object Samples { const val lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" const val appcompat = "androidx.appcompat:appcompat:1.2.0" - const val composeRuntime = "androidx.compose.runtime:runtime:1.2.1" + const val composeRuntime = "androidx.compose.runtime:runtime:1.1.1" const val composeNavigation = "androidx.navigation:navigation-compose:2.5.2" const val composeActivity = "androidx.activity:activity-compose:1.4.0" const val composeFoundation = "androidx.compose.foundation:foundation:1.2.1" diff --git a/examples/android-instrumentation-sample/build.gradle.kts b/examples/android-instrumentation-sample/build.gradle.kts index 7683150e..4ddea1e2 100644 --- a/examples/android-instrumentation-sample/build.gradle.kts +++ b/examples/android-instrumentation-sample/build.gradle.kts @@ -48,7 +48,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = "1.3.2" + kotlinCompilerExtensionVersion = "1.1.1" } } From 1c8646fbf5a8067e35f2817cfe68d77d20e73d8a Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 31 Oct 2022 13:17:01 +0100 Subject: [PATCH 08/23] Fix compose artifact name --- .../src/main/kotlin/io/sentry/android/gradle/util/Versions.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8d3de2a9..ef4cd093 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 @@ -21,7 +21,7 @@ internal object SentryVersions { internal object SentryModules { internal const val SENTRY_ANDROID_CORE = "sentry-android-core" internal const val SENTRY_ANDROID_OKHTTP = "sentry-android-okhttp" - internal const val SENTRY_ANDROID_COMPOSE = "sentry-android-compose" + internal const val SENTRY_ANDROID_COMPOSE = "sentry-compose-android" } /** From 41d7e0040c18403e7324c6400656407a78ff093f Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 31 Oct 2022 13:17:40 +0100 Subject: [PATCH 09/23] Use CommonClassVisitor instead of custom impl --- .../androidx/compose/ComposeNavigation.kt | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt index cf232a7a..30390de9 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt @@ -2,6 +2,9 @@ package io.sentry.android.gradle.instrumentation.androidx.compose import com.android.build.api.instrumentation.ClassContext import io.sentry.android.gradle.instrumentation.ClassInstrumentable +import io.sentry.android.gradle.instrumentation.CommonClassVisitor +import io.sentry.android.gradle.instrumentation.MethodContext +import io.sentry.android.gradle.instrumentation.MethodInstrumentable import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory import io.sentry.android.gradle.instrumentation.wrap.Replacement import org.objectweb.asm.ClassVisitor @@ -13,11 +16,11 @@ import org.objectweb.asm.commons.Method open class ComposeNavigation : ClassInstrumentable { companion object { - private const val NAV_HOST_CONTROLLER_CLASSNAME = "androidx.navigation.compose.NavHostControllerKt" - private const val REMEMBER_NAV_CONTROLLER_NAME = "rememberNavController" + private const val NAV_HOST_CONTROLLER_CLASSNAME = + "androidx.navigation.compose.NavHostControllerKt" /* ktlint-disable max-line-length */ - val replacement = Replacement( + private val replacement = Replacement( "Lio/sentry/compose/SentryNavigationIntegrationKt;", "withSentryObservableEffect", "(Landroidx/navigation/NavHostController;Landroidx/compose/runtime/Composer;I)Landroidx/navigation/NavHostController;" @@ -31,21 +34,27 @@ open class ComposeNavigation : ClassInstrumentable { originalVisitor: ClassVisitor, parameters: SpanAddingClassVisitorFactory.SpanAddingParameters ): ClassVisitor { - return object : ClassVisitor(apiVersion, originalVisitor) { + return CommonClassVisitor( + apiVersion, + originalVisitor, + NAV_HOST_CONTROLLER_CLASSNAME, + listOf(object : MethodInstrumentable { - override fun visitMethod( - access: Int, - name: String?, - descriptor: String?, - signature: String?, - exceptions: Array?, - ): MethodVisitor { - val methodVisitor = - originalVisitor.visitMethod(access, name, descriptor, signature, exceptions) - - return if (name == REMEMBER_NAV_CONTROLLER_NAME) { - object : AdviceAdapter(apiVersion, methodVisitor, access, name, descriptor) { + override val fqName: String get() = "rememberNavController" + override fun getVisitor( + instrumentableContext: MethodContext, + apiVersion: Int, + originalVisitor: MethodVisitor, + parameters: SpanAddingClassVisitorFactory.SpanAddingParameters + ): MethodVisitor { + return object : AdviceAdapter( + apiVersion, + originalVisitor, + instrumentableContext.access, + instrumentableContext.name, + instrumentableContext.descriptor + ) { override fun onMethodExit(opcode: Int) { // NavHostController is the return value; // thus it's already on top of stack @@ -63,11 +72,10 @@ open class ComposeNavigation : ClassInstrumentable { super.onMethodExit(opcode) } } - } else { - methodVisitor } - } - } + }), + parameters + ) } override fun isInstrumentable(data: ClassContext): Boolean { From 47321b844cc50b2a48648c71aceb3b0931372f2e Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 31 Oct 2022 13:31:24 +0100 Subject: [PATCH 10/23] Extract method visitor to RememberNavControllerMethodVisitor class --- .../androidx/compose/ComposeNavigation.kt | 38 ++-------------- .../RememberNavControllerMethodVisitor.kt | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 34 deletions(-) create mode 100644 plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/visitor/RememberNavControllerMethodVisitor.kt diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt index 30390de9..3302d123 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/ComposeNavigation.kt @@ -6,26 +6,15 @@ import io.sentry.android.gradle.instrumentation.CommonClassVisitor import io.sentry.android.gradle.instrumentation.MethodContext import io.sentry.android.gradle.instrumentation.MethodInstrumentable import io.sentry.android.gradle.instrumentation.SpanAddingClassVisitorFactory -import io.sentry.android.gradle.instrumentation.wrap.Replacement +import io.sentry.android.gradle.instrumentation.androidx.compose.visitor.RememberNavControllerMethodVisitor import org.objectweb.asm.ClassVisitor import org.objectweb.asm.MethodVisitor -import org.objectweb.asm.Type -import org.objectweb.asm.commons.AdviceAdapter -import org.objectweb.asm.commons.Method open class ComposeNavigation : ClassInstrumentable { companion object { private const val NAV_HOST_CONTROLLER_CLASSNAME = "androidx.navigation.compose.NavHostControllerKt" - - /* ktlint-disable max-line-length */ - private val replacement = Replacement( - "Lio/sentry/compose/SentryNavigationIntegrationKt;", - "withSentryObservableEffect", - "(Landroidx/navigation/NavHostController;Landroidx/compose/runtime/Composer;I)Landroidx/navigation/NavHostController;" - ) - /* ktlint-enable max-line-length */ } override fun getVisitor( @@ -48,30 +37,11 @@ open class ComposeNavigation : ClassInstrumentable { originalVisitor: MethodVisitor, parameters: SpanAddingClassVisitorFactory.SpanAddingParameters ): MethodVisitor { - return object : AdviceAdapter( + return RememberNavControllerMethodVisitor( apiVersion, originalVisitor, - instrumentableContext.access, - instrumentableContext.name, - instrumentableContext.descriptor - ) { - override fun onMethodExit(opcode: Int) { - // NavHostController is the return value; - // thus it's already on top of stack - - // Composer $composer - loadArg(1) - - // int $changed - loadArg(2) - - invokeStatic( - Type.getType(replacement.owner), - Method(replacement.name, replacement.descriptor) - ) - super.onMethodExit(opcode) - } - } + instrumentableContext + ) } }), parameters diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/visitor/RememberNavControllerMethodVisitor.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/visitor/RememberNavControllerMethodVisitor.kt new file mode 100644 index 00000000..701d5a23 --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/androidx/compose/visitor/RememberNavControllerMethodVisitor.kt @@ -0,0 +1,45 @@ +package io.sentry.android.gradle.instrumentation.androidx.compose.visitor + +import io.sentry.android.gradle.instrumentation.MethodContext +import io.sentry.android.gradle.instrumentation.wrap.Replacement +import org.objectweb.asm.MethodVisitor +import org.objectweb.asm.Type +import org.objectweb.asm.commons.AdviceAdapter +import org.objectweb.asm.commons.Method + +class RememberNavControllerMethodVisitor( + apiVersion: Int, + originalVisitor: MethodVisitor, + instrumentableContext: MethodContext +) : AdviceAdapter( + apiVersion, + originalVisitor, + instrumentableContext.access, + instrumentableContext.name, + instrumentableContext.descriptor +) { + /* ktlint-disable max-line-length */ + private val replacement = Replacement( + "Lio/sentry/compose/SentryNavigationIntegrationKt;", + "withSentryObservableEffect", + "(Landroidx/navigation/NavHostController;Landroidx/compose/runtime/Composer;I)Landroidx/navigation/NavHostController;" + ) + /* ktlint-enable max-line-length */ + + override fun onMethodExit(opcode: Int) { + // NavHostController is the return value; + // thus it's already on top of stack + + // Composer $composer + loadArg(1) + + // int $changed + loadArg(2) + + invokeStatic( + Type.getType(replacement.owner), + Method(replacement.name, replacement.descriptor) + ) + super.onMethodExit(opcode) + } +} From 744bbc8548deb9cd2a36f44e2cefb2fe3aa93ebc Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 2 Nov 2022 14:20:28 +0100 Subject: [PATCH 11/23] Add tests for ComposeInstallStrategy --- .../compose/ComposeInstallStrategyTest.kt | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt new file mode 100644 index 00000000..a7cce78f --- /dev/null +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt @@ -0,0 +1,104 @@ +package io.sentry.android.gradle.autoinstall.compose + +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 ComposeInstallStrategyTest { + 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( + installCompose: Boolean = true, + composeVersion: String = "1.0.0" + ): ComposeInstallStrategy { + val id = mock { + whenever(it.version).doReturn(composeVersion) + } + whenever(metadataDetails.id).thenReturn(id) + + with(AutoInstallState.getInstance()) { + this.installCompose = installCompose + this.sentryVersion = "5.6.1" + } + return ComposeInstallStrategyImpl(logger) + } + } + + private val fixture = Fixture() + + @Test + fun `when sentry-compose-android is a direct dependency logs a message and does nothing`() { + val sut = fixture.getSut(installCompose = false) + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-compose-android won't be installed because it was already " + + "installed directly" + } + verify(fixture.metadataContext, never()).details + } + + @Test + fun `when sentry version is unsupported logs a message and does nothing`() { + val sut = fixture.getSut(composeVersion = "0.9.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-compose-android won't be installed because the current " + + "version is lower than the minimum supported version (1.0.0)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `installs sentry-android-compose with info message`() { + val sut = fixture.getSut() + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-compose-android was successfully installed with version: 5.6.1" + } + verify(fixture.dependencies).add( + check { + assertEquals("io.sentry:sentry-compose-android:5.6.1", it) + } + ) + } + + private class ComposeInstallStrategyImpl(logger: Logger) : ComposeInstallStrategy(logger) +} From 79c4da6b0c3e0529a259c589a0a0d1083e9dcb36 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 2 Nov 2022 14:21:01 +0100 Subject: [PATCH 12/23] Remove unused import --- .../java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt b/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt index 103c16f3..c61b7942 100644 --- a/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt +++ b/examples/android-instrumentation-sample/src/main/java/io/sentry/samples/instrumentation/ui/ComposeActivity.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable From 8d20d1e9a6fd4d0ca9f25a1226dcf511513ea06d Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 3 Nov 2022 09:14:54 +0100 Subject: [PATCH 13/23] Fix tests related to instrumentation --- .../instrumentation/ChainedInstrumentable.kt | 5 ++ .../SpanAddingClassVisitorFactory.kt | 5 +- .../io/sentry/android/gradle/util/Versions.kt | 2 +- .../sentry/android/gradle/SentryPluginTest.kt | 79 ++++++++++++++----- 4 files changed, 68 insertions(+), 23 deletions(-) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/ChainedInstrumentable.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/ChainedInstrumentable.kt index 926a19b6..1ff8d868 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/ChainedInstrumentable.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/instrumentation/ChainedInstrumentable.kt @@ -40,4 +40,9 @@ class ChainedInstrumentable( override fun isInstrumentable(data: ClassContext): Boolean = instrumentables.any { it.isInstrumentable(data) } + + override fun toString(): String { + return "ChainedInstrumentable(instrumentables=" + + "${instrumentables.joinToString(", ") { it.javaClass.simpleName }})" + } } 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 102e39a7..eafe3a0d 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 @@ -20,7 +20,6 @@ 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.debug import io.sentry.android.gradle.util.info import java.io.File import org.gradle.api.provider.Property @@ -65,8 +64,8 @@ abstract class SpanAddingClassVisitorFactory : get() { val memoized = parameters.get()._instrumentable if (memoized != null) { - SentryPlugin.logger.debug { - "Memoized: $memoized" + SentryPlugin.logger.info { + "Instrumentable: $memoized [Memoized]" } return memoized } 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 ef4cd093..4d6fdff7 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 @@ -15,7 +15,7 @@ internal object SentryVersions { internal val VERSION_PERFORMANCE = SemVer(4, 0, 0) internal val VERSION_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_COMPOSE = SemVer(6, 6, 0) } internal object SentryModules { diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt index 3c6fa79e..72e1ea15 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt @@ -181,12 +181,12 @@ class SentryPluginTest( applyTracingInstrumentation(features = setOf(InstrumentationFeature.DATABASE)) val build = runner - .appendArguments(":app:assembleDebug", "--debug") + .appendArguments(":app:assembleDebug", "--info") .build() assertTrue { - "[sentry] Instrumentables: AndroidXSQLiteDatabase, AndroidXSQLiteStatement," + - " AndroidXRoomDao" in build.output + "[sentry] Instrumentable: ChainedInstrumentable(instrumentables=" + + "AndroidXSQLiteDatabase, AndroidXSQLiteStatement, AndroidXRoomDao)" in build.output } } @@ -195,27 +195,71 @@ class SentryPluginTest( applyTracingInstrumentation(features = setOf(InstrumentationFeature.FILE_IO)) val build = runner - .appendArguments(":app:assembleDebug", "--debug") + .appendArguments(":app:assembleDebug", "--info") .build() assertTrue { - "[sentry] Instrumentables: ChainedInstrumentable" in build.output + "[sentry] Instrumentable: ChainedInstrumentable(instrumentables=" + + "WrappingInstrumentable, RemappingInstrumentable)" in build.output } } @Test - fun `applies all instrumentables when all features enabled`() { + fun `applies only Compose instrumentable when only Compose feature enabled`() { applyTracingInstrumentation( - features = setOf(InstrumentationFeature.DATABASE, InstrumentationFeature.FILE_IO) + features = setOf(InstrumentationFeature.COMPOSE), + dependencies = setOf( + "androidx.compose.runtime:runtime:1.1.0" + ) ) val build = runner - .appendArguments(":app:assembleDebug", "--debug") + .appendArguments(":app:assembleDebug", "--info") + .build() + assertTrue { + "[sentry] Instrumentable: ChainedInstrumentable(instrumentables=" + + "ComposeNavigation)" in build.output + } + } + + @Test + fun `does not apply Compose instrumentable when app does not depend on compose (runtime)`() { + applyTracingInstrumentation( + features = setOf(InstrumentationFeature.COMPOSE) + ) + + val build = runner + .appendArguments(":app:assembleDebug", "--info") + .build() + assertTrue { + "[sentry] Instrumentable: ChainedInstrumentable(instrumentables=)" in build.output + } + } + + @Test + fun `applies all instrumentables when all features are enabled`() { + applyTracingInstrumentation( + features = setOf( + InstrumentationFeature.DATABASE, + InstrumentationFeature.FILE_IO, + InstrumentationFeature.OKHTTP, + InstrumentationFeature.COMPOSE + ), + dependencies = setOf( + "com.squareup.okhttp3:okhttp:3.14.9", + "io.sentry:sentry-android-okhttp:6.6.0", + "androidx.compose.runtime:runtime:1.0.0" + ) + ) + val build = runner + .appendArguments(":app:assembleDebug", "--info") .build() assertTrue { - "[sentry] Instrumentables: AndroidXSQLiteDatabase, AndroidXSQLiteStatement," + - " AndroidXRoomDao, ChainedInstrumentable" in build.output + "[sentry] Instrumentable: ChainedInstrumentable(instrumentables=" + + "AndroidXSQLiteDatabase, AndroidXSQLiteStatement, AndroidXRoomDao, OkHttp, " + + "WrappingInstrumentable, RemappingInstrumentable, " + + "ComposeNavigation)" in build.output } } @@ -228,7 +272,7 @@ class SentryPluginTest( dependencies { implementation 'com.squareup.okhttp3:okhttp:3.14.9' - implementation 'io.sentry:sentry-android-okhttp:5.5.0' + implementation 'io.sentry:sentry-android-okhttp:6.6.0' } """.trimIndent() ) @@ -276,14 +320,16 @@ class SentryPluginTest( private fun applyTracingInstrumentation( tracingInstrumentation: Boolean = true, - features: Set = setOf(), + features: Set = emptySet(), + dependencies: Set = emptySet(), debug: Boolean = false ) { appBuildFile.appendText( // language=Groovy """ dependencies { - implementation 'io.sentry:sentry-android:5.5.0' + implementation 'io.sentry:sentry-android:6.6.0' + ${dependencies.joinToString("\n") { "implementation '$it'" }} } sentry { @@ -292,12 +338,7 @@ class SentryPluginTest( forceInstrumentDependencies = true enabled = $tracingInstrumentation debug = $debug - features = ${ - features.joinToString( - prefix = "[", - postfix = "]" - ) { "${it::class.java.canonicalName}.${it.name}" } - } + features = [${features.joinToString { "${it::class.java.canonicalName}.${it.name}" }}] } } """.trimIndent() From f8ccb9941643a9da3a22ecf2ea0db2e199a42d87 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 3 Nov 2022 10:36:03 +0100 Subject: [PATCH 14/23] Update Changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c703e1c..6d8ac41c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,16 @@ # Changelog -## 3.2.1 +## Unreleased ### Features -- Populate events with dependencies metadata ([#396](https://github.com/getsentry/sentry-android-gradle-plugin/pull/396)) +- Add auto-instrumentation for compose navigation ([#392](https://github.com/getsentry/sentry-android-gradle-plugin/pull/392)) + +## 3.2.1 ### Features -- Add auto-instrumentation for compose navigation ([#392](https://github.com/getsentry/sentry-android-gradle-plugin/pull/392)) +- Populate events with dependencies metadata ([#396](https://github.com/getsentry/sentry-android-gradle-plugin/pull/396)) ### Fixes From c1f6de63c0585286156b20d20e56d62a179f0815 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 3 Nov 2022 13:40:48 +0100 Subject: [PATCH 15/23] Push Sentry plugin-build dependency to 6.6.0 Replace testRuntimeOnly with testImplementationAar as otherwise the Gradle sync fails with the following error: - Incompatible because this component declares an API of a component, with the library elements 'aar' and the consumer needed a runtime of a component, packaged as a jar --- buildSrc/src/main/java/Dependencies.kt | 2 +- plugin-build/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 04b75336..4121e28a 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -27,7 +27,7 @@ object LibsVersion { const val JUNIT = "4.13.2" const val ASM = "7.0" // 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 = "5.5.0" + const val SENTRY = "6.6.0" } object Libs { diff --git a/plugin-build/build.gradle.kts b/plugin-build/build.gradle.kts index d9691ec0..121fe015 100644 --- a/plugin-build/build.gradle.kts +++ b/plugin-build/build.gradle.kts @@ -51,7 +51,7 @@ dependencies { testImplementationAar(Libs.SQLITE) testImplementationAar(Libs.SQLITE_FRAMEWORK) testRuntimeOnly(files(androidSdkPath)) - testRuntimeOnly(Libs.SENTRY_ANDROID) + testImplementationAar(Libs.SENTRY_ANDROID) testRuntimeOnly( files( From 1cb1eb26ed0627208953d3aeb234780dcf6d4df4 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 3 Nov 2022 13:42:41 +0100 Subject: [PATCH 16/23] Add missing compose dependencies to instrumentation feature test --- .../kotlin/io/sentry/android/gradle/SentryPluginTest.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt index 15497611..f0d1cd2e 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt @@ -210,7 +210,8 @@ class SentryPluginTest( applyTracingInstrumentation( features = setOf(InstrumentationFeature.COMPOSE), dependencies = setOf( - "androidx.compose.runtime:runtime:1.1.0" + "androidx.compose.runtime:runtime:1.1.0", + "io.sentry:sentry-compose-android:6.6.0" ) ) @@ -249,7 +250,8 @@ class SentryPluginTest( dependencies = setOf( "com.squareup.okhttp3:okhttp:3.14.9", "io.sentry:sentry-android-okhttp:6.6.0", - "androidx.compose.runtime:runtime:1.0.0" + "androidx.compose.runtime:runtime:1.1.0", + "io.sentry:sentry-compose-android:6.6.0" ) ) val build = runner From b97da5d3e85ca177b6c0433ffc44440a0e223985 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Fri, 4 Nov 2022 12:39:48 +0100 Subject: [PATCH 17/23] Ensure integrations are only added for supported sentry versions as well E.g. the compose integration requires both a specific androidx runtime version as well as sentry SDK version --- .../autoinstall/AbstractInstallStrategy.kt | 29 +++++-- .../compose/ComposeInstallStrategy.kt | 15 ++-- .../fragment/FragmentInstallStrategy.kt | 2 +- .../okhttp/OkHttpInstallStrategy.kt | 6 +- .../timber/TimberInstallStrategy.kt | 4 +- .../gradle/SentryPluginAutoInstallTest.kt | 85 ++++++++++++++----- 6 files changed, 101 insertions(+), 40 deletions(-) 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 06e6101d..12c86193 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 @@ -11,25 +11,36 @@ abstract class AbstractInstallStrategy : ComponentMetadataRule { protected lateinit var logger: Logger - protected abstract val moduleId: String + protected abstract val sentryModuleId: String protected abstract val shouldInstallModule: Boolean - protected open val minSupportedVersion: SemVer = SemVer(0, 0, 0) + protected open val minSupportedThirdPartyVersion: SemVer = SemVer(0, 0, 0) + + protected open val minSupportedSentryVersion: SemVer = SemVer(0, 0, 0) override fun execute(context: ComponentMetadataContext) { val autoInstallState = AutoInstallState.getInstance() if (!shouldInstallModule) { logger.info { - "$moduleId won't be installed because it was already installed directly" + "$sentryModuleId won't be installed because it was already installed directly" + } + return + } + val thirdPartySemVersion = SemVer.parse(context.details.id.version) + if (thirdPartySemVersion < minSupportedThirdPartyVersion) { + logger.warn { + "$sentryModuleId won't be installed because the current version is " + + "lower than the minimum supported version ($minSupportedThirdPartyVersion)" } return } - val semVer = SemVer.parse(context.details.id.version) - if (semVer < minSupportedVersion) { + + val sentrySemVersion = SemVer.parse(autoInstallState.sentryVersion) + if (sentrySemVersion < minSupportedSentryVersion) { logger.warn { - "$moduleId won't be installed because the current version is " + - "lower than the minimum supported version ($minSupportedVersion)" + "$sentryModuleId won't be installed because the current version is lower than " + + "the minimum supported sentry version ($autoInstallState.sentryVersion)" } return } @@ -37,10 +48,10 @@ abstract class AbstractInstallStrategy : ComponentMetadataRule { context.details.allVariants { metadata -> metadata.withDependencies { dependencies -> val sentryVersion = autoInstallState.sentryVersion - dependencies.add("$SENTRY_GROUP:$moduleId:$sentryVersion") + dependencies.add("$SENTRY_GROUP:$sentryModuleId:$sentryVersion") logger.info { - "$moduleId was successfully installed with version: $sentryVersion" + "$sentryModuleId was successfully installed with version: $sentryVersion" } } } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt index 8fa824c4..c86c98b1 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt @@ -19,21 +19,24 @@ abstract class ComposeInstallStrategy : AbstractInstallStrategy { @Inject // inject is needed to avoid Gradle error constructor() : this(SentryPlugin.logger) - override val moduleId: String get() = SENTRY_COMPOSE_ID + override val sentryModuleId: String get() = SENTRY_COMPOSE_ID override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installCompose - override val minSupportedVersion: SemVer get() = MIN_SUPPORTED_VERSION + // TODO switch to 6.7.0 once released + override val minSupportedSentryVersion: SemVer + get() = SemVer(6, 6, 0) + + override val minSupportedThirdPartyVersion: SemVer + get() = SemVer(1, 0, 0) companion object Registrar : InstallStrategyRegistrar { - private const val COMPOSE_GROUP = "androidx.compose.runtime" - private const val COMPOSE_ID = "runtime" + internal const val SENTRY_COMPOSE_ID = "sentry-compose-android" - private val MIN_SUPPORTED_VERSION = SemVer(1, 0, 0) override fun register(component: ComponentMetadataHandler) { component.withModule( - "$COMPOSE_GROUP:$COMPOSE_ID", + "androidx.compose.runtime:runtime", ComposeInstallStrategy::class.java ) {} } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt index 122d4c82..c194b440 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt @@ -19,7 +19,7 @@ abstract class FragmentInstallStrategy : AbstractInstallStrategy { @Inject // inject is needed to avoid Gradle error constructor() : this(SentryPlugin.logger) - override val moduleId: String get() = SENTRY_FRAGMENT_ID + override val sentryModuleId: String get() = SENTRY_FRAGMENT_ID override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installFragment 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 87c98be3..5960e70d 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 @@ -20,11 +20,13 @@ abstract class OkHttpInstallStrategy : AbstractInstallStrategy { @Inject // inject is needed to avoid Gradle error constructor() : this(SentryPlugin.logger) - override val moduleId: String get() = SENTRY_OKHTTP_ID + override val sentryModuleId: String get() = SENTRY_OKHTTP_ID override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installOkHttp - override val minSupportedVersion: SemVer get() = MIN_SUPPORTED_VERSION + override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION + + override val minSupportedSentryVersion: SemVer get() = SemVer(4, 4, 0) companion object Registrar : InstallStrategyRegistrar { private const val OKHTTP_GROUP = "com.squareup.okhttp3" diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt index 12ea60a5..c250cd52 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt @@ -20,11 +20,11 @@ abstract class TimberInstallStrategy : AbstractInstallStrategy { @Inject // inject is needed to avoid Gradle error constructor() : this(SentryPlugin.logger) - override val moduleId: String get() = SENTRY_TIMBER_ID + override val sentryModuleId: String get() = SENTRY_TIMBER_ID override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installTimber - override val minSupportedVersion: SemVer get() = MIN_SUPPORTED_VERSION + override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION companion object Registrar : InstallStrategyRegistrar { private const val TIMBER_GROUP = "com.jakewharton.timber" diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt index 382be5ed..2760feb7 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt @@ -25,11 +25,7 @@ class SentryPluginAutoInstallTest( """.trimIndent() ) - val result = runner - .appendArguments("app:dependencies") - .appendArguments("--configuration") - .appendArguments("debugRuntimeClasspath") - .build() + val result = runListDependenciesTask() assertTrue { "io.sentry:sentry-android:$SENTRY_SDK_VERSION" in result.output } @@ -56,16 +52,16 @@ class SentryPluginAutoInstallTest( """.trimIndent() ) - val result = runner - .appendArguments("app:dependencies") - .appendArguments("--configuration") - .appendArguments("debugRuntimeClasspath") - .build() + val result = runListDependenciesTask() assertFalse { "io.sentry:sentry-android:5.1.0" in result.output } assertTrue { "io.sentry:sentry-android-timber:5.1.0" in result.output } assertTrue { "io.sentry:sentry-android-fragment:5.1.0" in result.output } assertFalse { "io.sentry:sentry-android-okhttp:5.1.0" in result.output } assertTrue { "io.sentry:sentry-android-okhttp:5.4.0" in result.output } + assertFalse { "io.sentry:sentry-compose-android:5.1.0" in result.output } + + // ensure all dependencies could be resolved + assertFalse { "FAILED" in result.output } } @Test @@ -84,15 +80,14 @@ class SentryPluginAutoInstallTest( """.trimIndent() ) - val result = runner - .appendArguments("app:dependencies") - .appendArguments("--configuration") - .appendArguments("debugRuntimeClasspath") - .build() + val result = runListDependenciesTask() assertFalse { "io.sentry:sentry-android:$SENTRY_SDK_VERSION" in result.output } assertFalse { "io.sentry:sentry-android-timber:$SENTRY_SDK_VERSION" in result.output } assertFalse { "io.sentry:sentry-android-fragment:$SENTRY_SDK_VERSION" in result.output } assertFalse { "io.sentry:sentry-android-okhttp:$SENTRY_SDK_VERSION" in result.output } + + // ensure all dependencies could be resolved + assertFalse { "FAILED" in result.output } } @Test @@ -113,14 +108,64 @@ class SentryPluginAutoInstallTest( """.trimIndent() ) - val result = runner - .appendArguments("app:dependencies") - .appendArguments("--configuration") - .appendArguments("debugRuntimeClasspath") - .build() + val result = runListDependenciesTask() + assertTrue { "io.sentry:sentry-android:5.1.2" in result.output } assertTrue { "io.sentry:sentry-android-timber:5.1.2" in result.output } assertTrue { "io.sentry:sentry-android-okhttp:5.1.2" in result.output } assertTrue { "io.sentry:sentry-android-fragment:5.4.0" in result.output } + + // ensure all dependencies could be resolved + assertFalse { "FAILED" in result.output } } + + @Test + fun `compose is not added for lower sentry versions`() { + appBuildFile.appendText( + // language=Groovy + """ + dependencies { + implementation 'androidx.compose.runtime:runtime:1.1.1' + } + + sentry.autoInstallation.enabled = true + sentry.autoInstallation.sentryVersion = "6.5.0" + sentry.includeProguardMapping = false + """.trimIndent() + ) + + val result = runListDependenciesTask() + + assertFalse { "io.sentry:sentry-compose-android:6.5.0" in result.output } + assertFalse { "FAILED" in result.output } + } + + @Test + fun `compose is added with when compose and sentry versions match`() { + // TODO switch to 6.7.0 once released + appBuildFile.appendText( + // language=Groovy + """ + dependencies { + implementation 'androidx.compose.runtime:runtime:1.1.1' + } + + sentry.autoInstallation.enabled = true + sentry.autoInstallation.sentryVersion = "6.6.0" + sentry.includeProguardMapping = false + """.trimIndent() + ) + + val result = runListDependenciesTask() + + assertTrue { "io.sentry:sentry-compose-android:6.6.0" in result.output } + // ensure all dependencies could be resolved + assertFalse { "FAILED" in result.output } + } + + private fun runListDependenciesTask() = runner + .appendArguments("app:dependencies") + .appendArguments("--configuration") + .appendArguments("debugRuntimeClasspath") + .build() } From da1954d1b7978fa760dcff76a7158dbeac31152d Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Fri, 4 Nov 2022 12:53:09 +0100 Subject: [PATCH 18/23] Adapt to latest sentry 6.7.0 release --- .../kotlin/io/sentry/android/gradle/SentryPlugin.kt | 2 +- .../autoinstall/compose/ComposeInstallStrategy.kt | 3 +-- .../kotlin/io/sentry/android/gradle/util/Versions.kt | 2 +- .../android/gradle/SentryPluginAutoInstallTest.kt | 11 +++++------ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt index f3296655..d39af026 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/SentryPlugin.kt @@ -426,7 +426,7 @@ class SentryPlugin : Plugin { companion object { const val SENTRY_ORG_PARAMETER = "sentryOrg" const val SENTRY_PROJECT_PARAMETER = "sentryProject" - internal const val SENTRY_SDK_VERSION = "6.6.0" + internal const val SENTRY_SDK_VERSION = "6.7.0" internal const val SENTRY_DEPENDENCIES_REPORT_OUTPUT = "sentry-external-modules.txt" internal val sep = File.separator diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt index c86c98b1..dd634326 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategy.kt @@ -23,9 +23,8 @@ abstract class ComposeInstallStrategy : AbstractInstallStrategy { override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installCompose - // TODO switch to 6.7.0 once released override val minSupportedSentryVersion: SemVer - get() = SemVer(6, 6, 0) + get() = SemVer(6, 7, 0) override val minSupportedThirdPartyVersion: SemVer get() = SemVer(1, 0, 0) 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 be281d49..fd297f7e 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 @@ -21,7 +21,7 @@ internal object SentryVersions { internal val VERSION_PERFORMANCE = SemVer(4, 0, 0) internal val VERSION_OKHTTP = SemVer(5, 0, 0) internal val VERSION_FILE_IO = SemVer(5, 5, 0) - internal val VERSION_COMPOSE = SemVer(6, 6, 0) + internal val VERSION_COMPOSE = SemVer(6, 7, 0) } internal object SentryModules { diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt index 2760feb7..0a1fd8be 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginAutoInstallTest.kt @@ -129,20 +129,19 @@ class SentryPluginAutoInstallTest( } sentry.autoInstallation.enabled = true - sentry.autoInstallation.sentryVersion = "6.5.0" + sentry.autoInstallation.sentryVersion = "6.6.0" sentry.includeProguardMapping = false """.trimIndent() ) val result = runListDependenciesTask() - assertFalse { "io.sentry:sentry-compose-android:6.5.0" in result.output } + assertFalse { "io.sentry:sentry-compose-android:6.6.0" in result.output } assertFalse { "FAILED" in result.output } } @Test - fun `compose is added with when compose and sentry versions match`() { - // TODO switch to 6.7.0 once released + fun `compose is added with when sentry version 6_7_0 or above is used`() { appBuildFile.appendText( // language=Groovy """ @@ -151,14 +150,14 @@ class SentryPluginAutoInstallTest( } sentry.autoInstallation.enabled = true - sentry.autoInstallation.sentryVersion = "6.6.0" + sentry.autoInstallation.sentryVersion = "6.7.0" sentry.includeProguardMapping = false """.trimIndent() ) val result = runListDependenciesTask() - assertTrue { "io.sentry:sentry-compose-android:6.6.0" in result.output } + assertTrue { "io.sentry:sentry-compose-android:6.7.0" in result.output } // ensure all dependencies could be resolved assertFalse { "FAILED" in result.output } } From 2acf02250513bdf8073bf261071b9b655c669f6d Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Fri, 4 Nov 2022 13:02:10 +0100 Subject: [PATCH 19/23] Add min supported versions for timer and fragment integrations --- .../gradle/autoinstall/fragment/FragmentInstallStrategy.kt | 3 +++ .../android/gradle/autoinstall/timber/TimberInstallStrategy.kt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt index c194b440..3db2c84a 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/fragment/FragmentInstallStrategy.kt @@ -4,6 +4,7 @@ import io.sentry.android.gradle.SentryPlugin import io.sentry.android.gradle.autoinstall.AbstractInstallStrategy import io.sentry.android.gradle.autoinstall.AutoInstallState 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 @@ -23,6 +24,8 @@ abstract class FragmentInstallStrategy : AbstractInstallStrategy { override val shouldInstallModule: Boolean get() = AutoInstallState.getInstance().installFragment + override val minSupportedSentryVersion: SemVer get() = SemVer(5, 1, 0) + companion object Registrar : InstallStrategyRegistrar { private const val FRAGMENT_GROUP = "androidx.fragment" private const val FRAGMENT_ID = "fragment" diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt index c250cd52..8b4a3ebb 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/timber/TimberInstallStrategy.kt @@ -26,6 +26,8 @@ abstract class TimberInstallStrategy : AbstractInstallStrategy { override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION + override val minSupportedSentryVersion: SemVer get() = SemVer(3, 0, 0) + companion object Registrar : InstallStrategyRegistrar { private const val TIMBER_GROUP = "com.jakewharton.timber" private const val TIMBER_ID = "timber" From abe38517972e0d8d42ddd2600f87674c2ec17a85 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 7 Nov 2022 07:18:27 +0100 Subject: [PATCH 20/23] Fix Changelog --- CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15f4bab2..a3b59efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Features +- Populate events with dependencies metadata ([#396](https://github.com/getsentry/sentry-android-gradle-plugin/pull/396)) - Add auto-instrumentation for compose navigation ([#392](https://github.com/getsentry/sentry-android-gradle-plugin/pull/392)) ### Dependencies @@ -14,10 +15,6 @@ ## 3.2.1 -### Features - -- Populate events with dependencies metadata ([#396](https://github.com/getsentry/sentry-android-gradle-plugin/pull/396)) - ### Fixes - Ignore minified classes from any instrumentation ([#389](https://github.com/getsentry/sentry-android-gradle-plugin/pull/389)) From 94887e7d28214a16ef3b98f6568ca8b92a37ace0 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 7 Nov 2022 12:58:36 +0100 Subject: [PATCH 21/23] Fix non-semantic SDK versions can not be evaluated for auto-install --- .../autoinstall/AbstractInstallStrategy.kt | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) 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 12c86193..b89d626a 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 @@ -36,13 +36,25 @@ abstract class AbstractInstallStrategy : ComponentMetadataRule { return } - 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)" + if (minSupportedSentryVersion.major > 0) { + try { + 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)" + } + 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 } - return } context.details.allVariants { metadata -> From 29bd2d30ccf88cdf7042d9e3d38eec25521f42cd Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 7 Nov 2022 14:11:31 +0100 Subject: [PATCH 22/23] Update tests to use latest compose-ready sentry version --- .../test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt index f0d1cd2e..e6825290 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/SentryPluginTest.kt @@ -211,7 +211,7 @@ class SentryPluginTest( features = setOf(InstrumentationFeature.COMPOSE), dependencies = setOf( "androidx.compose.runtime:runtime:1.1.0", - "io.sentry:sentry-compose-android:6.6.0" + "io.sentry:sentry-compose-android:6.7.0" ) ) @@ -251,7 +251,7 @@ class SentryPluginTest( "com.squareup.okhttp3:okhttp:3.14.9", "io.sentry:sentry-android-okhttp:6.6.0", "androidx.compose.runtime:runtime:1.1.0", - "io.sentry:sentry-compose-android:6.6.0" + "io.sentry:sentry-compose-android:6.7.0" ) ) val build = runner From 708c4773fa89ffe48742f1afa860d875d6c0b61f Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 7 Nov 2022 15:03:50 +0100 Subject: [PATCH 23/23] Fix use latest sentry sdk version for compose --- .../autoinstall/compose/ComposeInstallStrategyTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt index a7cce78f..333cf965 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/compose/ComposeInstallStrategyTest.kt @@ -50,7 +50,7 @@ class ComposeInstallStrategyTest { with(AutoInstallState.getInstance()) { this.installCompose = installCompose - this.sentryVersion = "5.6.1" + this.sentryVersion = "6.7.0" } return ComposeInstallStrategyImpl(logger) } @@ -91,11 +91,11 @@ class ComposeInstallStrategyTest { assertTrue { fixture.logger.capturedMessage == - "[sentry] sentry-compose-android was successfully installed with version: 5.6.1" + "[sentry] sentry-compose-android was successfully installed with version: 6.7.0" } verify(fixture.dependencies).add( check { - assertEquals("io.sentry:sentry-compose-android:5.6.1", it) + assertEquals("io.sentry:sentry-compose-android:6.7.0", it) } ) }