| type | Reference | |||
|---|---|---|---|---|
| title | Android CI workflow | |||
| description | Shape and triage notes for .github/workflows/android.yml. | |||
| tags |
|
|||
| timestamp | 2026-07-31 00:00:00 UTC |
Workflow: .github/workflows/android.yml
pull_requestpush
| Step | Detail |
|---|---|
| Runner | ubuntu-latest, 30m timeout |
| Checkout | actions/checkout (pinned) |
| Cache | ~/.gradle/caches, ~/.gradle/wrapper keyed on Gradle files |
| JDK | Temurin 21 |
| Build | ./scripts/build.sh |
| On failure | ./scripts/print_build_logs.sh |
Canonical owner for the CI unit-path step list. Script: scripts/build.sh.
- Copy
library/google-services.json→app/andproguard-tests/ ./gradlew --max-workers=2 clean./gradlew --max-workers=2 assembleDebug./gradlew --max-workers=2 proguard-tests:build— the R8 gate, detail below./gradlew --max-workers=2 checkstyle./gradlew --max-workers=2 testDebugUnitTest -x :e2eTest:testDebugUnitTest
Step 5 is Java-only (include("**/*.java")), so it inspects zero files in the Kotlin modules — Kotlin blind spot. Android Lint covers that gap and runs in its own workflow, not in build.sh — see below.
:proguard-tests is a source-less application module that depends on :auth, :firestore, :database and :storage and builds its release variant with isMinifyEnabled = true, so minifyReleaseWithR8 is the only place the libraries' consumer ProGuard rules are ever applied. Each library's own release build sets isMinifyEnabled = false. consumerProguardFiles is declared by :auth (auth-proguard.pro), :firestore and :database (proguard-rules.pro each); :storage and :common declare none, though AGP also merges rules generated by annotation processors. The gate is sensitive: removing -dontwarn com.facebook.** from auth-proguard.pro fails minifyReleaseWithR8, because :auth takes facebook-login as compileOnly. It proves the rules shrink and package, not that the shrunk app behaves correctly at runtime.
The module's beforeVariants filter disables its debug variant when CI=true, so CI builds the release variant only; a local run of the script builds both.
Lint footprint. build depends on check, which depends on lint, so this step runs Android Lint too. On CI that is :proguard-tests:lintRelease; locally, with CI unset, it is :proguard-tests:lintDebug — the ungated debug variant lintAll does not cover, so a debug-only finding can redden a local build.sh while CI stays green. Either way lint analysis fans out to the library dependencies (:auth, :common, :database, :firestore, :storage, plus :internal:lintchecks locally, since :auth takes it as debugImplementation), because AGP builds a lint model for each; only the report is scoped to :proguard-tests. Two consequences: it duplicates analysis lintAll already does, and since the step sits at position 4 of 6 under set -e, a finding here aborts the run before checkstyle and before every unit-test result — the same masking that kept lint out of this script in the first place (below). Drop to :proguard-tests:assembleRelease if that trade stops being worth it.
Separate workflow, pull_request only, running ./gradlew --max-workers=2 lintAll.
lintAll is registered in the root build.gradle.kts and gates all 10 Android modules. The strictness flags and the common disable set live in a shared policy in that same file, applied to every module that applies the application or library plugin; a module's own lint { } block carries only its module-specific disables.
It is a separate workflow rather than a step in build.sh for two reasons. Lint measured ~4-5 minutes on this repo — the build job went from 3-6 min to 8-11 min when it was inline — so running it in parallel roughly halves PR feedback time at about the same total runner cost, since the extra compile the lint job pays is the one build.sh stops paying (lintAnalyze depends on compileDebugKotlin, and there is no remote build cache: Develocity here is configured for build scans only). And under set -e an inline lint failure aborted the run before testDebugUnitTest, so one new finding cost you every test result for that run.
The workflow copies library/google-services.json into app/ and proguard-tests/ before running, because lintAll gates :proguard-tests:lintRelease and that module applies the google-services plugin.
- Match this path locally with
./scripts/build.sh— agent command policy. - Do not treat this job as e2e coverage; that is e2e.md.