Files
LibreMail/CLAUDE.md
T
JMR-devandClaude Opus 4.8 3728efb55e chore(preflight): compile androidTest source set in the fast gate
assembleDebug, testDebugUnitTest, and lintDebug never compile the
androidTest source set, so a change that breaks it (e.g. an
instrumented test calling a UI API that just changed signature) passed
preflight locally yet only failed once CI ran. Add
:app:compileDebugAndroidTestKotlin to the fast gate to catch that
class of breakage before pushing, and update CLAUDE.md's summary of
the gate to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:27:12 -05:00

69 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
LibreMail is a GPL-3.0 Android email client (Kotlin, Jetpack Compose, Material 3).
See `@README.md` for OAuth/account setup (Gmail, Outlook), the tech stack, and the
offline-first architecture — this file only covers what isn't obvious from the code.
## Build, test, lint
Use a **JDK 17–21** for the Gradle daemon. AGP 9.2 does **not** support JDK 25 — if
`JAVA_HOME` points at 25+, builds fail. Commands (PowerShell: use `.\gradlew`):
```bash
./gradlew :app:assembleDebug # build debug APK
./gradlew :app:testDebugUnitTest # JVM unit tests
./gradlew :app:lintDebug # Android lint
./gradlew :app:ktlintCheck :app:detekt # static analysis (CI's "Static analysis" gate)
# single unit test:
./gradlew :app:testDebugUnitTest --tests "org.libremail.data.SomeClassTest"
```
E2E/instrumented tests need a booted emulator: `./gradlew :app:connectedDebugAndroidTest`,
or via Gradle Managed Devices `./gradlew e2eGroupDebugAndroidTest` (whole matrix) /
`./gradlew api29DebugAndroidTest` (one API level). The managed-device list in
`app/build.gradle.kts` must stay in lockstep with the E2E matrix in `.github/workflows/ci.yml`.
**Before treating a change as done**, run the fast CI gate: `assembleDebug` +
`testDebugUnitTest` + `compileDebugAndroidTestKotlin` + `lintDebug` + `ktlintCheck` +
`detekt` (the `/preflight` skill does this). `compileDebugAndroidTestKotlin` compiles the
`androidTest` source set that the rest of the gate skips, catching E2E/instrumented-test
compile errors before they surface only in CI. `ktlintCheck`/`detekt` cover the
`test`/`androidTest` source sets that `lintDebug` skips, so they catch style violations that
would otherwise fail CI's Static analysis gate. Emulator E2E is left to CI unless asked.
## Build-config gotchas
- **Built-in Kotlin (AGP 9.x).** Kotlin compilation is handled by AGP's built-in Kotlin;
the Kotlin version (2.4.0) is pinned via the root `build.gradle.kts` buildscript classpath.
**Never apply the `org.jetbrains.kotlin.android` plugin** — it throws a ClassCastException
against AGP 9's DSL. (The `kotlin-android` alias in `libs.versions.toml` exists but must
not be used.) `libs.versions.toml` still supplies all *library* versions.
- **KSP, not KAPT** for all annotation processing (Hilt, Room).
- Room schemas are exported to `app/schemas` and validated by migration tests — commit
schema changes.
- OAuth client IDs come from `secrets.properties` (git-ignored) via `BuildConfig`; the
build works without it (empty/placeholder values).
## Code conventions
- Sources live under `app/src/{main,test,androidTest}/kotlin/`; package root `org.libremail`
(applicationId `org.libremail.app`).
- **Every source file starts with** `// SPDX-License-Identifier: GPL-3.0-or-later` (or the
`<!-- ... -->` form for XML/Markdown). All 117 current `.kt` files follow this.
- `kotlin.code.style=official`.
## Testing
JVM unit tests use JUnit4 + `kotlin.test`, **Turbine** for `Flow`, **MockK** for mocks,
**GreenMail** for a real in-process IMAP/SMTP server, and coroutines-test. `org.json` is
pulled in as a real dependency for unit tests because `android.jar`'s version is a no-op stub.
## Repo etiquette
- Branch off `main`; branch names like `feat-…` / `fix-…`. PRs target `main` and must pass
the `CI passed` gate.
- **Conventional Commits** for commit subjects and PR titles: `type(scope): summary`
(`feat`, `fix`, `chore`, …), matching existing history.