Merge main into feat-164-reorder-accounts

This commit is contained in:
Jason Ross
2026-07-03 13:15:27 -05:00
committed by GitHub
2 changed files with 40 additions and 9 deletions
+22 -4
View File
@@ -1,6 +1,6 @@
---
name: preflight
description: Run LibreMail's fast CI gate locally (assembleDebug + testDebugUnitTest + compileDebugAndroidTestKotlin + lintDebug + ktlintCheck + detekt) before pushing or opening a PR. Mirrors the merge gate; does NOT run emulator E2E. Use before treating a change as done.
description: Run LibreMail's fast CI gate locally (assembleDebug + testDebugUnitTest + compileDebugAndroidTestKotlin + lintDebug + ktlintCheck + detekt) plus the latest-API-level emulator E2E before pushing or opening a PR. Mirrors the merge gate and runs the highest-API E2E via its Gradle Managed Device; the full multi-API matrix stays CI-only. Use before treating a change as done.
---
# /preflight
@@ -13,6 +13,12 @@ Run the same fast checks CI enforces on every PR, in order, and report the outco
with a JDK/AGP version mismatch, check `java -version` / `JAVA_HOME` and point it at a 17–21
JDK (e.g. Android Studio's bundled JBR) before retrying.
- PowerShell: invoke the wrapper as `.\gradlew`. Git Bash / the Bash tool: `./gradlew`.
- The final E2E step boots an emulator through a Gradle Managed Device, so the host needs
hardware acceleration (WHPX on Windows, KVM on Linux, HVF on macOS). Gradle downloads the
system image and boots/tears down the AVD itself — no manual emulator setup — but the first
run is slow while the image downloads. If the host has no accelerated emulator and the
managed device cannot boot, report the E2E step as not run rather than treating the gate as
green.
## Steps
@@ -24,6 +30,7 @@ Run these, stopping at the first failure:
./gradlew :app:compileDebugAndroidTestKotlin
./gradlew :app:lintDebug
./gradlew :app:ktlintCheck :app:detekt
./gradlew :app:api36DebugAndroidTest # latest-API emulator E2E (highest level in the matrix)
```
`compileDebugAndroidTestKotlin` compiles the `androidTest` source set — the E2E/instrumented
@@ -37,13 +44,24 @@ merge gate even when the build and lint are green. Add `--continue` to any comma
`:app:ktlintCheck :app:detekt --continue`) to collect every failure in one pass instead of
stopping at the first.
`api36DebugAndroidTest` is last because it is the slowest: it runs the full instrumented/E2E
suite on `api36` — the highest API level in the E2E matrix — via its Gradle Managed Device,
which Gradle provisions, boots, and tears down automatically. This one latest-API level is the
E2E that preflight runs locally and it must pass; CI fans the same suite out across the whole
API matrix (plus the API 37 preview job). Keep `api36DebugAndroidTest` in lockstep with the
highest managed device in `app/build.gradle.kts` and the E2E matrix in
`.github/workflows/ci.yml` — when a newer API level is added there, run that one instead.
## Reporting
- If everything passes, say so plainly (e.g. "preflight green: build, unit tests, lint, ktlint, detekt").
- If everything passes, say so plainly (e.g. "preflight green: build, unit tests, lint, ktlint, detekt, api36 E2E").
- On failure, surface the actual Gradle error and point at the relevant report:
- unit tests → `app/build/reports/tests/testDebugUnitTest/`
- lint → `app/build/reports/lint-results-debug.html`
- ktlint → `app/build/reports/ktlint/` (per source set, e.g. `ktlintTestSourceSetCheck/`)
- detekt → `app/build/reports/detekt/`
- Do **not** run emulator/E2E (`connectedDebugAndroidTest`) here — that's CI's job unless the
user explicitly asks.
- E2E → `app/build/reports/androidTests/managedDevice/` (per-device HTML, e.g. `.../api36/`)
- Run only the **latest-API** E2E here (`api36DebugAndroidTest`, the highest level in the
matrix); the full multi-API matrix and the API 37 preview job stay CI's job. If the host has
no accelerated emulator and the managed device cannot boot, report that E2E could not run
rather than treating the gate as green.
+18 -5
View File
@@ -28,11 +28,15 @@ or via Gradle Managed Devices `./gradlew e2eGroupDebugAndroidTest` (whole matrix
**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.
`detekt` + the latest-API emulator E2E `api36DebugAndroidTest` (the `/preflight` skill does
all of this). `compileDebugAndroidTestKotlin` compiles the `androidTest` source set that the
static part 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. `api36DebugAndroidTest` runs the instrumented/E2E suite on API 36 — the highest
API level in the E2E matrix — via its Gradle Managed Device (Gradle boots and tears down the
emulator automatically). Running that one latest-API level locally is required; the full
multi-API matrix (and the API 37 preview job) stays CI's job.
## Build-config gotchas
@@ -61,6 +65,15 @@ JVM unit tests use JUnit4 + `kotlin.test`, **Turbine** for `Flow`, **MockK** for
**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.
## Definition of done
A change is not done until it ships with passing **unit tests** and **E2E/instrumented tests**
that exercise the new or changed behaviour. Writing and committing that E2E/instrumented test
is a required part of every task — and the test must actually **run and pass**, not merely
compile: preflight runs the latest-API-level emulator E2E locally (`api36DebugAndroidTest`, the
highest API level in the E2E matrix and its Gradle Managed Device task) and it must be green
before the change is done. CI then runs the full multi-API matrix.
## Repo etiquette
- Branch off `main`; branch names like `feat-…` / `fix-…`. PRs target `main` and must pass