Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Add `installGroupsOverride` parameter and `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))

### Internal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal class DistributionHttpClient(private val options: SentryOptions) {
val versionCode: Long,
val versionName: String,
val buildConfiguration: String,
val installGroupsOverride: List<String>? = null,
)

/**
Expand Down Expand Up @@ -58,6 +59,9 @@ internal class DistributionHttpClient(private val options: SentryOptions) {
append("&build_number=${URLEncoder.encode(params.versionCode.toString(), "UTF-8")}")
append("&build_version=${URLEncoder.encode(params.versionName, "UTF-8")}")
append("&build_configuration=${URLEncoder.encode(params.buildConfiguration, "UTF-8")}")
params.installGroupsOverride?.forEach { group ->
append("&install_groups=${URLEncoder.encode(group, "UTF-8")}")
}
}
val url = URL(urlString)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ internal class UpdateResponseParser(private val options: SentryOptions) {
val downloadUrl = json.optString("download_url", "")
val appName = json.optString("app_name", "")
val createdDate = json.optString("created_date", "")
val installGroups = parseInstallGroups(json)

// Validate required fields (optString returns "null" for null values)
val missingFields = mutableListOf<String>()
Expand All @@ -77,6 +78,26 @@ internal class UpdateResponseParser(private val options: SentryOptions) {
)
}

return UpdateInfo(id, buildVersion, buildNumber, downloadUrl, appName, createdDate)
return UpdateInfo(
id,
buildVersion,
buildNumber,
downloadUrl,
appName,
createdDate,
installGroups,
)
}

private fun parseInstallGroups(json: JSONObject): List<String>? {
val installGroupsArray = json.optJSONArray("install_groups") ?: return null
val installGroups = mutableListOf<String>()
for (i in 0 until installGroupsArray.length()) {
val group = installGroupsArray.optString(i)
if (group.isNotEmpty() && group != "null") {
installGroups.add(group)
}
}
return if (installGroups.isEmpty()) null else installGroups
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class UpdateResponseParserTest {
"build_number": 42,
"download_url": "https://example.com/download",
"app_name": "Test App",
"created_date": "2023-10-01T00:00:00Z"
"created_date": "2023-10-01T00:00:00Z",
"install_groups": ["beta", "internal"]
},
"current": null
}
Expand All @@ -49,6 +50,7 @@ class UpdateResponseParserTest {
assertEquals("https://example.com/download", updateInfo.downloadUrl)
assertEquals("Test App", updateInfo.appName)
assertEquals("2023-10-01T00:00:00Z", updateInfo.createdDate)
assertEquals(listOf("beta", "internal"), updateInfo.installGroups)
}

@Test
Expand Down Expand Up @@ -355,4 +357,103 @@ class UpdateResponseParserTest {
error.message.contains("Missing required fields in API response: id"),
)
}

@Test
fun `parseResponse returns null installGroups when not present`() {
val responseBody =
"""
{
"update": {
"id": "update-123",
"build_version": "2.0.0",
"build_number": 42,
"download_url": "https://example.com/download",
"app_name": "Test App",
"created_date": "2023-10-01T00:00:00Z"
}
}
"""
.trimIndent()

val result = parser.parseResponse(200, responseBody)

assertTrue("Should return NewRelease", result is UpdateStatus.NewRelease)
val updateInfo = (result as UpdateStatus.NewRelease).info
assertEquals(null, updateInfo.installGroups)
}

@Test
fun `parseResponse returns null installGroups when array is empty`() {
val responseBody =
"""
{
"update": {
"id": "update-123",
"build_version": "2.0.0",
"build_number": 42,
"download_url": "https://example.com/download",
"app_name": "Test App",
"created_date": "2023-10-01T00:00:00Z",
"install_groups": []
}
}
"""
.trimIndent()

val result = parser.parseResponse(200, responseBody)

assertTrue("Should return NewRelease", result is UpdateStatus.NewRelease)
val updateInfo = (result as UpdateStatus.NewRelease).info
assertEquals(null, updateInfo.installGroups)
}

@Test
fun `parseResponse returns null installGroups when array is null`() {
val responseBody =
"""
{
"update": {
"id": "update-123",
"build_version": "2.0.0",
"build_number": 42,
"download_url": "https://example.com/download",
"app_name": "Test App",
"created_date": "2023-10-01T00:00:00Z",
"install_groups": null
}
}
"""
.trimIndent()

val result = parser.parseResponse(200, responseBody)

assertTrue("Should return NewRelease", result is UpdateStatus.NewRelease)
val updateInfo = (result as UpdateStatus.NewRelease).info
assertEquals(null, updateInfo.installGroups)
}

@Test
fun `parseResponse returns single installGroup`() {
val responseBody =
"""
{
"update": {
"id": "update-123",
"build_version": "2.0.0",
"build_number": 42,
"download_url": "https://example.com/download",
"app_name": "Test App",
"created_date": "2023-10-01T00:00:00Z",
"install_groups": ["beta-testers"]
}
}
"""
.trimIndent()

val result = parser.parseResponse(200, responseBody)

assertTrue("Should return NewRelease", result is UpdateStatus.NewRelease)
val updateInfo = (result as UpdateStatus.NewRelease).info
assertEquals(listOf("beta-testers"), updateInfo.installGroups)
}
}
3 changes: 2 additions & 1 deletion sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -4521,13 +4521,14 @@ public class io/sentry/UncaughtExceptionHandlerIntegration$UncaughtExceptionHint
}

public final class io/sentry/UpdateInfo {
public fun <init> (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
public fun <init> (Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V
public fun getAppName ()Ljava/lang/String;
public fun getBuildNumber ()I
public fun getBuildVersion ()Ljava/lang/String;
public fun getCreatedDate ()Ljava/lang/String;
public fun getDownloadUrl ()Ljava/lang/String;
public fun getId ()Ljava/lang/String;
public fun getInstallGroups ()Ljava/util/List;
public fun toString ()Ljava/lang/String;
}

Expand Down
12 changes: 11 additions & 1 deletion sentry/src/main/java/io/sentry/UpdateInfo.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry;

import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -13,20 +14,23 @@ public final class UpdateInfo {
private final @NotNull String downloadUrl;
private final @NotNull String appName;
private final @Nullable String createdDate;
private final @Nullable List<String> installGroups;

public UpdateInfo(
final @NotNull String id,
final @NotNull String buildVersion,
final int buildNumber,
final @NotNull String downloadUrl,
final @NotNull String appName,
final @Nullable String createdDate) {
final @Nullable String createdDate,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change to the constructor. I don't think the constructor is used directly by consumers so it is fine.

final @Nullable List<String> installGroups) {
this.id = id;
this.buildVersion = buildVersion;
this.buildNumber = buildNumber;
this.downloadUrl = downloadUrl;
this.appName = appName;
this.createdDate = createdDate;
this.installGroups = installGroups;
}

public @NotNull String getId() {
Expand All @@ -53,6 +57,10 @@ public int getBuildNumber() {
return createdDate;
}

public @Nullable List<String> getInstallGroups() {
return installGroups;
}

@Override
public String toString() {
return "UpdateInfo{"
Expand All @@ -73,6 +81,8 @@ public String toString() {
+ ", createdDate='"
+ createdDate
+ '\''
+ ", installGroups="
+ installGroups
+ '}';
}
}
Loading