Commit b66ec62
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
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
75 | 83 | | |
76 | 84 | | |
77 | 85 | | |
| |||
0 commit comments