Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Allow tracing instrumentation and runtime optimizations to be disabled for specific variants, build types, or flavors without disabling other Sentry plugin features ([#1409](https://github.com/getsentry/sentry-android-gradle-plugin/pull/1409))

## 6.19.0

### Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,22 @@ fun ApplicationAndroidComponentsExtension.configure(
}
}

val runtimeOptimizationsEnabled = extension.runtimeOptimizations.enabled.get()
val tracingInstrumentationEnabled = extension.tracingInstrumentation.enabled.get()
val runtimeOptimizations = extension.runtimeOptimizations
val runtimeOptimizationsEnabled =
variant.isInstrumentationEnabled(
runtimeOptimizations.enabled.get(),
runtimeOptimizations.ignoredVariants,
runtimeOptimizations.ignoredBuildTypes,
runtimeOptimizations.ignoredFlavors,
)
val tracingInstrumentation = extension.tracingInstrumentation
val tracingInstrumentationEnabled =
variant.isInstrumentationEnabled(
tracingInstrumentation.enabled.get(),
tracingInstrumentation.ignoredVariants,
tracingInstrumentation.ignoredBuildTypes,
tracingInstrumentation.ignoredFlavors,
)
// Both visitor factories need the resolved dependency graph.
val modulesService =
if (runtimeOptimizationsEnabled || tracingInstrumentationEnabled) {
Expand Down Expand Up @@ -581,6 +595,17 @@ fun Variant.configureUploadAppTasks(
return uploadBundleTask to uploadApkTask
}

private fun Variant.isInstrumentationEnabled(
enabled: Boolean,
ignoredVariants: SetProperty<String>,
ignoredBuildTypes: SetProperty<String>,
ignoredFlavors: SetProperty<String>,
): Boolean =
enabled &&
name !in ignoredVariants.get() &&
flavorName !in ignoredFlavors.get() &&
buildType !in ignoredBuildTypes.get()

private fun <T : InstrumentationParameters> Variant.configureInstrumentation(
classVisitorFactoryImplClass: Class<out AsmClassVisitorFactory<T>>,
scope: InstrumentationScope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@ package io.sentry.android.gradle.extensions
import javax.inject.Inject
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty

open class RuntimeOptimizationsExtension @Inject constructor(objects: ObjectFactory) {
/**
* Enables runtime optimizations of the Sentry SDK at the cost of build time. Defaults to true.
*/
val enabled: Property<Boolean> = objects.property(Boolean::class.java).convention(true)

/** Android build variants for which runtime optimizations should be disabled. */
val ignoredVariants: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())

/** Android build types for which runtime optimizations should be disabled. */
val ignoredBuildTypes: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())

/** Android build flavors for which runtime optimizations should be disabled. */
val ignoredFlavors: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ open class TracingInstrumentationExtension @Inject constructor(objects: ObjectFa
*/
val enabled: Property<Boolean> = objects.property(Boolean::class.java).convention(true)

/** Android build variants for which tracing instrumentation should be disabled. */
val ignoredVariants: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())

/** Android build types for which tracing instrumentation should be disabled. */
val ignoredBuildTypes: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())

/** Android build flavors for which tracing instrumentation should be disabled. */
val ignoredFlavors: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())

/**
* Enabled debug output of the plugin. Useful when there are issues with code instrumentation,
* shows the modified bytecode. Defaults to false.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.android.gradle.integration

import com.google.common.truth.Truth.assertThat
import io.sentry.BuildConfig
import org.gradle.util.GradleVersion
import org.junit.Assert.assertFalse
Expand Down Expand Up @@ -83,6 +84,107 @@ class SentryPluginVariantTest :
assertTrue(":app:uploadSentryProguardMappingsDemoRelease" in build.output)
}

@Test
fun `skips tracing for ignored variant while preserving mapping upload`() {
applyTracingIgnores(ignoredVariants = setOf("fullRelease"))

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleDemoRelease", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformDemoReleaseClassesWithAsm")
}

@Test
fun `skips tracing for ignored build type while preserving mapping upload`() {
applyTracingIgnores(ignoredBuildTypes = setOf("release"))

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleFullDebug", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformFullDebugClassesWithAsm")
}

@Test
fun `skips tracing for ignored flavor while preserving mapping upload`() {
applyTracingIgnores(ignoredFlavors = setOf("full"))

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleDemoRelease", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformDemoReleaseClassesWithAsm")
}

@Test
fun `skips runtime optimizations for ignored variant while preserving mapping upload`() {
applyRuntimeOptimizationIgnores(ignoredVariants = setOf("fullRelease"))

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleDemoRelease", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformDemoReleaseClassesWithAsm")
}

@Test
fun `skips runtime optimizations for ignored build type while preserving mapping upload`() {
applyRuntimeOptimizationIgnores(ignoredBuildTypes = setOf("release"))

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleFullDebug", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformFullDebugClassesWithAsm")
}

@Test
fun `skips runtime optimizations for ignored flavor while preserving mapping upload`() {
applyRuntimeOptimizationIgnores(ignoredFlavors = setOf("full"))

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleDemoRelease", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformDemoReleaseClassesWithAsm")
}

@Test
fun `skips both instrumentation visitors when both extensions ignore a build type`() {
applyRuntimeOptimizationIgnores(
ignoredBuildTypes = setOf("release"),
tracingInstrumentation = true,
)

val ignoredBuild = runner.appendArguments(":app:assembleFullRelease", "--dry-run").build()

assertThat(ignoredBuild.output).doesNotContain(":app:transformFullReleaseClassesWithAsm")
assertThat(ignoredBuild.output).contains(":app:uploadSentryProguardMappingsFullRelease")

val allowedBuild = runner.appendArguments(":app:assembleFullDebug", "--dry-run").build()

assertThat(allowedBuild.output).contains(":app:transformFullDebugClassesWithAsm")
}

private fun applyIgnores(
ignoredVariants: Set<String> = setOf(),
ignoredBuildTypes: Set<String> = setOf(),
Expand All @@ -107,4 +209,64 @@ class SentryPluginVariantTest :
.trimIndent()
)
}

private fun applyTracingIgnores(
ignoredVariants: Set<String> = emptySet(),
ignoredBuildTypes: Set<String> = emptySet(),
ignoredFlavors: Set<String> = emptySet(),
) {
val variants = ignoredVariants.joinToString(",") { "\"$it\"" }
val buildTypes = ignoredBuildTypes.joinToString(",") { "\"$it\"" }
val flavors = ignoredFlavors.joinToString(",") { "\"$it\"" }
appBuildFile.appendText(
// language=Groovy
"""
sentry {
autoUploadProguardMapping = false
runtimeOptimizations {
enabled = false
}
tracingInstrumentation {
enabled = true
ignoredVariants = [$variants]
ignoredBuildTypes = [$buildTypes]
ignoredFlavors = [$flavors]
}
}
"""
.trimIndent()
)
}

private fun applyRuntimeOptimizationIgnores(
ignoredVariants: Set<String> = emptySet(),
ignoredBuildTypes: Set<String> = emptySet(),
ignoredFlavors: Set<String> = emptySet(),
tracingInstrumentation: Boolean = false,
) {
val variants = ignoredVariants.joinToString(",") { "\"$it\"" }
val buildTypes = ignoredBuildTypes.joinToString(",") { "\"$it\"" }
val flavors = ignoredFlavors.joinToString(",") { "\"$it\"" }
appBuildFile.appendText(
// language=Groovy
"""
sentry {
autoUploadProguardMapping = false
runtimeOptimizations {
enabled = true
ignoredVariants = [$variants]
ignoredBuildTypes = [$buildTypes]
ignoredFlavors = [$flavors]
}
tracingInstrumentation {
enabled = $tracingInstrumentation
ignoredVariants = [$variants]
ignoredBuildTypes = [$buildTypes]
ignoredFlavors = [$flavors]
}
}
"""
.trimIndent()
)
}
}