This document explains the GitHub Actions workflows used in the OpenMapView project.
Naming Convention: Reusable workflows are prefixed with an underscore (e.g.,
_docs.yml,_test.yml) to distinguish them from caller workflows (e.g.,ci.yml,release.yml). This convention makes it easy to identify modular components that can be composed into different pipelines.
The workflows are designed using a modular, reusable component architecture to eliminate code duplication and enable parallel execution.
- DRY (Don't Repeat Yourself): Common setup code is in reusable workflows
- Composable: Mix and match workflow components
- Parallel Execution: Independent jobs run simultaneously for speed
- Maintainable: Change configuration once, affects all workflows
- Fail Fast: Format checks run first, expensive builds run last
Located in .github/workflows/:
- Purpose: Verify MIT license headers in all
.ktfiles - Runs:
./scripts/check-copyright.sh - Usage: Called by CI and Release workflows
- Fast: ~30 seconds
- Purpose: Verify code formatting with Spotless
- Runs:
./gradlew spotlessCheck - Usage: Called by CI and Release workflows
- Fast: ~30 seconds
- Purpose: Run Detekt static code analysis
- Runs:
./gradlew detekt - Usage: Called by CI and Release workflows
- Duration: ~1-2 minutes
- Reports: HTML, XML, and SARIF reports generated
- Purpose: Check test coverage meets minimum threshold
- Runs:
./scripts/check-coverage.sh(minimum threshold defined in Contributing Guide) - Artifacts: Uploads coverage reports to Codecov and as artifacts
- Usage: Called by CI workflow
- Duration: ~1-2 minutes
- Purpose: Run unit tests
- Runs:
./gradlew :openmapview:test --continue - Artifacts: Uploads test results and HTML reports
- Usage: Called by CI and Release workflows
- Duration: ~1-2 minutes
- Purpose: Build the OpenMapView AAR library
- Runs:
./gradlew :openmapview:assembleRelease - Artifacts: Uploads the compiled AAR file
- Usage: Called by CI and Release workflows
- Duration: ~2-3 minutes
- Purpose: Build all three example apps
- Runs: Builds Example01Pan, Example02Zoom, Example03Markers
- Artifacts: Uploads all debug APKs
- Usage: Called by CI and Release workflows
- Duration: ~3-4 minutes
- Purpose: Run instrumentation tests on Android emulators
- Runs: Tests on both phone (Nexus 6) and automotive (automotive_1024p_landscape) profiles
- Artifacts: Uploads test results and reports for both device types
- Usage: Called by daily.yml and ci.yml (PR only)
- Duration: ~10-15 minutes (may vary due to emulator startup)
- Purpose: Build API documentation with Dokka, license report, and Detekt report
- Runs:
./gradlew dokkaGenerate,./gradlew generateLicenseReport,./gradlew detekt - Artifacts: Uploads generated HTML documentation with license and Detekt reports
- Usage: Called by CI for validation and docs-deploy for publishing
- Duration: ~2-3 minutes
- Published URLs:
Trigger: Push or Pull Request to main or master branch
Purpose: Validate all changes before they're merged
Execution Flow:
format ────┐
│
copyright ─┼──→ test/coverage/docs ──→ build-library
│ │
detekt ────┘ └──→ build-examples
For Pull Requests only:
instrumented-test (Phone + Automotive) runs in parallel
Jobs:
- format - Runs Spotless formatting check
- copyright - Verifies MIT license headers
- detekt - Runs Detekt static code analysis
- test - Runs unit tests (depends on format + copyright + detekt)
- docs - Builds API documentation with Dokka (depends on format + copyright + detekt)
- coverage - Checks test coverage meets 20% minimum (depends on format + copyright + detekt)
- build-library - Builds library AAR (depends on all above, runs in parallel with build-examples)
- build-examples - Builds example APKs (depends on all above, runs in parallel with build-library)
- instrumented-test - Runs instrumentation tests on phone and automotive emulators (PR only)
Total Duration:
- Maintainer pushes to main: ~3-4 minutes (no instrumentation tests)
- Pull Requests: ~10-15 minutes (includes instrumentation tests on phone + automotive)
Benefits:
- Catches formatting issues early (before expensive builds)
- Parallel builds save time
- PR checks ensure code quality before merge
- Instrumentation tests only run on PRs, reducing CI time for maintainer's direct commits
- External contributors' PRs are thoroughly tested on both phone and automotive platforms
Trigger: Push of version tag matching v*.*.* pattern (e.g., v0.2.0)
Purpose: Run full CI pipeline, publish to Maven Central, and create GitHub Release
Execution Flow:
format ────┐
├──→ test ──→ build-library ──┐
detekt ────┘ │ ├──→ publish
└──→ build-examples ──┘
Jobs:
- format - Runs Spotless formatting check
- detekt - Runs Detekt static code analysis
- test - Runs unit tests (depends on format + detekt)
- build-library - Builds library AAR (depends on format + detekt + test)
- build-examples - Builds example APKs (depends on format + detekt + test)
- publish - Publishes to Maven Central and creates GitHub Release (depends on all above)
Publish Job Details:
- Validates tag format (must be
vMAJOR.MINOR.PATCH) - Extracts version number (e.g.,
v0.2.0->0.2.0) - Signs artifacts with GPG key
- Uploads to Maven Central OSSRH
- Generates changelog from git history
- Creates GitHub Release with:
- Version number and changelog
- Maven/Gradle installation instructions
- Links to artifacts
Total Duration: ~5-7 minutes (including publish)
Secrets Required: See "Required GitHub Secrets" section below
Trigger: Scheduled daily at 09:45 UTC, or manual trigger via workflow_dispatch
Purpose: Run comprehensive instrumentation tests on both phone and automotive platforms daily to catch potential issues early
Execution Flow:
Scheduled trigger (09:45 UTC daily)
|
v
instrumented-test (calls _instrumentation.yml)
|
v
+------------------+------------------+
| |
v v
Phone Tests Automotive Tests
(Nexus 6 profile) (automotive_1024p_landscape)
Jobs:
- instrumented-test - Calls the reusable
_instrumentation.ymlworkflow
Total Duration: ~10-15 minutes (may vary due to emulator startup)
Benefits:
- Catches device-specific regressions early
- Tests on both phone and automotive form factors
- Manual trigger available for on-demand testing
- Runs daily for continuous quality monitoring
Trigger: Push to main or master branch (paths: openmapview/src/**/*.kt, README.md, .github/workflows/_docs.yml, .github/workflows/docs-deploy.yml)
Purpose: Generate API documentation from KDoc comments and deploy to GitHub Pages
Execution Flow:
Push to main (filtered by paths)
|
v
build-docs (calls _docs.yml)
|
v
Build documentation with Dokka
|
v
Upload documentation artifact
|
v
deploy (Download artifact)
|
v
Deploy to GitHub Pages
Jobs:
- build-docs - Calls the reusable
_docs.ymlworkflow to build documentation - deploy - Downloads artifact and deploys to GitHub Pages
Configuration:
- Only runs when Kotlin source files or docs workflows change
- Uses concurrency control (only one deployment at a time)
- Requires GitHub Pages to be enabled with "GitHub Actions" as source
Total Duration: ~2-3 minutes
Published URL: https://afarber.github.io/OpenMapView/
Benefits:
- Documentation always in sync with code
- Automatic updates on every push to main
- No manual publishing needed
- Professional, searchable API reference
For the release workflow to function, the project owner must configure these secrets in the GitHub repository:
Location: Settings -> Secrets and variables -> Actions -> Repository secrets
- Description: Sonatype JIRA username
- Used for: Authenticating to Maven Central OSSRH
- How to get: Created when registering at https://issues.sonatype.org
- Description: Sonatype JIRA password
- Used for: Authenticating to Maven Central OSSRH
- How to get: Set when registering at https://issues.sonatype.org
- Description: Base64-encoded GPG private key
- Used for: Signing artifacts (required by Maven Central)
- How to get:
gpg --export-secret-keys YOUR_KEY_ID | base64 - Format: Very long base64 string (this is normal)
- Security: Never commit this or share it publicly
- Description: Passphrase for the GPG key
- Used for: Unlocking the GPG private key for signing
- How to get: The passphrase set when creating the GPG key
- Note: If no passphrase was set, use an empty string
These secrets are automatically provided by GitHub Actions:
- GITHUB_TOKEN: Used for creating GitHub Releases
- GITHUB_ACTOR: Used for GitHub Packages (if enabled)
Before pushing, developers can run the same checks locally:
# Format check
./gradlew spotlessCheck
# Auto-fix formatting
./gradlew spotlessApply
# Static analysis
./gradlew detekt
# Run unit tests
./gradlew :openmapview:test
# Build library
./gradlew :openmapview:assembleRelease
# Build examples
./gradlew :examples:Example01Pan:assembleDebug
./gradlew :examples:Example02Zoom:assembleDebug
./gradlew :examples:Example03Markers:assembleDebug
# Or build everything
./gradlew build# 1. Ensure all changes are committed and pushed
git status
git push
# 2. Create and push a version tag
git tag v0.2.0
git push origin v0.2.0
# 3. Watch the workflow
# Go to: https://github.com/afarber/OpenMapView/actions
# 4. For first release only: manually release staging repository
# Log in to: https://s01.oss.sonatype.org/
# Find your staging repo, click "Close", then "Release"
# 5. Verify publication after 2-4 hours
# https://central.sonatype.com/artifact/de.afarber/openmapviewGitHub Actions Tab: https://github.com/afarber/OpenMapView/actions
Workflow Runs:
- Green checkmark = Success
- Red X = Failed
- Yellow circle = In progress
Artifacts: Click on a workflow run to see uploaded artifacts:
- Test results (XML)
- Test reports (HTML)
- Library AAR
- Example APKs
Artifacts are retained for 30 days.
- Go to Actions tab
- Click on the failed workflow run
- Click on the failed job
- Expand the failed step to see logs
Common Failures:
- Format check fails: Run
./gradlew spotlessApplylocally and commit - Detekt fails: Run
./gradlew detektlocally to see issues - Test fails: Run
./gradlew :openmapview:testlocally to debug - Build fails: Check for compilation errors in logs
- Publish fails: Verify GitHub Secrets are configured correctly
Developer creates PR with code changes
|
v
GitHub triggers ci.yml workflow
|
v
format/copyright/detekt jobs run in parallel (30-60 sec each) - PASS
|
v
test/coverage/docs jobs run (1-2 min each) - PASS
|
v
build-library + build-examples run in parallel (2-3 min) - PASS
|
v
All core checks pass (3-4 min)
Meanwhile (in parallel, PR only):
instrumented-test: Phone + Automotive tests (10-15 min) - PASS
|
v
All checks complete -> PR is ready to merge
Developer tags v0.2.0 and pushes
|
v
GitHub triggers release.yml workflow
|
v
format + detekt jobs run in parallel - PASS
|
v
test job: Run unit tests - PASS
|
v
build-library + build-examples run in parallel - PASS
|
v
publish job:
- Validate tag format - PASS
- Sign artifacts with GPG - PASS
- Upload to Maven Central - PASS
- Generate changelog - PASS
- Create GitHub Release - PASS
|
v
Wait 2-4 hours -> Library available on Maven Central
Before (old workflow): 124 lines with repeated setup code After (new workflow): 27 lines in ci.yml, reusable components
Building library and examples happens simultaneously, saving ~2 minutes per workflow run.
To upgrade Java version or change Gradle cache settings:
- Update in one reusable workflow file
- Automatically applies to CI and Release workflows
The reusable _instrumentation.yml workflow demonstrates this principle:
# Used by both daily.yml and ci.yml
jobs:
instrumentation-tests:
uses: ./.github/workflows/_instrumentation.ymlThis single workflow definition powers both daily scheduled tests and PR validation tests.
- Maintainer commits to main: Fast feedback (~3-4 min) without instrumentation delays
- Pull Requests: Comprehensive testing (~10-15 min) including phone and automotive instrumentation tests required for merge
- Daily scheduled runs: Proactive regression detection on both platforms
- Format checks catch simple issues fast
- Tests verify correctness
- Builds ensure compilation works
- Publish handles distribution
Add to README.md to show workflow status:
[](https://github.com/afarber/OpenMapView/actions)
[](https://github.com/afarber/OpenMapView/actions)GitHub sends email notifications on workflow failures to repository watchers.
Configure in: Settings -> Notifications -> Actions
- GitHub Actions Documentation: https://docs.github.com/en/actions
- Reusable Workflows Guide: https://docs.github.com/en/actions/using-workflows/reusing-workflows
- Gradle Build Cache: https://docs.gradle.org/current/userguide/build_cache.html
- Spotless Plugin: https://github.com/diffplug/spotless
The OpenMapView GitHub Actions setup provides:
- Fast feedback - Format checks in 30 seconds
- Parallel builds - Save time with concurrent execution
- Automated releases - Tag and publish in one step
- Quality gates - No broken code reaches main branch
- Easy maintenance - Change configuration once
- Full automation - From code change to Maven Central
For Maven Central setup details, see Publishing Guide.