diff --git a/CHANGELOG.md b/CHANGELOG.md index a18301c31..58334aa9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog +## 5.12.2 + +### Fixes + +- Fix compatibility with AGP 9.x when uploading proguard mappings ([#1021](https://github.com/getsentry/sentry-android-gradle-plugin/pull/1021)) + +## 5.12.1 + +### Fixes + +- Fix `Modifier.sentryTag()` not found warning ([#997](https://github.com/getsentry/sentry-android-gradle-plugin/pull/997)) + +## 5.12.0 + +### Dependencies + +- Bump Android SDK from v8.21.1 to v8.22.0 ([#989](https://github.com/getsentry/sentry-android-gradle-plugin/pull/989)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#8220) + - [diff](https://github.com/getsentry/sentry-java/compare/8.21.1...8.22.0) + +## 5.11.0 + +### Features + +- Auto install Spring Boot 4 (`sentry-spring-boot-4`) and Spring 7 (`sentry-spring-7`) modules ([#980](https://github.com/getsentry/sentry-android-gradle-plugin/pull/980)) +- Include version in dependency auto install messages ([#979](https://github.com/getsentry/sentry-android-gradle-plugin/pull/979)) + +### Fixes + +- Sentry dependencies intended for Spring Boot 3 / Spring 6 will no longer be installed for Spring Boot 4 / Spring 7 ([#980](https://github.com/getsentry/sentry-android-gradle-plugin/pull/980)) + +### Dependencies + +- Bump Android SDK from v8.20.0 to v8.21.1 ([#981](https://github.com/getsentry/sentry-android-gradle-plugin/pull/981)) + - [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#8211) + - [diff](https://github.com/getsentry/sentry-java/compare/8.20.0...8.21.1) + ## 5.10.0 ### Dependencies diff --git a/build.gradle.kts b/build.gradle.kts index b16aba889..07e107157 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,9 @@ +buildscript { + dependencies { + classpath("com.android.tools:r8:8.11.18") + } +} + plugins { alias(libs.plugins.kotlin) apply false alias(libs.plugins.kotlinAndroid) apply false diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 0e88519c9..fa4a05d49 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -9,7 +9,7 @@ object BuildPluginsVersion { } object LibsVersion { - const val SDK_VERSION = 33 + const val SDK_VERSION = 34 const val MIN_SDK_VERSION = 21 } diff --git a/examples/android-instrumentation-sample/build.gradle.kts b/examples/android-instrumentation-sample/build.gradle.kts index 18be73027..225173c23 100644 --- a/examples/android-instrumentation-sample/build.gradle.kts +++ b/examples/android-instrumentation-sample/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.kotlinAndroid) alias(libs.plugins.kapt) id("io.sentry.android.gradle") + id("io.sentry.kotlin.compiler.gradle") } // useful for local debugging of the androidx.sqlite lib 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 c61b7942c..8671c6200 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 @@ -11,72 +11,77 @@ 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.runtime.Composable 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.unit.dp +import androidx.navigation.NavController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import io.sentry.samples.instrumentation.ui.ComposeActivity.Destination class ComposeActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContent { - val navController = rememberNavController() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + val navController = rememberNavController() - NavHost( - navController = navController, - startDestination = Destination.Home.route - ) { - val pillShape = RoundedCornerShape(50) + 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." - ) - } - } - } + composable(Destination.Home.route) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + HomeText(navController, pillShape) + } } + composable(Destination.Details.route) { + Column( + modifier = Modifier.fillMaxSize(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + DetailsText(navController, pillShape) + } + } + } } + } - sealed class Destination( - val route: String - ) { - object Home : Destination("home") - object Details : Destination("details") - } + sealed class Destination(val route: String) { + object Home : Destination("home") + + object Details : Destination("details") + } +} + +@Composable +fun HomeText(navController: NavController, pillShape: RoundedCornerShape) { + 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 +fun DetailsText(navController: NavController, pillShape: RoundedCornerShape) { + 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.", + ) } 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 36b1c221a..c53736484 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 @@ -12,53 +12,53 @@ import io.sentry.SpanStatus import io.sentry.TransactionOptions import io.sentry.samples.instrumentation.R import io.sentry.samples.instrumentation.SampleApp -import io.sentry.samples.instrumentation.network.TrackService import io.sentry.samples.instrumentation.ui.list.TrackAdapter -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.withContext class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) - val list = findViewById(R.id.list) - list.layoutManager = LinearLayoutManager(this) - list.adapter = TrackAdapter() + val list = findViewById(R.id.list) + list.layoutManager = LinearLayoutManager(this) + list.adapter = TrackAdapter() - lifecycleScope.launchWhenStarted { - Sentry.getSpan()?.finish() - val transaction = Sentry.startTransaction( - "Track Interaction", - "ui.action.load", - TransactionOptions().apply { isBindToScope = true } - ) - SampleApp.database.tracksDao() - .all() - .map { - val remote = withContext(Dispatchers.IO) { - TrackService.instance.tracks("6188aa82-3102-436a-9a68-513e6ad9efcb") - } - remote + it - } - .collect { - (list.adapter as TrackAdapter).populate(it) - transaction.finish(SpanStatus.OK) - } + lifecycleScope.launchWhenStarted { + Sentry.getSpan()?.finish() + val transaction = + Sentry.startTransaction( + "Track Interaction", + "ui.action.load", + TransactionOptions().apply { isBindToScope = true }, + ) + SampleApp.database + .tracksDao() + .all() + // TODO: this service doesn't work anymore, need to find a replacement + // .map { + // val remote = + // withContext(Dispatchers.IO) { + // TrackService.instance.tracks("6188aa82-3102-436a-9a68-513e6ad9efcb") + // } + // remote + it + // } + .collect { + (list.adapter as TrackAdapter).populate(it) + transaction.finish(SpanStatus.OK) } + } - findViewById(R.id.toolbar).setOnMenuItemClickListener { - if (it.itemId == R.id.action_add) { - 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 - } + findViewById(R.id.toolbar).setOnMenuItemClickListener { + if (it.itemId == R.id.action_add) { + 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/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7972d02f7..3d88d2894 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -65,11 +65,11 @@ sample-androidx-recyclerView = "androidx.recyclerview:recyclerview:1.2.0" sample-androidx-lifecycle = "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" sample-androidx-appcompat = "androidx.appcompat:appcompat:1.2.0" -sample-androidx-composeRuntime = "androidx.compose.runtime:runtime:1.1.1" +sample-androidx-composeRuntime = "androidx.compose.runtime:runtime:1.5.4" sample-androidx-composeNavigation = "androidx.navigation:navigation-compose:2.5.2" sample-androidx-composeActivity = "androidx.activity:activity-compose:1.4.0" -sample-androidx-composeFoundation = "androidx.compose.foundation:foundation:1.2.1" -sample-androidx-composeFoundationLayout = "androidx.compose.foundation:foundation-layout:1.2.1" +sample-androidx-composeFoundation = "androidx.compose.foundation:foundation:1.5.4" +sample-androidx-composeFoundationLayout = "androidx.compose.foundation:foundation-layout:1.5.4" sample-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "sampleCoroutines" } sample-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "sampleCoroutines" } diff --git a/plugin-build/gradle.properties b/plugin-build/gradle.properties index b915ece3c..650f09b40 100644 --- a/plugin-build/gradle.properties +++ b/plugin-build/gradle.properties @@ -8,8 +8,8 @@ org.gradle.parallel=true name = sentry-android-gradle-plugin group = io.sentry -version = 5.10.0 -sdk_version = 8.20.0 +version = 5.12.2 +sdk_version = 8.22.0 # publication pom properties POM_NAME=Sentry Android Gradle Plugin diff --git a/plugin-build/src/agp70/kotlin/io/sentry/android/gradle/AGP70Compat.kt b/plugin-build/src/agp70/kotlin/io/sentry/android/gradle/AGP70Compat.kt index 63167839a..520e90000 100644 --- a/plugin-build/src/agp70/kotlin/io/sentry/android/gradle/AGP70Compat.kt +++ b/plugin-build/src/agp70/kotlin/io/sentry/android/gradle/AGP70Compat.kt @@ -6,7 +6,7 @@ import com.android.build.api.instrumentation.AsmClassVisitorFactory import com.android.build.api.instrumentation.FramesComputationMode import com.android.build.api.instrumentation.InstrumentationParameters import com.android.build.api.instrumentation.InstrumentationScope -import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.ApplicationAndroidComponentsExtension import com.android.build.api.variant.Variant import com.android.build.gradle.api.ApplicationVariant import io.sentry.gradle.common.SentryVariant @@ -63,8 +63,8 @@ fun configureInstrumentationFor70( } fun onVariants70( - androidComponentsExt: AndroidComponentsExtension<*, *, *>, - callback: (Variant) -> Unit, + androidComponentsExt: ApplicationAndroidComponentsExtension, + callback: (com.android.build.api.variant.ApplicationVariant) -> Unit, ) { androidComponentsExt.onVariants(callback = callback) } diff --git a/plugin-build/src/agp74/kotlin/io/sentry/android/gradle/AGP74Compat.kt b/plugin-build/src/agp74/kotlin/io/sentry/android/gradle/AGP74Compat.kt index 82d03f34f..e10722a7a 100644 --- a/plugin-build/src/agp74/kotlin/io/sentry/android/gradle/AGP74Compat.kt +++ b/plugin-build/src/agp74/kotlin/io/sentry/android/gradle/AGP74Compat.kt @@ -7,7 +7,8 @@ import com.android.build.api.instrumentation.AsmClassVisitorFactory import com.android.build.api.instrumentation.FramesComputationMode import com.android.build.api.instrumentation.InstrumentationParameters import com.android.build.api.instrumentation.InstrumentationScope -import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.ApplicationAndroidComponentsExtension +import com.android.build.api.variant.ApplicationVariant import com.android.build.api.variant.CanMinifyCode import com.android.build.api.variant.Variant import com.android.build.api.variant.impl.ApplicationVariantImpl @@ -111,8 +112,8 @@ fun configureInstrumentationFor74( } fun onVariants74( - androidComponentsExt: AndroidComponentsExtension<*, *, *>, - callback: (Variant) -> Unit, + androidComponentsExt: ApplicationAndroidComponentsExtension, + callback: (ApplicationVariant) -> Unit, ) { androidComponentsExt.onVariants(callback = callback) } diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt index daa83c706..261dacd47 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/AndroidComponentsConfig.kt @@ -7,9 +7,9 @@ import com.android.build.api.instrumentation.AsmClassVisitorFactory import com.android.build.api.instrumentation.FramesComputationMode import com.android.build.api.instrumentation.InstrumentationParameters import com.android.build.api.instrumentation.InstrumentationScope -import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.ApplicationAndroidComponentsExtension +import com.android.build.api.variant.ApplicationVariant import com.android.build.api.variant.Variant -import com.android.build.gradle.AppExtension import com.android.build.gradle.internal.utils.setDisallowChanges import io.sentry.android.gradle.SentryPlugin.Companion.sep import io.sentry.android.gradle.SentryPropertiesFileProvider.getPropertiesFilePath @@ -48,7 +48,7 @@ import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.TaskProvider import org.gradle.internal.build.event.BuildEventListenerRegistryInternal -fun AndroidComponentsExtension<*, *, *>.configure( +fun ApplicationAndroidComponentsExtension.configure( project: Project, extension: SentryPluginExtension, buildEvents: BuildEventListenerRegistryInternal, @@ -347,7 +347,7 @@ private fun Variant.configureDependenciesTask( } } -private fun Variant.configureProguardMappingsTasks( +private fun ApplicationVariant.configureProguardMappingsTasks( project: Project, extension: SentryPluginExtension, sentryTelemetryProvider: Provider, @@ -373,7 +373,7 @@ private fun Variant.configureProguardMappingsTasks( output = paths.proguardUuidDir, ) - val releaseInfo = getReleaseInfo(project, this) + val releaseInfo = getReleaseInfo() val uploadMappingsTask = SentryUploadProguardMappingsTask.register( project = project, @@ -445,7 +445,9 @@ private fun Variant.configureInstrumentation( * onVariants method in AGP 7.4.0 has a binary incompatibility with the prior versions, hence we * have to distinguish here, although the compatibility sources would look exactly the same. */ -private fun AndroidComponentsExtension<*, *, *>.configureVariants(callback: (Variant) -> Unit) { +private fun ApplicationAndroidComponentsExtension.configureVariants( + callback: (ApplicationVariant) -> Unit +) { if (isAGP74) { onVariants74(this, callback) } else { @@ -453,16 +455,15 @@ private fun AndroidComponentsExtension<*, *, *>.configureVariants(callback: (Var } } -private fun getReleaseInfo(project: Project, variant: Variant): ReleaseInfo { - val appExtension = project.extensions.getByType(AppExtension::class.java) - var applicationId = appExtension.defaultConfig.applicationId ?: appExtension.namespace.toString() - var versionName = appExtension.defaultConfig.versionName ?: "undefined" - var versionCode = appExtension.defaultConfig.versionCode - val flavor = appExtension.productFlavors.find { it.name == variant.flavorName } - flavor?.applicationId?.let { applicationId = it } - flavor?.versionName?.let { versionName = it } - flavor?.versionCode?.let { versionCode = it } - flavor?.applicationIdSuffix?.let { applicationId += it } - flavor?.versionNameSuffix?.let { versionName += it } +private fun ApplicationVariant.getReleaseInfo(): ReleaseInfo { + val applicationId = applicationId.orNull ?: namespace.get() + var versionName = outputs.firstOrNull()?.versionName?.orNull + if (versionName.isNullOrEmpty()) { + versionName = "undefined" + } + var versionCode = outputs.firstOrNull()?.versionCode?.orNull + if (versionCode != null && versionCode < 0) { + versionCode = null + } return ReleaseInfo(applicationId, versionName, versionCode) } 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 f49aa02ad..8a30d7eb3 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 @@ -1,6 +1,6 @@ package io.sentry.android.gradle -import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.ApplicationAndroidComponentsExtension import com.android.build.gradle.AppExtension import io.sentry.BuildConfig import io.sentry.android.gradle.autoinstall.installDependencies @@ -48,7 +48,7 @@ constructor(private val buildEvents: BuildEventListenerRegistryInternal) : Plugi project.pluginManager.withPlugin("com.android.application") { val oldAGPExtension = project.extensions.getByType(AppExtension::class.java) val androidComponentsExt = - project.extensions.getByType(AndroidComponentsExtension::class.java) + project.extensions.getByType(ApplicationAndroidComponentsExtension::class.java) val cliExecutable = project.cliExecutableProvider() val extraProperties = project.extensions.getByName("ext") as ExtraPropertiesExtension 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 94f06231a..514472141 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 @@ -14,8 +14,10 @@ import io.sentry.android.gradle.autoinstall.override.WarnOnOverrideStrategy import io.sentry.android.gradle.autoinstall.quartz.QuartzInstallStrategy import io.sentry.android.gradle.autoinstall.spring.Spring5InstallStrategy import io.sentry.android.gradle.autoinstall.spring.Spring6InstallStrategy +import io.sentry.android.gradle.autoinstall.spring.Spring7InstallStrategy import io.sentry.android.gradle.autoinstall.spring.SpringBoot2InstallStrategy import io.sentry.android.gradle.autoinstall.spring.SpringBoot3InstallStrategy +import io.sentry.android.gradle.autoinstall.spring.SpringBoot4InstallStrategy import io.sentry.android.gradle.autoinstall.sqlite.SQLiteInstallStrategy import io.sentry.android.gradle.autoinstall.timber.TimberInstallStrategy import io.sentry.android.gradle.extensions.SentryPluginExtension @@ -48,8 +50,10 @@ private val delayedStrategies = listOf( Spring5InstallStrategy.Registrar, Spring6InstallStrategy.Registrar, + Spring7InstallStrategy.Registrar, SpringBoot2InstallStrategy.Registrar, SpringBoot3InstallStrategy.Registrar, + SpringBoot4InstallStrategy.Registrar, ) fun Project.installDependencies(extension: SentryPluginExtension, isAndroid: Boolean) { @@ -115,6 +119,7 @@ private fun DependencySet.findSentryVersion(isAndroid: Boolean): String? = (it.name == SentryModules.SENTRY.name || it.name == SentryModules.SENTRY_SPRING_BOOT2.name || it.name == SentryModules.SENTRY_SPRING_BOOT3.name || + it.name == SentryModules.SENTRY_SPRING_BOOT4.name || it.name == SentryModules.SENTRY_BOM.name || it.name == SentryModules.SENTRY_OPENTELEMETRY_AGENTLESS.name || it.name == SentryModules.SENTRY_OPENTELEMETRY_AGENTLESS_SPRING.name) && diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt index 38d0ac49c..0a047673d 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/override/WarnOnOverrideStrategy.kt @@ -76,8 +76,10 @@ abstract class WarnOnOverrideStrategy : ComponentMetadataRule { SentryModules.SENTRY_QUARTZ, SentryModules.SENTRY_SPRING5, SentryModules.SENTRY_SPRING6, + SentryModules.SENTRY_SPRING7, SentryModules.SENTRY_SPRING_BOOT2, SentryModules.SENTRY_SPRING_BOOT3, + SentryModules.SENTRY_SPRING_BOOT4, ) override fun register(component: ComponentMetadataHandler) { diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategy.kt index 42566e335..ac1cdbfd3 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategy.kt @@ -25,6 +25,9 @@ abstract class Spring6InstallStrategy : AbstractInstallStrategy { override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION + override val maxSupportedThirdPartyVersion: SemVer + get() = MAX_SUPPORTED_VERSION + override val minSupportedSentryVersion: SemVer get() = SemVer(6, 7, 0) @@ -34,6 +37,7 @@ abstract class Spring6InstallStrategy : AbstractInstallStrategy { internal const val SENTRY_SPRING_6_ID = "sentry-spring-jakarta" private val MIN_SUPPORTED_VERSION = SemVer(6, 0, 0) + private val MAX_SUPPORTED_VERSION = SemVer(6, 9999, 9999) override fun register(component: ComponentMetadataHandler) { component.withModule("$SPRING_GROUP:$SPRING_6_ID", Spring6InstallStrategy::class.java) {} diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring7InstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring7InstallStrategy.kt new file mode 100644 index 000000000..ae64fc521 --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring7InstallStrategy.kt @@ -0,0 +1,46 @@ +package io.sentry.android.gradle.autoinstall.spring + +import io.sentry.android.gradle.SentryPlugin +import io.sentry.android.gradle.autoinstall.AbstractInstallStrategy +import io.sentry.android.gradle.autoinstall.InstallStrategyRegistrar +import io.sentry.android.gradle.util.SemVer +import javax.inject.Inject +import org.gradle.api.artifacts.dsl.ComponentMetadataHandler +import org.slf4j.Logger + +// @CacheableRule +abstract class Spring7InstallStrategy : AbstractInstallStrategy { + + constructor(logger: Logger) : super() { + this.logger = logger + } + + @Suppress("unused") // used by Gradle + @Inject // inject is needed to avoid Gradle error + constructor() : this(SentryPlugin.logger) + + override val sentryModuleId: String + get() = SENTRY_SPRING_7_ID + + override val minSupportedThirdPartyVersion: SemVer + get() = MIN_SUPPORTED_VERSION + + override val maxSupportedThirdPartyVersion: SemVer + get() = MAX_SUPPORTED_VERSION + + override val minSupportedSentryVersion: SemVer + get() = SemVer(8, 21, 0) + + companion object Registrar : InstallStrategyRegistrar { + private const val SPRING_GROUP = "org.springframework" + private const val SPRING_7_ID = "spring-core" + internal const val SENTRY_SPRING_7_ID = "sentry-spring-7" + + private val MIN_SUPPORTED_VERSION = SemVer(7, 0, 0, "M1") + private val MAX_SUPPORTED_VERSION = SemVer(7, 9999, 9999) + + override fun register(component: ComponentMetadataHandler) { + component.withModule("$SPRING_GROUP:$SPRING_7_ID", Spring7InstallStrategy::class.java) {} + } + } +} diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategy.kt index edd8e56ef..b0c384df3 100644 --- a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategy.kt +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategy.kt @@ -25,6 +25,9 @@ abstract class SpringBoot3InstallStrategy : AbstractInstallStrategy { override val minSupportedThirdPartyVersion: SemVer get() = MIN_SUPPORTED_VERSION + override val maxSupportedThirdPartyVersion: SemVer + get() = MAX_SUPPORTED_VERSION + override val minSupportedSentryVersion: SemVer get() = SemVer(6, 28, 0) @@ -34,6 +37,7 @@ abstract class SpringBoot3InstallStrategy : AbstractInstallStrategy { internal const val SENTRY_SPRING_BOOT_3_ID = "sentry-spring-boot-jakarta" private val MIN_SUPPORTED_VERSION = SemVer(3, 0, 0) + private val MAX_SUPPORTED_VERSION = SemVer(3, 9999, 9999) override fun register(component: ComponentMetadataHandler) { component.withModule( diff --git a/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot4InstallStrategy.kt b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot4InstallStrategy.kt new file mode 100644 index 000000000..801c2cdde --- /dev/null +++ b/plugin-build/src/main/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot4InstallStrategy.kt @@ -0,0 +1,49 @@ +package io.sentry.android.gradle.autoinstall.spring + +import io.sentry.android.gradle.SentryPlugin +import io.sentry.android.gradle.autoinstall.AbstractInstallStrategy +import io.sentry.android.gradle.autoinstall.InstallStrategyRegistrar +import io.sentry.android.gradle.util.SemVer +import javax.inject.Inject +import org.gradle.api.artifacts.dsl.ComponentMetadataHandler +import org.slf4j.Logger + +// @CacheableRule +abstract class SpringBoot4InstallStrategy : AbstractInstallStrategy { + + constructor(logger: Logger) : super() { + this.logger = logger + } + + @Suppress("unused") // used by Gradle + @Inject // inject is needed to avoid Gradle error + constructor() : this(SentryPlugin.logger) + + override val sentryModuleId: String + get() = SENTRY_SPRING_BOOT_4_ID + + override val minSupportedThirdPartyVersion: SemVer + get() = MIN_SUPPORTED_VERSION + + override val maxSupportedThirdPartyVersion: SemVer + get() = MAX_SUPPORTED_VERSION + + override val minSupportedSentryVersion: SemVer + get() = SemVer(8, 21, 0) + + companion object Registrar : InstallStrategyRegistrar { + private const val SPRING_GROUP = "org.springframework.boot" + private const val SPRING_BOOT_4_ID = "spring-boot" + internal const val SENTRY_SPRING_BOOT_4_ID = "sentry-spring-boot-4" + + private val MIN_SUPPORTED_VERSION = SemVer(4, 0, 0, "M1") + private val MAX_SUPPORTED_VERSION = SemVer(4, 9999, 9999) + + override fun register(component: ComponentMetadataHandler) { + component.withModule( + "$SPRING_GROUP:$SPRING_BOOT_4_ID", + SpringBoot4InstallStrategy::class.java, + ) {} + } + } +} 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 23e6fcf83..26b570c32 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 @@ -63,10 +63,13 @@ internal object SentryModules { internal val SENTRY_QUARTZ = DefaultModuleIdentifier.newId("io.sentry", "sentry-quartz") internal val SENTRY_SPRING5 = DefaultModuleIdentifier.newId("io.sentry", "sentry-spring") internal val SENTRY_SPRING6 = DefaultModuleIdentifier.newId("io.sentry", "sentry-spring-jakarta") + internal val SENTRY_SPRING7 = DefaultModuleIdentifier.newId("io.sentry", "sentry-spring-7") internal val SENTRY_SPRING_BOOT2 = DefaultModuleIdentifier.newId("io.sentry", "sentry-spring-boot") internal val SENTRY_SPRING_BOOT3 = DefaultModuleIdentifier.newId("io.sentry", "sentry-spring-boot-jakarta") + internal val SENTRY_SPRING_BOOT4 = + DefaultModuleIdentifier.newId("io.sentry", "sentry-spring-boot-4") internal val SENTRY_BOM = DefaultModuleIdentifier.newId("io.sentry", "sentry-bom") internal val SENTRY_OPENTELEMETRY_AGENTLESS = DefaultModuleIdentifier.newId("io.sentry", "sentry-opentelemetry-agentless") diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategyTest.kt index 74d72ca9e..12a1b6256 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategyTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring6InstallStrategyTest.kt @@ -68,6 +68,19 @@ class Spring6InstallStrategyTest { verify(fixture.metadataDetails, never()).allVariants(any()) } + @Test + fun `when spring version is too high logs a message and does nothing`() { + val sut = fixture.getSut(springVersion = "7.0.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-jakarta won't be installed because the current " + + "version is higher than the maximum supported version (6.9999.9999)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + @Test fun `installs sentry-spring-jakarta with info message`() { val sut = fixture.getSut() diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring7InstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring7InstallStrategyTest.kt new file mode 100644 index 000000000..2bc003335 --- /dev/null +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/Spring7InstallStrategyTest.kt @@ -0,0 +1,102 @@ +package io.sentry.android.gradle.autoinstall.spring + +import com.nhaarman.mockitokotlin2.any +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 Spring7InstallStrategyTest { + 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(springVersion: String = "7.0.0"): Spring7InstallStrategy { + val id = mock { whenever(it.version).doReturn(springVersion) } + whenever(metadataDetails.id).thenReturn(id) + + with(AutoInstallState.getInstance()) { + this.enabled = true + this.sentryVersion = "8.21.0" + } + return Spring7InstallStrategyImpl(logger) + } + } + + private val fixture = Fixture() + + @Test + fun `when spring version is too low logs a message and does nothing`() { + val sut = fixture.getSut(springVersion = "6.7.4") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-7 won't be installed because the current " + + "version is lower than the minimum supported version (7.0.0-M1)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `when spring version is too high logs a message and does nothing`() { + val sut = fixture.getSut(springVersion = "8.0.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-7 won't be installed because the current " + + "version is higher than the maximum supported version (7.9999.9999)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `installs sentry-spring-jakarta with info message`() { + val sut = fixture.getSut() + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-7 was successfully installed with version: 8.21.0" + } + verify(fixture.dependencies) + .add( + com.nhaarman.mockitokotlin2.check { + assertEquals("io.sentry:sentry-spring-7:8.21.0", it) + } + ) + } + + private class Spring7InstallStrategyImpl(logger: Logger) : Spring7InstallStrategy(logger) +} diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategyTest.kt index 7351d5403..cbd7b7d63 100644 --- a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategyTest.kt +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot3InstallStrategyTest.kt @@ -68,6 +68,19 @@ class SpringBoot3InstallStrategyTest { verify(fixture.metadataDetails, never()).allVariants(any()) } + @Test + fun `when spring version is too high logs a message and does nothing`() { + val sut = fixture.getSut(springVersion = "4.0.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-boot-jakarta won't be installed because the current " + + "version is higher than the maximum supported version (3.9999.9999)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + @Test fun `installs sentry-spring-boot-jakarta with info message`() { val sut = fixture.getSut() diff --git a/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot4InstallStrategyTest.kt b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot4InstallStrategyTest.kt new file mode 100644 index 000000000..cca778f39 --- /dev/null +++ b/plugin-build/src/test/kotlin/io/sentry/android/gradle/autoinstall/spring/SpringBoot4InstallStrategyTest.kt @@ -0,0 +1,136 @@ +package io.sentry.android.gradle.autoinstall.spring + +import com.nhaarman.mockitokotlin2.any +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 SpringBoot4InstallStrategyTest { + 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(springVersion: String = "4.0.0"): SpringBoot4InstallStrategy { + val id = mock { whenever(it.version).doReturn(springVersion) } + whenever(metadataDetails.id).thenReturn(id) + + with(AutoInstallState.getInstance()) { + this.enabled = true + this.sentryVersion = "8.21.0" + } + return SpringBoot4InstallStrategyImpl(logger) + } + } + + private val fixture = Fixture() + + @Test + fun `when spring version is too low logs a message and does nothing`() { + val sut = fixture.getSut(springVersion = "3.5.5") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-boot-4 won't be installed because the " + + "current version is lower than the minimum supported version (4.0.0-M1)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `when spring version is too high logs a message and does nothing`() { + val sut = fixture.getSut(springVersion = "5.0.0") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-boot-4 won't be installed because the current " + + "version is higher than the maximum supported version (4.9999.9999)" + } + verify(fixture.metadataDetails, never()).allVariants(any()) + } + + @Test + fun `installs sentry-spring-boot-4 with info message`() { + val sut = fixture.getSut() + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-boot-4 was successfully installed with " + "version: 8.21.0" + } + verify(fixture.dependencies) + .add( + com.nhaarman.mockitokotlin2.check { + assertEquals("io.sentry:sentry-spring-boot-4:8.21.0", it) + } + ) + } + + @Test + fun `installs sentry-spring-boot-4 M1 with info message`() { + val sut = fixture.getSut(springVersion = "4.0.0-M1") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-boot-4 was successfully installed with " + "version: 8.21.0" + } + verify(fixture.dependencies) + .add( + com.nhaarman.mockitokotlin2.check { + assertEquals("io.sentry:sentry-spring-boot-4:8.21.0", it) + } + ) + } + + @Test + fun `installs sentry-spring-boot-4 RC1 with info message`() { + val sut = fixture.getSut(springVersion = "4.0.0-RC1") + sut.execute(fixture.metadataContext) + + assertTrue { + fixture.logger.capturedMessage == + "[sentry] sentry-spring-boot-4 was successfully installed with " + "version: 8.21.0" + } + verify(fixture.dependencies) + .add( + com.nhaarman.mockitokotlin2.check { + assertEquals("io.sentry:sentry-spring-boot-4:8.21.0", it) + } + ) + } + + private class SpringBoot4InstallStrategyImpl(logger: Logger) : SpringBoot4InstallStrategy(logger) +} diff --git a/sentry-kotlin-compiler-plugin/gradle.properties b/sentry-kotlin-compiler-plugin/gradle.properties index c895c0ce0..43b985201 100644 --- a/sentry-kotlin-compiler-plugin/gradle.properties +++ b/sentry-kotlin-compiler-plugin/gradle.properties @@ -1,6 +1,6 @@ GROUP = io.sentry POM_ARTIFACT_ID = sentry-kotlin-compiler-plugin -VERSION_NAME = 5.10.0 +VERSION_NAME = 5.12.2 # publication pom properties POM_NAME=Sentry Kotlin Compiler Plugin diff --git a/sentry-kotlin-compiler-plugin/src/kotlin2200/kotlin/io/sentry/compose/JetpackComposeTracingIrExtension22.kt b/sentry-kotlin-compiler-plugin/src/kotlin2200/kotlin/io/sentry/compose/JetpackComposeTracingIrExtension22.kt index 8e9f1c55f..c111dec30 100644 --- a/sentry-kotlin-compiler-plugin/src/kotlin2200/kotlin/io/sentry/compose/JetpackComposeTracingIrExtension22.kt +++ b/sentry-kotlin-compiler-plugin/src/kotlin2200/kotlin/io/sentry/compose/JetpackComposeTracingIrExtension22.kt @@ -87,8 +87,7 @@ class JetpackComposeTracingIrExtension22(private val messageCollector: MessageCo val sentryModifierClassId = FqName("io.sentry.compose").classId("SentryModifier") - val sentryModifierCompanionClass = - pluginContext.referenceClass(sentryModifierClassId)?.owner?.companionObject() + val sentryModifierCompanionClass = pluginContext.referenceClass(sentryModifierClassId)?.owner val sentryModifierTagFunction = sentryModifierClassId.callableId("sentryTag") diff --git a/settings.gradle.kts b/settings.gradle.kts index 2bac0afbf..0917c4c58 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,6 +19,9 @@ pluginManagement { gradlePluginPortal() mavenCentral() google() + maven { + url = uri("https://storage.googleapis.com/r8-releases/raw") + } } } @@ -54,4 +57,9 @@ include(":examples:multi-module-sample:spring-boot-in-multi-module-sample2") includeBuild("plugin-build") -includeBuild("sentry-kotlin-compiler-plugin") +// this is needed so we can use kotlin-compiler-plugin directly in the sample app without publishing +includeBuild("sentry-kotlin-compiler-plugin") { + dependencySubstitution { + substitute(module("io.sentry:sentry-kotlin-compiler-plugin")).using(project(":")) + } +}