Sample Android app (PipelineGenericAndroid) with GitHub Actions CI/CD aligned to the Pipeline-Generic iOS template: reusable jobs, Debug APK artifact, unit tests with a JaCoCo line-coverage gate, release AAB on main/master, detekt / ktlint / Android Lint, CodeQL, and Semgrep-based security scanning.
- Package / applicationId:
com.codeandtheory.pipelinegeneric - UI: Jetpack Compose (“Hello, world!”), mirroring the iOS SwiftUI sample.
- Release signing (template): the
releasebuild type uses the debug keystore so CI can produce a signed AAB without repository secrets. Replace with your release keystore before publishing to Play.
| Resource | Purpose |
|---|---|
| SETUP_ANDROID_DEVOPS_KIT.md | rsync paths to merge this pipeline into another Android repo |
| CURSOR_ANDROID_DEVOPS_REUSE.md | File manifest and “I only have a URL” routing |
| CURSOR_ANDROID_DEVOPS_APPLY_TEMPLATE_PROMPT.txt | One-shot: copy from TEMPLATE_ROOT + bootstrap + optional git push |
| CURSOR_ANDROID_DEVOPS_BOOTSTRAP_PROMPT.txt | Rewire applicationId, artifact names, and Gradle paths after files are merged |
| GITIGNORE_APPEND.txt | Lines to append to a host repo’s .gitignore |
| .cursor/rules/ | Agent playbook, CI reference (github-actions-android-ci.mdc), Git bootstrap, APK install runbook |
| Workflow | When | What |
|---|---|---|
| Android CI/CD | push / pull_request to main or master; workflow_dispatch |
ktlint + detekt + Android Lint → security (Semgrep, TruffleHog, Snyk) → in parallel: Debug APK + unit tests (JaCoCo line coverage ≥ configurable threshold, default 80% on non-UI sources) → bundleRelease on main/master push or manual dispatch |
| Android code health | Same branches | detekt XML + tech-debt + heuristic security reports → artifact android-code-health-reports |
| CodeQL Android | main / master push & PR; weekly Monday 06:00 UTC |
Java/Kotlin analysis after assembleDebug |
| Dependabot | Weekly | PRs for GitHub Actions and Gradle |
Invoked from .github/workflows/android.yml:
| File | Role |
|---|---|
android-job-lint.yml |
ktlintCheck, detekt, lintDebug |
android-job-security.yml |
Semgrep, TruffleHog, Snyk |
android-job-debug-apk.yml |
assembleDebug → artifact PipelineGenericAndroid-debug-apk |
android-job-test.yml |
testDebugUnitTest + JaCoCo report + jacocoTestCoverageVerification |
android-release.yml |
bundleRelease → artifact PipelineGenericAndroid-release-aab |
| Secret | Used by |
|---|---|
SNYK_TOKEN |
android-job-security.yml |
Without SNYK_TOKEN, the Snyk step is skipped (notice in the job log).
Publishing to Google Play requires a release keystore, Play App Signing, and a service account or upload action. This template only uploads the AAB as a workflow artifact; add your preferred Play upload step when you are ready.
Enable Code scanning on the repository so CodeQL results appear under Security.
- Install Android Studio or the Android SDK and set
ANDROID_HOME, or rely on Gradle toolchains / SDK install via Studio. - Create
local.propertieswithsdk.dir=...if the SDK is not in the default location. - From the repo root:
./gradlew assembleDebug testDebugUnitTest jacocoTestReport jacocoTestCoverageVerification ktlintCheck detekt lintDebugCode health scripts (write under Reports/, gitignored):
python3 .github/scripts/tech_debt_scan.py
python3 .github/scripts/security_patterns_scan.py
python3 .github/scripts/codebase_health_report.py(codebase_health_report.py expects Reports/detekt.xml; run ./gradlew detekt first or copy from app/build/reports/detekt/detekt.xml.)
- App module:
app/ - Semgrep configs:
.semgrep/ - detekt config:
config/detekt/detekt.yml - Scripts:
.github/scripts/