Skip to content

Commit b66ec62

Browse files
antonisclaude
andauthored
fix(android): replace tasks.findAll with tasks.named() to fix AGP Artifacts API conflict (#5714)
* fix(android): replace tasks.findAll with tasks.named() to fix AGP Artifacts API conflict tasks.findAll iterates the entire task container, realizing every lazily-registered task as a side effect. This broke two distinct scenarios: - react-native-legal (issue #5236): AboutLibraries registers tasks lazily via tasks.register(); eager realization during onVariants caused a build crash. - Fullstory / AGP Artifacts API (issue #5698): AGP Artifacts API transforms (e.g. variant.artifacts.use().wiredWithDirectories().toTransformMany()) must be registered before the artifact chain is finalized. Realizing AGP's internal tasks inside onVariants locks the APK artifact prematurely, causing the APK to land in build/intermediates/ instead of build/outputs/. Fix: predict the two known RN bundle task names from the variant name (createBundle${Variant}JsAndAssets / bundle${Variant}JsAndAssets), check existence with tasks.names.contains() (no realization), then wire lazily via tasks.named(). A warn() is emitted when neither task is found so the skip is observable. Additional changes: - Add || currentVariants.isEmpty() guard to prevent orphan upload-task registration - Remove redundant bundleTask.configure { finalizedBy } nesting (already inside configure) Fixes #5698 Related: #5236, #5253 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Adds changelog * fix(android): fix variant capitalization and task timing in sentry.gradle - Replace v.name.capitalize() with substring(0,1).toUpperCase()+substring(1) so that flavored variants like freeRelease produce FreeRelease (not Freerelease), matching React Native's bundle task naming convention. - Replace tasks.named() with tasks.configureEach + name-set filter to handle bundle tasks registered after sentry's onVariants callback fires (e.g. when sentry.gradle is applied before the React Native plugin). configureEach does not iterate or realize the task container so the Fullstory AGP Artifacts API fix (#5698) and react-native-legal fix (#5236) are preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): restore missing bundle task warning via taskGraph.whenReady Re-adds the diagnostic warn() that was lost when switching from tasks.named() to tasks.configureEach. The check is deferred to gradle.taskGraph.whenReady so all plugins' onVariants callbacks (including the RN plugin's) have completed and tasks.names reflects the full set of registered tasks before we decide to emit the warning. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): move bundle task lookup to afterEvaluate, restore warning Follow the SAGP pattern (sentry-android-gradle-plugin/util/tasks.kt): register project.afterEvaluate{} inside onVariants{} so that task lookup is deferred until after all plugins have registered their tasks. onVariants fires during project evaluation — before the task container is complete — so tasks.configureEach registered there could miss late-registered bundle tasks. afterEvaluate runs after all onVariants callbacks (including the React Native plugin's) have completed, making tasks.names reliable. Replaces tasks.configureEach + gradle.taskGraph.whenReady with: - project.afterEvaluate for timing - tasks.names.contains() guard with inline warn() for missing tasks - tasks.named() for a targeted lazy reference (no container iteration) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): resolve AGP variant data inside onVariants, not afterEvaluate AGP Variant objects (outputs, applicationId, versionCode/versionName providers) are only valid inside the onVariants callback. Using them inside project.afterEvaluate{} can trigger late variant API access errors. Pre-extract all AGP-dependent data as plain values before registering the afterEvaluate block: - variantName (String) from v.name - variantApplicationId (String) from v.applicationId.get() - variantOutputsData (List<Map>) from v.outputs with all providers resolved Update extractCurrentVariants() to accept these plain values instead of the AGP Variant object so no AGP API is called outside onVariants. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): remove afterEvaluate wrapper, fix indentation in sentry.gradle project.afterEvaluate{} is not needed: bundle tasks are already registered by the time onVariants fires, matching the timing of the original tasks.findAll. Moving the tasks.names.contains() check and tasks.named().configure{} directly into onVariants keeps the fix simple and avoids the regression risk that afterEvaluate introduced in the earlier PR #5690. Also fixes the indentation of the ~240-line configure{} closure body so it is visually distinct from the enclosing onVariants block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): pre-register sentry tasks in onVariants to fix Gradle 8.x Gradle 8.x forbids tasks.register() inside a task configuration action (the closure passed to tasks.named().configure {}). The previous change wrapped the entire sentry task setup in tasks.named(bundleTaskName).configure {}, which triggered the restriction when the RN bundle task was being created: DefaultTaskContainer#register(String, Action) on task set cannot be executed in the current context. Fix: pre-register all sentry task stubs (cliTask, modulesTask, cleanup tasks) directly in onVariants where task registration is always allowed. The tasks.named().configure {} block now only calls .configure {} on already-registered tasks and wires finalizedBy/dependsOn — both of which are allowed inside configuration actions. extractCurrentVariants() is now called in onVariants using the bundle task name as a proxy (the helper only reads bundleTask.name), so currentVariants is available before tasks.named().configure {} is reached. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): use ctx map to avoid TaskProvider.configure inside configure action Gradle 8.14.3 also forbids TaskProvider.configure(Action) inside a task configuration action, not just tasks.register(). The previous fix moved tasks.register() out but left tasks.named(other).configure {} calls inside bundleTask.configure {}, which triggered: DefaultTaskContainer#NamedDomainObjectProvider.configure(Action) on task set cannot be executed in the current context. Fix: introduce a shared mutable context map (ctx) that task action closures (doFirst/doLast/onlyIf/delete) capture by reference. The tasks are fully registered and wired in onVariants — including their complete doFirst/doLast logic referencing ctx. bundleTask.configure {} now does exactly two things: populate ctx from the bundle task's properties, and call bundleTask.finalizedBy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(android): add Gradle test-repro for task-realization regressions Adds a self-contained Android project under packages/core/test-repro/ that verifies two canary regressions: - CANARY 1 (#5236, react-native-legal): sentry.gradle must not realize lazily-registered tasks by iterating the task container (tasks.findAll). - CANARY 2 (#5698, Fullstory): sentry.gradle must not configure the fullstoryTransformRelease task before AGP's onVariants wires it via toTransformMany(), otherwise the APK lands in build/intermediates/ instead of build/outputs/. Includes stubs for multiple approaches under test: - sentry-main.gradle → tasks.findAll in onVariants (❌ both canaries fail) - sentry-noop.gradle → baseline no-op (✅ both canaries pass) - sentry-named.gradle → tasks.names.contains + tasks.named (✅ our fix) - sentry-configureEach.gradle → tasks.configureEach alternative (✅) - sentry-afterEvaluate.gradle → afterEvaluate + tasks.named (✅) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Revert "test(android): add Gradle test-repro for task-realization regressions" This reverts commit 513a738. * fix(android): replace tasks.findAll with tasks.named to fix AGP Artifacts API conflict tasks.findAll iterates the entire task container, realizing every lazily- registered task regardless of whether it matches the predicate. This caused two distinct issues: - react-native-legal (#5236): AboutLibraries tasks were realized as a side-effect of container iteration. - Fullstory / AGP Artifacts API (#5698): fullstoryTransformRelease was configured before AGP's toTransformMany() wired its artifact paths, causing the APK to land in build/intermediates/ instead of build/outputs/. Fix: predict the bundle task name from the variant name and use tasks.names.contains() (no realization) to check existence, then tasks.named().get() to obtain only that specific task. The rest of the task registration logic is unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(android): simplify variant capitalization using Groovy capitalize() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fd44e01 commit b66ec62

2 files changed

Lines changed: 14 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
### Fixes
1212

13+
- Fix AGP Artifacts API conflict caused by eager task realization in `sentry.gradle` ([#5714](https://github.com/getsentry/sentry-react-native/pull/5714))
1314
- Fix Android crash on app launch caused by version mismatch between Sentry Android SDK and Sentry Android Gradle Plugin ([#5726](https://github.com/getsentry/sentry-react-native/pull/5726))
1415

1516
### Dependencies

packages/core/sentry.gradle

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,19 @@ plugins.withId('com.android.application') {
6767

6868
androidComponents.onVariants(androidComponents.selector().all()) { v ->
6969
if (!v.name.toLowerCase().contains("debug")) {
70-
// separately we then hook into the bundle task of react native to inject
71-
// sourcemap generation parameters. In case for whatever reason no release
72-
// was found for the asset folder we just bail.
73-
def bundleTasks = tasks.findAll { task -> (task.name.startsWith("createBundle") || task.name.startsWith("bundle")) && task.name.endsWith("JsAndAssets") && !task.name.contains("Debug") && task.enabled }
74-
bundleTasks.each { bundleTask ->
70+
// Hook into the bundle task of react native to inject sourcemap generation parameters.
71+
// tasks.names.contains() checks task existence without iterating the container, avoiding
72+
// eager realization of unrelated tasks (fixes #5698, Fullstory AGP Artifacts API).
73+
def variantCapitalized = v.name.capitalize()
74+
def sentryBundleTaskName = ["createBundle${variantCapitalized}JsAndAssets", "bundle${variantCapitalized}JsAndAssets"].find { tasks.names.contains(it) }
75+
if (sentryBundleTaskName == null) {
76+
project.logger.warn("[sentry] No bundle task found for variant '${v.name}'. " +
77+
"Expected 'createBundle${variantCapitalized}JsAndAssets' or " +
78+
"'bundle${variantCapitalized}JsAndAssets'. Source maps will not be uploaded.")
79+
return
80+
}
81+
def bundleTask = tasks.named(sentryBundleTaskName).get()
82+
if (bundleTask.enabled) {
7583
def shouldCleanUp
7684
def sourcemapOutput
7785
def bundleOutput

0 commit comments

Comments
 (0)