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: 0 additions & 1 deletion .configure-files/sentry.properties.enc

This file was deleted.

6 changes: 1 addition & 5 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

sentry {
projectName = project.findProperty("sentryAndroidProject")?.toString()
projectName = "pocket-casts-android"
}

android {
Expand Down Expand Up @@ -48,10 +48,6 @@ android {

named("release") {
manifestPlaceholders["appIcon"] = "@mipmap/ic_launcher"

if (project.findProperty("sentryAndroidProject")?.toString().isNullOrBlank()) {
println("WARNING: Sentry configuration not found. The ProGuard mapping files won't be uploaded.")
}
}
}

Expand Down
6 changes: 1 addition & 5 deletions automotive/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

sentry {
projectName = project.findProperty("sentryAutomotiveProject")?.toString()
projectName = "pocket-casts-automotive"
}

android {
Expand Down Expand Up @@ -38,10 +38,6 @@ android {

named("release") {
manifestPlaceholders["appIcon"] = "@mipmap/ic_launcher"

if (project.findProperty("sentryAutomotiveProject")?.toString().isNullOrBlank()) {
println("WARNING: Sentry configuration not found. The ProGuard mapping files won't be uploaded.")
}
}
}

Expand Down
18 changes: 16 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.google.devtools.ksp.gradle.KspExtension
import com.google.devtools.ksp.gradle.KspGradleSubplugin
import io.sentry.android.gradle.extensions.InstrumentationFeature
import io.sentry.android.gradle.extensions.SentryPluginExtension
import io.sentry.android.gradle.tasks.SentryCliExecTask
import java.util.EnumSet
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
Expand Down Expand Up @@ -474,9 +475,11 @@ subprojects {
}

fun Project.applyCommonSentryConfiguration() {
val sentryAuthToken = providers.environmentVariable("SENTRY_AUTH_TOKEN").orNull?.trim()?.ifEmpty { null }

extensions.getByType(SentryPluginExtension::class.java).apply {
authToken = project.findProperty("sentryAuthToken")?.toString()
org = project.findProperty("sentryOrg")?.toString()
authToken = sentryAuthToken

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure why this assignment is needed if you already have it above?

You could also keep the fact that it exists or not like val hasSentryAuthToken = providers.environmentVariable("SENTRY_AUTH_TOKEN").map { it.isNotBlank() }.orElse(false) or similar.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Adopted the Provider form in 5dad760, but kept the assignment — it's load-bearing.

Checking the 6.16.0 plugin jar: SentryPluginExtension.authToken is objects.property(String::class.java).convention(null as String?). It has no environment default, so without authToken = … the extension property stays absent. SentryCliExecTask then goes the other way — it exports SENTRY_AUTH_TOKEN into the sentry-cli process from that property. And the extension value isn't only used for that: SentryOrgValueSource, SentryTelemetryService, and the source-bundle/native-symbol registration read it too.

So sentry-cli picking the token up "for free" would rely on it happening to be in the Gradle daemon's inherited environment, which is stale whenever the daemon outlives the shell that started it. The explicit assignment makes it deterministic.

Your second point stands on its own though, so I took it:

val sentryAuthToken = providers.environmentVariable("SENTRY_AUTH_TOKEN").filter { it.isNotBlank() }

authToken = sentryAuthToken
//
if (!sentryAuthToken.isPresent) { throw GradleException(…) }

Same single source for the bound value and the guard, but lazy now — a build that never configures Sentry never resolves the variable. I used filter { it.isNotBlank() } rather than map { … }.orElse(false) so the one provider serves both roles; a blank value stays absent instead of reaching the plugin as "".

Verified against the three env states (unset / set-but-empty / set), with configuration cache on: the extension property reads <absent>, <absent>, dummy-token, and the guard throws, throws, passes.

Posted by Claude Code (Opus 5) on behalf of @mokagio with approval.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correcting myself — I've reverted the provider refactor in 3ad15ee, so this is back to the String? val you commented on.

The refactor was a local improvement that made this repo the odd one out. The same migration already merged elsewhere with the eager read:

  • WordPress-Android#23189WordPress/build.gradle:71, def sentryAuthToken = providers.environmentVariable("SENTRY_AUTH_TOKEN").orNull?.trim() ?: null, bound with authToken = sentryAuthToken and guarded with if (sentryAuthToken == null) on SentryCliExecTask. Same shape as here.
  • simplenote-android#1850Simplenote/build.gradle:77, authToken = providers.environmentVariable("SENTRY_AUTH_TOKEN").orNull (no guard).

The point of this migration is one pattern across the fleet, so consistency wins over the marginally nicer form here.

On the assignment itself: it is needed. In the 6.16.0 plugin jar, SentryPluginExtension.authToken is objects.property(String::class.java).convention(null as String?) — no environment default. SentryCliExecTask goes the other way, exporting SENTRY_AUTH_TOKEN into the sentry-cli process from that property, and SentryOrgValueSource / SentryTelemetryService read it too. Without the assignment we'd be relying on the token happening to sit in the Gradle daemon's inherited environment, which is stale whenever the daemon outlives the shell that started it.

Why takeIf { it.isNotBlank() } here rather than WordPress-Android's ?.trim() ?: null: that form relies on Groovy truth, where "" ?: null is null. In Kotlin the elvis only fires on null, so a set-but-empty variable would sail through as "". Verified both against the four env states — unset, empty, whitespace, real — and they agree.

Posted by Claude Code (Opus 5) on behalf of @mokagio with approval.

@mokagio mokagio Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@iangmaia real Gio here, not a meat proxy.

You could also keep the fact that it exists or not like val hasSentryAuthToken = providers.environmentVariable("SENTRY_AUTH_TOKEN").map { it.isNotBlank() }.orElse(false) or similar.

I updated the implementation in 829a341 and aligned it with the other apps that already do this.

Not sure why this assignment is needed if you already have it above?

My understanding is that the val sentryAuthToken = assigns the token from the env if any making it available to the other steps. The authToken = sentryAuthToken is what passes it to the Sentry plugin itself.

org = "a8c"

val shouldUploadDebugFiles = System.getenv()["CI"].toBoolean() &&
!project.properties["skipSentryProguardMappingUpload"]?.toString().toBoolean()
Expand All @@ -490,6 +493,17 @@ fun Project.applyCommonSentryConfiguration() {
includeDependenciesReport = false
ignoredBuildTypes = setOf("debug", "debugProd", "prototype")
}

tasks.withType<SentryCliExecTask>().configureEach {
doFirst {
if (sentryAuthToken == null) {
throw GradleException(
"SENTRY_AUTH_TOKEN is not set (or is blank). Export it to upload debug files to Sentry, " +
"or pass -PskipSentryProguardMappingUpload=true to skip the upload.",
)
}
}
}
}

tasks.register("aggregatedLintRelease") {
Expand Down
6 changes: 0 additions & 6 deletions dependencies.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,5 @@ project.apply {
set("encryptionKey", secretProperties.getProperty("encryption_key", ""))
set("appSecret", secretProperties.getProperty("app_secret", ""))
set("metaAppId", secretProperties.getProperty("metaAppId", ""))
set("sentryAuthToken", secretProperties.getProperty("sentryAuthToken", ""))
set("sentryOrg", secretProperties.getProperty("sentryOrg", ""))
set("sentryAndroidProject", secretProperties.getProperty("sentryAndroidProject", ""))
set("sentryAutomotiveProject", secretProperties.getProperty("sentryAutomotiveProject", ""))
set("sentryWearProject", secretProperties.getProperty("sentryWearProject", ""))
set("sentryTvProject", secretProperties.getProperty("sentryTvProject", ""))
}
}
6 changes: 1 addition & 5 deletions wear/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ plugins {
}

sentry {
projectName = project.findProperty("sentryWearProject")?.toString()
projectName = "pocket-casts-wear"
}

android {
Expand All @@ -34,10 +34,6 @@ android {

named("release") {
manifestPlaceholders["appIcon"] = "@mipmap/ic_launcher"

if (project.findProperty("sentryWearProject")?.toString().isNullOrBlank()) {
println("WARNING: Sentry configuration not found. The ProGuard mapping files won't be uploaded.")
}
}
}

Expand Down