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
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,27 @@ fun ApplicationAndroidComponentsExtension.configure(
tmpDir.mkdirs()

onVariants { variant ->
if (isVariantAllowed(extension, variant.name, variant.flavorName, variant.buildType)) {
val paths = OutputPaths(project, variant.name)
val sentryTelemetryProvider =
// Calculate feature enablement early
val sizeAnalysisEnabledForVariant = calculateSizeAnalysisEnabled(extension, variant.name)
val variantIsAllowed =
isVariantAllowed(extension, variant.name, variant.flavorName, variant.buildType)
val distributionEnabledForVariant =
variantIsAllowed && extension.distribution.enabledVariants.get().contains(variant.name)

// Configure telemetry if ANY feature needs it (variant allowed OR size analysis enabled)
val sentryTelemetryProvider =
if (variantIsAllowed || sizeAnalysisEnabledForVariant) {
variant.configureTelemetry(project, extension, cliExecutable, sentryOrg, buildEvents)
} else {
null
}

if (variantIsAllowed) {
val paths = OutputPaths(project, variant.name)
// sentryTelemetryProvider is guaranteed to be non-null here since variantIsAllowed is true
val telemetryProvider = sentryTelemetryProvider!!

variant.configureDependenciesTask(project, extension, sentryTelemetryProvider)
variant.configureDependenciesTask(project, extension, telemetryProvider)

// TODO: do this only once, and all other tasks should be SentryVariant.configureSomething
val sentryVariant = AndroidVariant74(variant)
Expand All @@ -84,7 +99,7 @@ fun ApplicationAndroidComponentsExtension.configure(
variant.configureSourceBundleTasks(
project,
extension,
sentryTelemetryProvider,
telemetryProvider,
paths,
sourceFiles,
cliExecutable,
Expand All @@ -97,7 +112,7 @@ fun ApplicationAndroidComponentsExtension.configure(
variant.configureProguardMappingsTasks(
project,
extension,
sentryTelemetryProvider,
telemetryProvider,
paths,
cliExecutable,
sentryOrg,
Expand All @@ -109,7 +124,7 @@ fun ApplicationAndroidComponentsExtension.configure(
variant.configureDistributionPropertiesTask(
project,
extension,
sentryTelemetryProvider,
telemetryProvider,
paths,
sentryOrg,
sentryProject,
Expand All @@ -119,7 +134,7 @@ fun ApplicationAndroidComponentsExtension.configure(
sentryVariant.configureNativeSymbolsTask(
project,
extension,
sentryTelemetryProvider,
telemetryProvider,
cliExecutable,
sentryOrg,
sentryProject,
Expand All @@ -135,7 +150,7 @@ fun ApplicationAndroidComponentsExtension.configure(
InjectSentryMetaPropertiesIntoAssetsTask.register(
project,
extension,
sentryTelemetryProvider,
telemetryProvider,
tasksGeneratingProperties,
variant.name.capitalized,
)
Expand Down Expand Up @@ -216,7 +231,7 @@ fun ApplicationAndroidComponentsExtension.configure(
SentryGenerateIntegrationListTask.register(
project,
extension,
sentryTelemetryProvider,
telemetryProvider,
sentryModulesService,
variant.name,
)
Expand All @@ -229,18 +244,18 @@ fun ApplicationAndroidComponentsExtension.configure(
)
.toTransform(SingleArtifact.MERGED_MANIFEST)
}
val sizeAnalysisEnabled = extension.sizeAnalysis.enabled.get() == true
val distributionEnabled = extension.distribution.enabledVariants.get().contains(variant.name)
if (sizeAnalysisEnabled || distributionEnabled) {
variant.configureUploadAppTasks(
project,
extension,
sentryTelemetryProvider,
cliExecutable,
sentryOrg,
sentryProject,
)
}
}

// Configure upload tasks if EITHER feature is enabled for this variant
if (sizeAnalysisEnabledForVariant || distributionEnabledForVariant) {
variant.configureUploadAppTasks(
project,
extension,
sentryTelemetryProvider!!,
cliExecutable,
sentryOrg,
sentryProject,
)
}
}
}
Expand Down Expand Up @@ -499,3 +514,29 @@ private fun ApplicationVariant.getReleaseInfo(): ReleaseInfo {
}
return ReleaseInfo(applicationId, versionName, versionCode)
}

/**
* Calculates whether size analysis is enabled for a specific variant.
*
* Size analysis is enabled if:
* 1. The global enabled flag is true, AND
* 2. Either enabledVariants is empty (meaning all variants), OR the variant is in enabledVariants
*
* Note: This function BYPASSES isVariantAllowed. This means size analysis can run on variants
* that are globally ignored via ignoredVariants, ignoredBuildTypes, or ignoredFlavors. This is
* intentional to provide fine-grained control over which variants have size analysis enabled.
*/
private fun calculateSizeAnalysisEnabled(
extension: SentryPluginExtension,
variantName: String,
): Boolean {
// Master kill-switch check first
if (extension.sizeAnalysis.enabled.get() != true) {
return false
}

val enabledVariants = extension.sizeAnalysis.enabledVariants.get()

// Empty set = enable for all variants (backward compatibility)
return enabledVariants.isEmpty() || enabledVariants.contains(variantName)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import javax.inject.Inject
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.provider.SetProperty
import org.jetbrains.annotations.ApiStatus.Experimental

@Experimental
Expand All @@ -17,6 +18,31 @@ constructor(objects: ObjectFactory, providerFactory: ProviderFactory) {
.property(Boolean::class.java)
.convention(providerFactory.isCi() && false) // set to false for now otherwise upload fails CI

/**
* Set of Android build variants that should have size analysis enabled.
*
* When empty (default), size analysis runs on all variants (subject to the enabled flag).
* When populated, only the specified variants will have size analysis enabled.
*
* Note: This property BYPASSES the global ignore settings (ignoredVariants, ignoredBuildTypes,
* ignoredFlavors). This allows size analysis to run on specific variants even if they are
* globally ignored. This is different from most other Sentry features which respect the global
* ignore settings.
*
* Example:
* ```
* sentry {
* ignoredVariants.set(["debug"]) // Most features ignore debug
* sizeAnalysis {
* enabled = true
* enabledVariants.set(["debug", "release"]) // Size analysis runs on both
* }
* }
* ```
*/
val enabledVariants: SetProperty<String> =
objects.setProperty(String::class.java).convention(emptySet())

/**
* The build configuration to use for the upload. This allows comparison between builds with the
* same buildConfiguration. If not provided, the build variant will be used.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package io.sentry.android.gradle.extensions

import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.gradle.testfixtures.ProjectBuilder
import org.junit.Test

class SizeAnalysisExtensionTest {

@Test
fun `enabledVariants is empty by default`() {
val project = ProjectBuilder.builder().build()
val extension =
project.objects.newInstance(
SizeAnalysisExtension::class.java,
project.objects,
project.providers,
)

assertTrue(extension.enabledVariants.get().isEmpty())
}

@Test
fun `enabledVariants can be configured with variant names`() {
val project = ProjectBuilder.builder().build()
val extension =
project.objects.newInstance(
SizeAnalysisExtension::class.java,
project.objects,
project.providers,
)

extension.enabledVariants.set(setOf("release", "staging", "debug"))

assertEquals(setOf("release", "staging", "debug"), extension.enabledVariants.get())
}

@Test
fun `enabledVariants can be updated multiple times`() {
val project = ProjectBuilder.builder().build()
val extension =
project.objects.newInstance(
SizeAnalysisExtension::class.java,
project.objects,
project.providers,
)

extension.enabledVariants.set(setOf("release"))
assertEquals(setOf("release"), extension.enabledVariants.get())

extension.enabledVariants.set(setOf("debug", "staging"))
assertEquals(setOf("debug", "staging"), extension.enabledVariants.get())
}

@Test
fun `enabled is false by default in non-CI environment`() {
val project = ProjectBuilder.builder().build()
val extension =
project.objects.newInstance(
SizeAnalysisExtension::class.java,
project.objects,
project.providers,
)

// In test environment, CI is typically not set
assertFalse(extension.enabled.get())
}

@Test
fun `enabled can be configured`() {
val project = ProjectBuilder.builder().build()
val extension =
project.objects.newInstance(
SizeAnalysisExtension::class.java,
project.objects,
project.providers,
)

extension.enabled.set(true)

assertTrue(extension.enabled.get())
}

@Test
fun `buildConfiguration can be configured`() {
val project = ProjectBuilder.builder().build()
val extension =
project.objects.newInstance(
SizeAnalysisExtension::class.java,
project.objects,
project.providers,
)

extension.buildConfiguration.set("custom-config")

assertEquals("custom-config", extension.buildConfiguration.get())
}
}
Loading
Loading