Step 1 of M8 (docs/android/PLAN.md item 9).
- compileSdk/targetSdk 36 (Play's floor since 2026-08-31). AGP 8.6.1
cannot build against 36, so AGP goes to 8.13.2 (the last 8.x) with the
Gradle 8.14.3 wrapper. Kotlin, KSP and Hilt are unchanged. All three
workflows install platforms;android-36; AGP 8.13 still defaults to
build-tools 35.0.0.
- release.yml also runs bundleRelease, signed with the same keystore,
and attaches the .aab to the Gitea release beside the APK (the first
bundle has to be uploaded by hand, and this is where it comes from).
- A last step uploads the bundle to Play's internal track through the
Play Developer API v3 edit flow. The OAuth token comes from a
service-account JWT signed with openssl; the key is the new
PLAY_SERVICE_ACCOUNT_JSON secret. While that secret is unset, the
step warns and skips. The step runs after the Gitea release, so a
Play failure never holds back the APK.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Fix the SonarQube coverage gate (0% on new code) — a reporting gap, not a
testing gap: the JVM unit suite already exists but the source-only scan
never received a coverage report.
- app/build.gradle.kts: apply jacoco, enable debug unit-test coverage, add a
jacocoTestReport task (excludes generated/Hilt/Compose-singleton classes)
- sonar-project.properties: consume the JaCoCo XML; exclude pure-@Composable
UI from coverage (JVM unit tests can't execute composable bodies)
- .gitea/workflows/sonarqube.yml: run JDK 17 + Android SDK +
`testDebugUnitTest jacocoTestReport` before the scan
Also clear the three actionable code smells: remove an unused import
(AdminContentScreen), remove an unused parameter (AdminSupportScreen.
RespondDialog), and decompose LoginViewModel.submit() (cognitive complexity
20 -> under 15). The remaining 12 smells (snake_case DTO fields that mirror
the JSON wire contract; Compose/nav complexity) are marked Won't Fix in
SonarQube with rationale.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgyHnrNa8WwG3doxvxjuCr
Mirrors the website repo's setup: a source-based scan of app/src/main
(Kotlin) that reports to the self-hosted SonarQube server after merge,
never gating PRs.
Uses the existing SonarQube project key Runic-Gateway-Android-app (the
server rejects re-creating a case-variant key). Supersedes #18.
Co-Authored-By: Claude <noreply@anthropic.com>