Skip to content

[Crashlytics] Fix release build cache invalidation#8185

Open
jrodiz wants to merge 4 commits into
firebase:mainfrom
jrodiz:feature/jrc--6770.Fix.release.build.cache.invalidation
Open

[Crashlytics] Fix release build cache invalidation#8185
jrodiz wants to merge 4 commits into
firebase:mainfrom
jrodiz:feature/jrc--6770.Fix.release.build.cache.invalidation

Conversation

@jrodiz
Copy link
Copy Markdown
Contributor

@jrodiz jrodiz commented May 20, 2026

Crashlytics: keep release mapping file id stable across builds

injectCrashlyticsMappingFileIdRelease generated a new random UUID on every release build, cascading through mergeReleaseResourcesprocessReleaseResourcesminifyReleaseWithR8 → packaging and breaking the build cache for every minified release.

This PR makes the task idempotent: it reuses the on-disk id when valid for the current mode, and only mints a fresh UUID on the first build (or after clean), or when mappingFileUploadEnabled flips.

Changes

A) Modify InjectMappingFileIdTask.kt:

  1. Idempotent action: when useBlankMappingFileId is false, reuse the on-disk id if non-blank; only call generateMappingFileId() when missing.
  2. Up-to-date predicate: outputs.upToDateWhen { ... } returns true when the on-disk id matches the current mode (blank vs. non-blank).
  3. Replaced blankMappingFileIdExists() with existingMappingFileId(): String?.

addGeneratedSourceDirectory wiring is unchanged — the SDK still reads the id via CommonUtils.getMappingFileId(context).

B) Added to TypicalAppFunctionalTests.kt:

  • is UP_TO_DATE on second invocation
  • release mapping file id resource is preserved across rebuilds (byte-equality)
  • task re-runs after clean
  • toggling mappingFileUploadEnabled invalidates the task

Risks / trade-offs

  • Reused id across release APKs without clean: shipping two minified releases without ./gradlew clean between them means both APKs share an id but have different mapping content; the second upload overwrites the first in Crashlytics. CI/CD release pipelines typically clean per release. This is the explicit trade-off injectCrashlyticsMappingFileIdRelease causes every release build to be invalidated #6770 accepts.
  • No SDK runtime change; configuration-cache compatibility preserved; first-build/post-clean behavior unchanged.

Test plan

  • CI: firebase-crashlytics-gradle:functionalTest and :test pass.
  • compileKotlin, compileFunctionalTestKotlin, test — pass.
  • Manual: run ./gradlew assembleRelease twice in a minified sample — task and downstream stay UP_TO_DATE.
  • Manual: toggle mappingFileUploadEnabled = false — task re-runs, resource becomes blank id.

Verification from manual test plan above

  • End-to-end manual verification in a real Android app: github.com/jrodiz/repro6770 (AGP 9.1.0-alpha05, Gradle 9.2.1, compileSdk 36, isMinifyEnabled = true, real Firebase project).
    • Reproduced the bug against the published pre-fix plugin com.google.firebase.crashlytics:3.0.3mappingFileId.txt flipped every rebuild (f5f0310…6514b43…), and :app:processReleaseResources, :app:uploadCrashlyticsMappingFileRelease, :app:packageRelease, :app:assembleRelease all re-executed with no source changes.
    • Verified the fix by publishing this branch to mavenLocal() as 3.0.7 and bumping the app's plugin version — mappingFileId.txt stays byte-identical across rebuilds, :app:injectCrashlyticsMappingFileIdRelease reports UP-TO-DATE, and the full downstream cascade (:mergeReleaseResources, :processReleaseResources, :minifyReleaseWithR8, :packageRelease, :assembleRelease) is UP-TO-DATE. Second assembleRelease finishes in ~1s.
    • Verified clean still mints a fresh id, and toggling mappingFileUploadEnabled = false re-runs the task and writes the blank id 0…0.
    • Full transcript with task outcomes and id values in TEST_RESULTS_ISSUE_6770.md.

Fixes #6770

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

@jrodiz jrodiz requested a review from mrober May 20, 2026 00:56
jrodiz added 4 commits May 19, 2026 19:16
Reuse the on-disk id when present and valid for the current mode; only
generate a new UUID on first build, after clean, or when the mode flips.
This lets the task report UP_TO_DATE and stops invalidating downstream
release tasks (mergeResources, R8, packaging, bundling) on every build.

Fixes firebase#6770
Covers: UP_TO_DATE on second run, resource preserved across rebuilds,
re-run after clean, mode-toggle invalidates the task.
Wrap the existingMappingFileId() KDoc to satisfy ktfmt.
@jrodiz jrodiz force-pushed the feature/jrc--6770.Fix.release.build.cache.invalidation branch from b02cde8 to 7e1c779 Compare May 20, 2026 01:16
@Test
fun `injectCrashlyticsMappingFileIdRelease is UP_TO_DATE on second invocation`() {
val first =
GradleRunner.create()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@jrodiz we have a common method for this Gradle block, check

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.

injectCrashlyticsMappingFileIdRelease causes every release build to be invalidated

2 participants