Skip to content

Commit 96449e8

Browse files
runningcodeclaudegetsentry-bot
authored
Add support for reading distribution options from properties (#4784)
* Add support for reading distribution options from sentry-debug-meta.properties Extends DebugMetaPropertiesApplier to read and apply distribution configuration from properties files. This allows the Gradle plugin to populate distribution options (orgSlug, projectSlug, orgAuthToken, buildConfiguration) that will be automatically loaded when the SDK initializes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Address PR review comments - Include buildConfiguration in initial property check to fix bug where buildConfiguration-only properties would be skipped - Add isEmpty() checks for all property values before applying - Add comment explaining break statement (only process first properties file) - Add test for buildConfiguration-only scenario - Add test for empty string values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Update auth token property name and improve test coverage - Rename property from `io.sentry.distribution.org-auth-token` to `io.sentry.distribution.auth-token` to match sentry-android-gradle-plugin - Rename method from `getDistributionOrgAuthToken` to `getDistributionAuthToken` - Improve test to verify first properties file with distribution options is used 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * Format code --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Sentry Github Bot <bot+github-bot@sentry.io>
1 parent 2dc2ca8 commit 96449e8

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

sentry/src/main/java/io/sentry/util/DebugMetaPropertiesApplier.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public static void apply(
1717
if (debugMetaProperties != null) {
1818
applyToOptions(options, debugMetaProperties);
1919
applyBuildTool(options, debugMetaProperties);
20+
applyDistributionOptions(options, debugMetaProperties);
2021
}
2122
}
2223

@@ -89,4 +90,79 @@ private static void applyBuildTool(
8990
final @NotNull Properties debugMetaProperties) {
9091
return debugMetaProperties.getProperty("io.sentry.build-tool-version");
9192
}
93+
94+
private static void applyDistributionOptions(
95+
final @NotNull SentryOptions options, final @NotNull List<Properties> debugMetaProperties) {
96+
for (Properties properties : debugMetaProperties) {
97+
final @Nullable String orgSlug = getDistributionOrgSlug(properties);
98+
final @Nullable String projectSlug = getDistributionProjectSlug(properties);
99+
final @Nullable String orgAuthToken = getDistributionAuthToken(properties);
100+
final @Nullable String buildConfiguration = getDistributionBuildConfiguration(properties);
101+
102+
if (orgSlug != null
103+
|| projectSlug != null
104+
|| orgAuthToken != null
105+
|| buildConfiguration != null) {
106+
final @NotNull SentryOptions.DistributionOptions distributionOptions =
107+
options.getDistribution();
108+
109+
if (orgSlug != null && !orgSlug.isEmpty() && distributionOptions.orgSlug.isEmpty()) {
110+
options.getLogger().log(SentryLevel.DEBUG, "Distribution org slug found: %s", orgSlug);
111+
distributionOptions.orgSlug = orgSlug;
112+
}
113+
114+
if (projectSlug != null
115+
&& !projectSlug.isEmpty()
116+
&& distributionOptions.projectSlug.isEmpty()) {
117+
options
118+
.getLogger()
119+
.log(SentryLevel.DEBUG, "Distribution project slug found: %s", projectSlug);
120+
distributionOptions.projectSlug = projectSlug;
121+
}
122+
123+
if (orgAuthToken != null
124+
&& !orgAuthToken.isEmpty()
125+
&& distributionOptions.orgAuthToken.isEmpty()) {
126+
options.getLogger().log(SentryLevel.DEBUG, "Distribution org auth token found");
127+
distributionOptions.orgAuthToken = orgAuthToken;
128+
}
129+
130+
if (buildConfiguration != null
131+
&& !buildConfiguration.isEmpty()
132+
&& distributionOptions.buildConfiguration == null) {
133+
options
134+
.getLogger()
135+
.log(
136+
SentryLevel.DEBUG,
137+
"Distribution build configuration found: %s",
138+
buildConfiguration);
139+
distributionOptions.buildConfiguration = buildConfiguration;
140+
}
141+
142+
// We only process the first properties file that contains distribution options
143+
// to maintain consistency with other properties like proguardUuid
144+
break;
145+
}
146+
}
147+
}
148+
149+
private static @Nullable String getDistributionOrgSlug(
150+
final @NotNull Properties debugMetaProperties) {
151+
return debugMetaProperties.getProperty("io.sentry.distribution.org-slug");
152+
}
153+
154+
private static @Nullable String getDistributionProjectSlug(
155+
final @NotNull Properties debugMetaProperties) {
156+
return debugMetaProperties.getProperty("io.sentry.distribution.project-slug");
157+
}
158+
159+
private static @Nullable String getDistributionAuthToken(
160+
final @NotNull Properties debugMetaProperties) {
161+
return debugMetaProperties.getProperty("io.sentry.distribution.auth-token");
162+
}
163+
164+
private static @Nullable String getDistributionBuildConfiguration(
165+
final @NotNull Properties debugMetaProperties) {
166+
return debugMetaProperties.getProperty("io.sentry.distribution.build-configuration");
167+
}
92168
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package io.sentry.util
2+
3+
import io.sentry.SentryOptions
4+
import java.util.Properties
5+
import kotlin.test.Test
6+
import kotlin.test.assertEquals
7+
import kotlin.test.assertNull
8+
9+
class DebugMetaPropertiesApplierTest {
10+
11+
@Test
12+
fun `applies distribution options from properties`() {
13+
val properties = Properties()
14+
properties.setProperty("io.sentry.distribution.org-slug", "test-org")
15+
properties.setProperty("io.sentry.distribution.project-slug", "test-project")
16+
properties.setProperty("io.sentry.distribution.auth-token", "test-token")
17+
properties.setProperty("io.sentry.distribution.build-configuration", "debug")
18+
19+
val options = SentryOptions()
20+
DebugMetaPropertiesApplier.apply(options, listOf(properties))
21+
22+
assertEquals("test-org", options.distribution.orgSlug)
23+
assertEquals("test-project", options.distribution.projectSlug)
24+
assertEquals("test-token", options.distribution.orgAuthToken)
25+
assertEquals("debug", options.distribution.buildConfiguration)
26+
}
27+
28+
@Test
29+
fun `applies partial distribution options from properties`() {
30+
val properties = Properties()
31+
properties.setProperty("io.sentry.distribution.org-slug", "test-org")
32+
properties.setProperty("io.sentry.distribution.project-slug", "test-project")
33+
34+
val options = SentryOptions()
35+
DebugMetaPropertiesApplier.apply(options, listOf(properties))
36+
37+
assertEquals("test-org", options.distribution.orgSlug)
38+
assertEquals("test-project", options.distribution.projectSlug)
39+
assertEquals("", options.distribution.orgAuthToken)
40+
assertNull(options.distribution.buildConfiguration)
41+
}
42+
43+
@Test
44+
fun `does not override existing distribution options`() {
45+
val properties = Properties()
46+
properties.setProperty("io.sentry.distribution.org-slug", "properties-org")
47+
properties.setProperty("io.sentry.distribution.project-slug", "properties-project")
48+
properties.setProperty("io.sentry.distribution.auth-token", "properties-token")
49+
properties.setProperty("io.sentry.distribution.build-configuration", "properties-config")
50+
51+
val options = SentryOptions()
52+
options.distribution.orgSlug = "existing-org"
53+
options.distribution.projectSlug = "existing-project"
54+
options.distribution.orgAuthToken = "existing-token"
55+
options.distribution.buildConfiguration = "existing-config"
56+
57+
DebugMetaPropertiesApplier.apply(options, listOf(properties))
58+
59+
assertEquals("existing-org", options.distribution.orgSlug)
60+
assertEquals("existing-project", options.distribution.projectSlug)
61+
assertEquals("existing-token", options.distribution.orgAuthToken)
62+
assertEquals("existing-config", options.distribution.buildConfiguration)
63+
}
64+
65+
@Test
66+
fun `applies distribution options from first properties file with values`() {
67+
val properties1 = Properties()
68+
val properties2 = Properties()
69+
val properties3 = Properties()
70+
71+
// properties1 has non-distribution properties so is ignored:
72+
properties1.setProperty("io.sentry.unrelated", "unrelated")
73+
74+
// properties2 should end up being the ones set
75+
properties2.setProperty("io.sentry.distribution.project-slug", "project-from-second")
76+
77+
// properties3 also has distribution properties but since properties2 was first they are
78+
// ignored.
79+
properties3.setProperty("io.sentry.distribution.project-slug", "project-from-third")
80+
81+
val options = SentryOptions()
82+
DebugMetaPropertiesApplier.apply(options, listOf(properties1, properties2, properties3))
83+
84+
assertEquals("project-from-second", options.distribution.projectSlug)
85+
}
86+
87+
@Test
88+
fun `does nothing when properties list is empty`() {
89+
val options = SentryOptions()
90+
val originalOrgSlug = options.distribution.orgSlug
91+
val originalProjectSlug = options.distribution.projectSlug
92+
93+
DebugMetaPropertiesApplier.apply(options, emptyList())
94+
95+
assertEquals(originalOrgSlug, options.distribution.orgSlug)
96+
assertEquals(originalProjectSlug, options.distribution.projectSlug)
97+
}
98+
99+
@Test
100+
fun `does nothing when properties list is null`() {
101+
val options = SentryOptions()
102+
val originalOrgSlug = options.distribution.orgSlug
103+
val originalProjectSlug = options.distribution.projectSlug
104+
105+
DebugMetaPropertiesApplier.apply(options, null)
106+
107+
assertEquals(originalOrgSlug, options.distribution.orgSlug)
108+
assertEquals(originalProjectSlug, options.distribution.projectSlug)
109+
}
110+
111+
@Test
112+
fun `applies buildConfiguration only when it is the only property set`() {
113+
val properties = Properties()
114+
properties.setProperty("io.sentry.distribution.build-configuration", "debug")
115+
116+
val options = SentryOptions()
117+
DebugMetaPropertiesApplier.apply(options, listOf(properties))
118+
119+
assertEquals("debug", options.distribution.buildConfiguration)
120+
assertEquals("", options.distribution.orgSlug)
121+
assertEquals("", options.distribution.projectSlug)
122+
assertEquals("", options.distribution.orgAuthToken)
123+
}
124+
125+
@Test
126+
fun `does not apply empty string values`() {
127+
val properties = Properties()
128+
properties.setProperty("io.sentry.distribution.org-slug", "")
129+
properties.setProperty("io.sentry.distribution.project-slug", "")
130+
properties.setProperty("io.sentry.distribution.auth-token", "")
131+
properties.setProperty("io.sentry.distribution.build-configuration", "")
132+
133+
val options = SentryOptions()
134+
DebugMetaPropertiesApplier.apply(options, listOf(properties))
135+
136+
assertEquals("", options.distribution.orgSlug)
137+
assertEquals("", options.distribution.projectSlug)
138+
assertEquals("", options.distribution.orgAuthToken)
139+
assertNull(options.distribution.buildConfiguration)
140+
}
141+
}

0 commit comments

Comments
 (0)