CI/CD, Code Quality & Release Pipeline
This document defines the automated quality gates, linting rules, test execution, and Maven publishing workflows for the Veg Sahayyak SDK codebase.
🏗️ Continuous Integration Workflow
Every Pull Request and commit pushed to the main branch undergoes automated validation defined in .github/workflows/quality-gates.yml.
🔍 1. Static Analysis & Linters
The SDK enforces strict Kotlin coding standards, complexity limits, and architectural boundaries:
| Tool | Role | Command |
|---|---|---|
detekt | Identifies complexity smells, potential memory leaks, and architectural deviations. | ./gradlew detekt --stacktrace --info |
Android Lint | Scans for Android API deprecations, resource leaks, and manifest security flaws. | ./gradlew lintDebug --stacktrace --info |
To run all static analysis checks locally before opening a pull request:
./gradlew detekt lintDebug🧪 2. Internal Automated Test Suites
The core telematics algorithms (TelematicsEngine, SpeedWatcher, SpeedometerService) are covered by comprehensive JVM unit tests using Robolectric and JUnit4:
// Source: speed-core/src/test/kotlin/com/vegsahayyak/speedcore/domain/TelematicsEngineTest.kt
package com.vegsahayyak.speedcore.domain
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class TelematicsEngineTest {
private fun assertSustainedSpeed(engine: TelematicsEngine, speedKmh: Float): TelematicsResult {
var result: TelematicsResult? = null
// Call processLocation multiple times to allow Exponential Moving Average (EMA) to converge
repeat(15) {
result = engine.processLocation(speedKmh / 3.6f, 10f)
}
return result!!
}
@Test
fun `isOverLimit triggers hysteresis correctly`() {
val engine = TelematicsEngine()
engine.setWarningThresholdMps(100f / 3.6f)
// Below limit (90 km/h) -> No alert
var result = assertSustainedSpeed(engine, 90f)
assertFalse(result.isOverLimit)
// Exceeds limit by 2 km/h (102 km/h) -> Triggers alert
result = assertSustainedSpeed(engine, 102f)
assertTrue(result.isOverLimit)
// Drops to limit (100 km/h) -> Still true due to hysteresis (-3 km/h buffer)
result = assertSustainedSpeed(engine, 100f)
assertTrue(result.isOverLimit)
// Drops below hysteresis threshold (96 km/h < 97 km/h) -> Clears alert
result = assertSustainedSpeed(engine, 96f)
assertFalse(result.isOverLimit)
}
@Test
fun `isUnderLimit triggers hysteresis correctly`() {
val engine = TelematicsEngine()
engine.setMinWarningThresholdMps(50f / 3.6f)
// Above minimum (60 km/h) -> No alert
var result = assertSustainedSpeed(engine, 60f)
assertFalse(result.isUnderLimit)
// Drops below minimum by 2 km/h (48 km/h) -> Triggers under-speed alert
result = assertSustainedSpeed(engine, 48f)
assertTrue(result.isUnderLimit)
// Rises above hysteresis threshold (54 km/h > 53 km/h) -> Clears alert
result = assertSustainedSpeed(engine, 54f)
assertFalse(result.isUnderLimit)
}
}Run test suites locally:
./gradlew testDebugUnitTest --info📊 3. Code Coverage Targets
The SDK enforces a strict 90%+ coverage bar on all domain logic:
- Domain & Telematics Logic (
TelematicsEngine): 100% branch coverage. - Location Signal Filtering (
SpeedWatcher): 96% coverage. - Unit Conversions (
SpeedUnit): 100% coverage. - Preferences & Service Locator: 91% coverage.
Test results are uploaded via mikepenz/action-junit-report@v4 on every pipeline run.
🚀 4. Automated Release & Maven Publishing
When a GitHub Release tag is published, .github/workflows/publish-sdk.yml automatically triggers:
./gradlew publishThis compiles and publishes the release artifacts to GitHub Packages:
com.vegsahayyak:speed-bom:2.2.0(Bill of Materials)com.vegsahayyak:speed-core:2.2.0(Telematics Engine, Colors & Service)com.vegsahayyak:speed-ui:2.2.0(Jetpack Compose UI, HUD Mode & Themes)com.vegsahayyak:speed-overlay:2.2.0(Floating PiP Overlay Widget)com.vegsahayyak:speed-autostart:2.2.0(Activity Recognition Autostart)