Skip to content

fix(android): make Sentry Gradle tasks Configuration Cache compatible#6469

Open
fabiendem wants to merge 3 commits into
getsentry:mainfrom
fabiendem:fix/gradle-configuration-cache-sentry-tasks
Open

fix(android): make Sentry Gradle tasks Configuration Cache compatible#6469
fabiendem wants to merge 3 commits into
getsentry:mainfrom
fabiendem:fix/gradle-configuration-cache-sentry-tasks

Conversation

@fabiendem

Copy link
Copy Markdown

📜 Description

Makes the two Sentry Gradle tasks compatible with the Gradle Configuration Cache by removing project-state access at execution time.

Fixes the hard failure reported in #6466 (and the earlier #4252):

Could not evaluate onlyIf predicate for task
  ':app:createBundleReleaseJsAndAssets_SentryUpload_<pkg>@<version>+<code>'.
> Could not evaluate spec for 'Task satisfies onlyIf closure'.

...which also occurs for :app:copySentryJsonConfiguration. These are hard, non-warnable exceptions — org.gradle.configuration-cache.problems=warn does not rescue them.

What changed in packages/core/sentry.gradle.kts

The exec-time project accesses were:

  1. onlyIf { shouldCopySentryOptionsFile() } / onlyIf { shouldSentryAutoUploadGeneral() } — these resolve closures stored in project.extra, so evaluating the onlyIf (at execution time) dereferences project.
  2. copySentryJsonConfiguration's doLast: project.rootDir and copy { … } (i.e. project.copy).
  3. The *_SentryUpload task actions: project.logger and Project.file(...).
  4. resolveSentryCliPackagePath(...) (called from the upload doLast) used .directory(rootDir).

Fixes, all behaviour-preserving and using patterns already present in this file (the CLI itself already runs via an injected ExecOperations):

  • Env reads captured into config-time vals referenced by the onlyIf specs.
  • project.rootDir captured at configuration time.
  • copy { } → an injected FileSystemOperations (InjectedFsOps), mirroring InjectedExecOps.
  • project.logger → the task's own logger.
  • Project.file("$reactRoot/…")File("$reactRoot/…") (path is already absolute).
  • resolveSentryCliPackagePath resolves from reactRoot instead of rootDir.

This is an interim step ahead of the full SAGP migration tracked in getsentry/sentry-android-gradle-plugin#796.

Out of scope (called out for transparency)

resolveSentryReactNativeSDKPath still runs node --print require.resolve(...) as an external process at configuration time. That is a separate, warn-level Configuration Cache problem shared with several other React Native libraries (netinfo, keychain, keyboard-controller, …) and does not fail the build the way the onlyIf did. Left for a follow-up so this PR stays focused on the hard failures.

💡 Motivation and Context

Gradle 9 recommends the Configuration Cache by default and nags on every build; the configuration phase is a meaningful share of Android build time on large RN apps. Today sentry.gradle(.kts) makes the build error out entirely when it's enabled. See #6466 for the full analysis.

💚 How did you test it?

Verified end-to-end on a React Native 0.83.9 app with Gradle 9.0.0 (org.gradle.configuration-cache=true, problems=warn).

Because the released 8.x line still ships the Groovy sentry.gradle (the .kts is a 8.14.0+ rewrite of the same logic), the fix was proven against the equivalent Groovy script installed via 8.10.0, then ported here 1:1 to Kotlin:

Build sentry.gradle Result
Before unpatched Could not evaluate onlyIf predicate for task ':app:copySentryJsonConfiguration'BUILD FAILED
After patched (this change) > Task :app:copySentryJsonConfiguration runs → BUILD SUCCESSFUL

After the fix, the remaining Configuration Cache problems are only the warn-level config-time external-process ones noted above (no sentry.gradle hard failure).

The *_SentryUpload task action changes (logger, file(), resolveSentryCliPackagePath) are the same violation classes; they were applied by static analysis (a real upload run needs live credentials), with copySentryJsonConfiguration as the empirical anchor for the shared onlyIf/project-access mechanism.

📝 Checklist

  • I added a CHANGELOG.md entry (Unreleased → Fixes).
  • No public API changes; no behaviour change.

Closes #6466


Generated with Claude Code

`copySentryJsonConfiguration` and the `*_SentryUpload` tasks no longer read
`project` state at execution time — `onlyIf` predicates resolving closures
from `project.extra`, plus `project.rootDir`, `project.copy`, `project.logger`,
and `Project.file` inside task actions. Environment reads are captured at
configuration time, file copies use an injected `FileSystemOperations`, and
task actions use the task's own `logger`. No behaviour change.

This fixes the hard `Could not evaluate onlyIf predicate` failure when
`org.gradle.configuration-cache=true` (Gradle 9 recommends it by default).

Verified end-to-end on a React Native 0.83.9 app with Gradle 9.0.0: the
equivalent Groovy `sentry.gradle` (shipped in 8.10.0) went from BUILD FAILED
(`Could not evaluate onlyIf predicate for task ':app:copySentryJsonConfiguration'`)
to BUILD SUCCESSFUL with config cache enabled after this change.

See getsentry#6466. Interim step ahead of the SAGP migration
(getsentry/sentry-android-gradle-plugin#796).

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Code <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


  • fix(android): make Sentry Gradle tasks Configuration Cache compatible by fabiendem in #6469

🤖 This preview updates automatically when you update the PR.

Comment thread packages/core/sentry.gradle.kts
@fabiendem
fabiendem marked this pull request as draft July 17, 2026 14:48
Addresses review feedback: capturing `SENTRY_DISABLE_AUTO_UPLOAD` via
`System.getenv` at apply-time ignored a `project.ext.shouldSentryAutoUploadGeneral`
override set right after `apply from` (e.g. the Expo `disableAutoUpload` config
plugin, which injects `project.ext.shouldSentryAutoUploadGeneral = { -> return false }`).
Uploads would then run even when the user disabled them.

Now capture `shouldSentryAutoUploadGeneral()` inside the `onVariants` callback,
which runs after the app `build.gradle` has evaluated, so the override is in
effect. Likewise capture `shouldCopySentryOptionsFile()` via the closure rather
than re-reading the env var, so `project.ext` overrides of it keep working.

Both `onlyIf` specs still reference a captured boolean, so the tasks remain
Configuration Cache compatible, and the original override behavior is restored.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Code <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7d293fd. Configure here.

Comment thread packages/core/sentry.gradle.kts Outdated
Comment thread packages/core/sentry.gradle.kts Outdated
…(CC)

Addresses two more review findings plus a failure surfaced by a full
bundle run under the configuration cache:

1. `copyOptionsFileEnabled` is now a `Property` set in `afterEvaluate` (after
   the app build.gradle evaluates), so a `project.ext.shouldCopySentryOptionsFile`
   override placed after `apply from` is honored — mirroring the deferral
   already applied for `shouldSentryAutoUploadGeneral`.

2. `resolveSentryCliPackagePath(reactRoot)` is now resolved at configuration
   time and captured, instead of being called inside the `*_SentryUpload`
   `doLast` exec closure. A `:app:createBundle...JsAndAssets` run with
   `configuration-cache=true` showed the previous revision still failed at
   execution ("Could not find method resolveSentryCliPackagePath() ... on
   DefaultExecAction_Decorated"): a serialized task action cannot resolve
   top-level script methods.

Verified on a fresh configuration-cache store (React Native 0.83.9,
Gradle 9.0.0): copySentryJsonConfiguration, _SentryUpload, and
_SentryCollectModules execute with no sentry.gradle hard failure. Only the
pre-existing warn-level config-time `require.resolve` external processes
(resolveSentryReactNativeSDKPath / resolveSentryCliPackagePath) remain, which
are out of scope for this PR.

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Code <noreply@anthropic.com>
@fabiendem

Copy link
Copy Markdown
Author

Update — I ran a full :app:createBundleDevGooglePlayReleaseJsAndAssets under --configuration-cache (React Native 0.83.9, Gradle 9.0.0), which actually exercises the *_SentryUpload task that my earlier revisions had only reasoned about statically. That surfaced a real failure I had missed:

Execution failed for task ':app:...JsAndAssets_SentryUpload_...'.
> Could not find method resolveSentryCliPackagePath() for arguments [...] on object of type org.gradle.process.internal.DefaultExecAction_Decorated.

The upload task's doLast called the top-level script method resolveSentryCliPackagePath(reactRoot) at execution time; under the configuration cache a serialized task action can't resolve top-level script methods. Fixed in 98dadca by resolving it at configuration time and capturing the result (mirroring resolveSentryReactNativeSDKPath, which was already resolved at config time).

After that fix, a fresh configuration-cache store shows copySentryJsonConfiguration, _SentryUpload, and _SentryCollectModules all executing with no sentry.gradle hard failure. The only remaining sentry.gradle entries are two warn-level config-time require.resolve external processes (resolveSentryReactNativeSDKPath / resolveSentryCliPackagePath) — the same shared React-Native-ecosystem pattern noted as out of scope in the PR description.

So the change now covers both copySentryJsonConfiguration and _SentryUpload end-to-end (empirically verified, not just by static analysis). Apologies for the earlier over-claim on _SentryUpload.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sentry.gradle.kts still breaks Gradle Configuration Cache on 8.19.0 / Gradle 9 — a small, targeted fix is possible ahead of the SAGP migration (#796)

1 participant