diff --git a/CHANGELOG.md b/CHANGELOG.md index 72431094bc..3edd3e447e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Features -- Add `installGroupsOverride` parameter and `installGroups` property to Build Distribution SDK ([#5062](https://github.com/getsentry/sentry-java/pull/5062)) +- Add `installGroupsOverride` parameter to Build Distribution SDK for programmatic filtering, with support for configuration via properties file using `io.sentry.distribution.install-groups-override` ([#5066](https://github.com/getsentry/sentry-java/pull/5066)) +- Add `installGroups` property to Build Distribution SDK ([#5062](https://github.com/getsentry/sentry-java/pull/5062)) - Update Android targetSdk to API 36 (Android 16) ([#5016](https://github.com/getsentry/sentry-java/pull/5016)) - Add AndroidManifest support for Spotlight configuration via `io.sentry.spotlight.enable` and `io.sentry.spotlight.url` ([#5064](https://github.com/getsentry/sentry-java/pull/5064)) diff --git a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt index daf702263f..4a53b557a0 100644 --- a/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt +++ b/sentry-android-distribution/src/main/java/io/sentry/android/distribution/DistributionIntegration.kt @@ -150,6 +150,7 @@ public class DistributionIntegration(context: Context) : Integration, IDistribut versionCode = versionCode, versionName = versionName, buildConfiguration = buildConfiguration, + installGroupsOverride = sentryOptions.distribution.installGroupsOverride, ) } catch (e: PackageManager.NameNotFoundException) { sentryOptions.logger.log(SentryLevel.ERROR, e, "Failed to get package info") diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 7020c8e216..8a31fdaca7 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -3754,6 +3754,7 @@ public final class io/sentry/SentryOptions$Cron { public final class io/sentry/SentryOptions$DistributionOptions { public field buildConfiguration Ljava/lang/String; + public field installGroupsOverride Ljava/util/List; public field orgAuthToken Ljava/lang/String; public field orgSlug Ljava/lang/String; public field projectSlug Ljava/lang/String; diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index c370672dd9..f4cff584b6 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -664,6 +664,9 @@ public static final class DistributionOptions { /** Optional build configuration name for filtering (e.g., "debug", "release", "staging") */ public @Nullable String buildConfiguration = null; + + /** Optional install groups for filtering updates */ + public @Nullable List installGroupsOverride = null; } private @NotNull DistributionOptions distribution = new DistributionOptions(); diff --git a/sentry/src/main/java/io/sentry/util/DebugMetaPropertiesApplier.java b/sentry/src/main/java/io/sentry/util/DebugMetaPropertiesApplier.java index a6ff901b90..8bb89fbcd8 100644 --- a/sentry/src/main/java/io/sentry/util/DebugMetaPropertiesApplier.java +++ b/sentry/src/main/java/io/sentry/util/DebugMetaPropertiesApplier.java @@ -98,11 +98,14 @@ private static void applyDistributionOptions( final @Nullable String projectSlug = getDistributionProjectSlug(properties); final @Nullable String orgAuthToken = getDistributionAuthToken(properties); final @Nullable String buildConfiguration = getDistributionBuildConfiguration(properties); + final @Nullable String installGroupsOverride = + getDistributionInstallGroupsOverride(properties); if (orgSlug != null || projectSlug != null || orgAuthToken != null - || buildConfiguration != null) { + || buildConfiguration != null + || installGroupsOverride != null) { final @NotNull SentryOptions.DistributionOptions distributionOptions = options.getDistribution(); @@ -139,6 +142,26 @@ private static void applyDistributionOptions( distributionOptions.buildConfiguration = buildConfiguration; } + if (installGroupsOverride != null + && !installGroupsOverride.isEmpty() + && distributionOptions.installGroupsOverride == null) { + final @NotNull String[] groups = installGroupsOverride.split(",", -1); + final @NotNull List groupList = new java.util.ArrayList<>(); + for (final String group : groups) { + final String trimmedGroup = group.trim(); + if (!trimmedGroup.isEmpty()) { + groupList.add(trimmedGroup); + } + } + if (!groupList.isEmpty()) { + options + .getLogger() + .log( + SentryLevel.DEBUG, "Distribution install groups override found: %s", groupList); + distributionOptions.installGroupsOverride = groupList; + } + } + // We only process the first properties file that contains distribution options // to maintain consistency with other properties like proguardUuid break; @@ -165,4 +188,9 @@ private static void applyDistributionOptions( final @NotNull Properties debugMetaProperties) { return debugMetaProperties.getProperty("io.sentry.distribution.build-configuration"); } + + private static @Nullable String getDistributionInstallGroupsOverride( + final @NotNull Properties debugMetaProperties) { + return debugMetaProperties.getProperty("io.sentry.distribution.install-groups-override"); + } } diff --git a/sentry/src/test/java/io/sentry/util/DebugMetaPropertiesApplierTest.kt b/sentry/src/test/java/io/sentry/util/DebugMetaPropertiesApplierTest.kt index 63c8a62c91..ab06c851f8 100644 --- a/sentry/src/test/java/io/sentry/util/DebugMetaPropertiesApplierTest.kt +++ b/sentry/src/test/java/io/sentry/util/DebugMetaPropertiesApplierTest.kt @@ -138,4 +138,87 @@ class DebugMetaPropertiesApplierTest { assertEquals("", options.distribution.orgAuthToken) assertNull(options.distribution.buildConfiguration) } + + @Test + fun `applies installGroupsOverride from properties`() { + val properties = Properties() + properties.setProperty( + "io.sentry.distribution.install-groups-override", + "internal,beta-testers", + ) + + val options = SentryOptions() + DebugMetaPropertiesApplier.apply(options, listOf(properties)) + + assertEquals(listOf("internal", "beta-testers"), options.distribution.installGroupsOverride) + } + + @Test + fun `applies installGroupsOverride with trimming`() { + val properties = Properties() + properties.setProperty( + "io.sentry.distribution.install-groups-override", + " internal , beta-testers , qa ", + ) + + val options = SentryOptions() + DebugMetaPropertiesApplier.apply(options, listOf(properties)) + + assertEquals( + listOf("internal", "beta-testers", "qa"), + options.distribution.installGroupsOverride, + ) + } + + @Test + fun `applies single installGroupsOverride value`() { + val properties = Properties() + properties.setProperty("io.sentry.distribution.install-groups-override", "internal") + + val options = SentryOptions() + DebugMetaPropertiesApplier.apply(options, listOf(properties)) + + assertEquals(listOf("internal"), options.distribution.installGroupsOverride) + } + + @Test + fun `does not override existing installGroupsOverride`() { + val properties = Properties() + properties.setProperty("io.sentry.distribution.install-groups-override", "properties-group") + + val options = SentryOptions() + options.distribution.installGroupsOverride = listOf("existing-group") + + DebugMetaPropertiesApplier.apply(options, listOf(properties)) + + assertEquals(listOf("existing-group"), options.distribution.installGroupsOverride) + } + + @Test + fun `does not apply empty installGroupsOverride`() { + val properties = Properties() + properties.setProperty("io.sentry.distribution.install-groups-override", "") + + val options = SentryOptions() + DebugMetaPropertiesApplier.apply(options, listOf(properties)) + + assertNull(options.distribution.installGroupsOverride) + } + + @Test + fun `ignores empty values in installGroupsOverride list`() { + val properties = Properties() + properties.setProperty( + "io.sentry.distribution.install-groups-override", + "internal,,beta-testers, ,qa", + ) + + val options = SentryOptions() + DebugMetaPropertiesApplier.apply(options, listOf(properties)) + + assertEquals( + listOf("internal", "beta-testers", "qa"), + options.distribution.installGroupsOverride, + ) + } }