feat: build logic (#4829)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-03-17 15:35:39 -05:00 committed by GitHub
parent 807db83f53
commit 7d63f8b824
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 479 additions and 486 deletions

View file

@ -15,10 +15,12 @@ Quick reference for maintaining and extending the build-logic convention system.
build-logic/
├── convention/
│ ├── src/main/kotlin/
│ │ ├── KmpLibraryConventionPlugin.kt # KMP modules: features, core
│ │ ├── KmpJvmAndroidConventionPlugin.kt # Opt-in jvmAndroidMain hierarchy for Android + desktop JVM
│ │ ├── AndroidApplicationConventionPlugin.kt # Main app
│ │ ├── AndroidLibraryConventionPlugin.kt # Android-only libraries
│ │ ├── KmpFeatureConventionPlugin.kt # KMP feature modules (composes library + compose + koin + common deps)
│ │ ├── KmpLibraryConventionPlugin.kt # KMP modules: core libraries
│ │ ├── KmpLibraryComposeConventionPlugin.kt # KMP Compose Multiplatform setup
│ │ ├── KmpJvmAndroidConventionPlugin.kt # Opt-in jvmAndroidMain hierarchy for Android + desktop JVM
│ │ ├── AndroidApplicationConventionPlugin.kt # Main app
│ │ ├── AndroidLibraryConventionPlugin.kt # Android-only libraries
│ │ ├── AndroidApplicationComposeConventionPlugin.kt
│ │ ├── AndroidLibraryComposeConventionPlugin.kt
│ │ ├── org/meshtastic/buildlogic/
@ -83,6 +85,48 @@ kotlin {
**Why:** The convention uses Kotlin's hierarchy template API to create `jvmAndroidMain` without the `Default Kotlin Hierarchy Template Not Applied Correctly` warning triggered by hand-written `dependsOn(...)` graphs.
### Example: Creating a new KMP feature module
**Current Pattern (GOOD ✅):**
Use `meshtastic.kmp.feature` for any `feature:*` module. It composes `kmp.library` + `kmp.library.compose` + `koin` and provides all the common Compose/Lifecycle/Koin/Android dependencies that every feature needs:
```kotlin
plugins {
alias(libs.plugins.meshtastic.kmp.feature)
// Optional: add only if this feature needs serialization
alias(libs.plugins.meshtastic.kotlinx.serialization)
}
kotlin {
jvm()
android {
namespace = "org.meshtastic.feature.yourfeature"
androidResources.enable = false
withHostTest { isIncludeAndroidResources = true }
}
sourceSets {
commonMain.dependencies {
// Only module-SPECIFIC deps here
implementation(projects.core.common)
implementation(projects.core.model)
implementation(projects.core.ui)
}
androidMain.dependencies {
// Only Android-specific extras here
}
}
}
```
**What the plugin provides automatically:**
- `commonMain`: `compose-multiplatform-material3`, `compose-multiplatform-materialIconsExtended`, `jetbrains-lifecycle-viewmodel-compose`, `koin-compose-viewmodel`, `kermit`
- `androidMain`: `androidx-compose-bom` (platform), `accompanist-permissions`, `androidx-activity-compose`, `androidx-compose-material3`, `androidx-compose-material-iconsExtended`, `androidx-compose-ui-text`, `androidx-compose-ui-tooling-preview`
- `commonTest`: `core:testing`
**Why:** Eliminates ~15 duplicate dependency declarations per feature module (modelled after Now in Android's `AndroidFeatureImplConventionPlugin`).
### Example: Adding Android-specific test config
**Pattern:** Add to `AndroidLibraryConventionPlugin.kt`:
@ -228,24 +272,22 @@ extensions.configure<CommonExtension> {
### ❌ **Mistake: Side effects during configuration**
```kotlin
// WRONG: Task configuration during plugin apply (too early)
// WRONG: Eager task configuration at plugin-apply time
tasks.withType<Test> {
// This runs before build.gradle.kts is parsed!
// Can realize tasks too early
}
// RIGHT: Use afterEvaluate if needed
afterEvaluate {
tasks.withType<Test> {
// Runs after all configuration
}
// RIGHT: Lazy, configuration-cache-friendly wiring
tasks.withType<Test>().configureEach {
// Applies to existing and future tasks lazily
}
```
## Related Files
- `AGENTS.md` - Development guidelines (Section 3.B testing, Section 4.A build protocol)
- `docs/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` - History of optimizations
- `docs/BUILD_LOGIC_INDEX.md` - Current build-logic doc entry point (with links to active references)
- `docs/archive/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` - Historical optimization deep-dive
- `build-logic/convention/build.gradle.kts` - Convention plugin build config
- `.github/copilot-instructions.md` - Build & test commands

View file

@ -1,165 +1,41 @@
# Build-Logic Documentation Index
Quick navigation guide for build-logic optimization and convention documentation.
Quick navigation guide for build-logic conventions in this repository.
## 📋 Start Here
## Start Here
**New to build-logic?** → `BUILD_LOGIC_CONVENTIONS_GUIDE.md`
**Want optimization details?** → `BUILD_LOGIC_OPTIMIZATION_SUMMARY.md`
**Need implementation details?** → `BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md`
- New to build-logic? -> `docs/BUILD_LOGIC_CONVENTIONS_GUIDE.md`
- Need test-dependency specifics? -> `docs/BUILD_CONVENTION_TEST_DEPS.md`
- Need implementation code? -> `build-logic/convention/src/main/kotlin/`
---
## Primary Docs (Current)
## 📚 Documentation Files
| Document | Purpose |
| :--- | :--- |
| `docs/BUILD_LOGIC_CONVENTIONS_GUIDE.md` | Canonical conventions, duplication heuristics, verification commands, common pitfalls |
| `docs/BUILD_CONVENTION_TEST_DEPS.md` | Rationale and behavior for centralized KMP test dependencies |
### Executive & Strategic
| Document | Purpose | Audience | Status |
|----------|---------|----------|--------|
| **[BUILD_LOGIC_OPTIMIZATION_SUMMARY.md](BUILD_LOGIC_OPTIMIZATION_SUMMARY.md)** | High-level summary of all optimizations, completed work, and recommendations | Tech Leads, Maintainers | ✅ Final |
| **[BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md](BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md)** | Detailed analysis: what was done, why, and future opportunities | Architects, Senior Devs | ✅ Final |
## Key Conventions to Follow
### Practical & Implementation
| Document | Purpose | Audience | Status |
|----------|---------|----------|--------|
| **[BUILD_LOGIC_CONVENTIONS_GUIDE.md](BUILD_LOGIC_CONVENTIONS_GUIDE.md)** | How to maintain, extend, and follow build-logic patterns | All Developers | ✅ Reference |
| **[BUILD_CONVENTION_TEST_DEPS.md](BUILD_CONVENTION_TEST_DEPS.md)** | Specific details on test dependency centralization | Test Developers, Module Owners | ✅ Reference |
- Prefer lazy Gradle APIs in convention plugins: `configureEach`, `withPlugin`, provider APIs.
- Avoid `afterEvaluate` in `build-logic/convention` unless there is no viable lazy alternative.
- Keep convention plugins single-purpose and compose them (e.g., `meshtastic.kmp.feature` composes KMP + Compose + Koin conventions).
- Use version-catalog aliases from `gradle/libs.versions.toml` consistently.
### Analysis & Research
| Document | Purpose | Audience | Status |
|----------|---------|----------|--------|
| **[BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md](BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md)** | Research findings: identified issues and analysis of each | Reviewers, Curious Developers | ✅ Research |
## Verification Commands
---
## 🎯 Quick Links by Use Case
### I need to...
**Add a new test framework dependency**
1. Read: `BUILD_LOGIC_CONVENTIONS_GUIDE.md` (Section "Adding a new test framework")
2. Edit: `build-logic/.../KotlinAndroid.kt::configureKmpTestDependencies()`
3. Verify: Run `./gradlew spotlessCheck detekt test`
**Share Java/JVM code between Android and Desktop in a KMP module**
1. Read: `BUILD_LOGIC_CONVENTIONS_GUIDE.md` (Section "Adding shared `jvmAndroidMain` code to a KMP module")
2. Apply: `id("meshtastic.kmp.jvm.android")`
3. Verify: Run `./gradlew spotlessCheck detekt assembleDebug test`
**Understand the test dependency optimization**
1. Read: `BUILD_CONVENTION_TEST_DEPS.md` (entire file)
2. Reference: `BUILD_LOGIC_OPTIMIZATION_SUMMARY.md` (Section "Completed Optimizations")
**Consolidate duplicate convention plugins**
1. Read: `BUILD_LOGIC_CONVENTIONS_GUIDE.md` (Section "Duplication Heuristics")
2. Reference: `BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` (Section "Future Optimization Opportunities")
3. Review: Comments in `AndroidApplicationComposeConventionPlugin.kt` and `AndroidLibraryFlavorsConventionPlugin.kt`
**Maintain build-logic going forward**
1. Read: `BUILD_LOGIC_CONVENTIONS_GUIDE.md` (entire file)
2. Reference: `BUILD_LOGIC_OPTIMIZATION_SUMMARY.md` (Section "Maintenance Going Forward")
**Review optimization decisions**
1. Read: `BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` (Section "Decision Rationale")
2. Check: Comments in modified convention plugins
---
## 📊 Changes at a Glance
### Code Changes
```
Modified Files: 9
Created Files: 5 (documentation)
Lines Removed: ~70 (redundant dependencies)
Lines Added: ~30 (consolidated config)
Build Verification:
✅ spotlessCheck
✅ detekt
✅ assembleDebug
✅ test (516 tasks, all passing)
```bash
./gradlew :build-logic:convention:compileKotlin
./gradlew :build-logic:convention:validatePlugins
./gradlew spotlessCheck
./gradlew detekt
```
### Plugin Status
```
✅ KmpLibraryConventionPlugin - Enhanced (test deps added)
✅ AndroidApplicationCompose - Optimized (documented duplication)
✅ AndroidLibraryCompose - Optimized (documented duplication)
✅ AndroidApplicationFlavors - Optimized (documented opportunity)
✅ AndroidLibraryFlavors - Optimized (documented opportunity)
```
---
## 🔄 Historical Context
### Previous Session (From Context)
- Identified and fixed Kotlin test compilation errors in feature modules
- Added `kotlin("test")` to individual module build files
### This Session
- **Identified:** Opportunity to centralize test dependency configuration
- **Implemented:** Moved test dependencies to convention plugin
- **Removed:** 7 redundant dependency declarations from modules
- **Implemented:** Added `meshtastic.kmp.jvm.android` to standardize `jvmAndroidMain` hierarchy setup
- **Removed:** Manual `dependsOn(...)` wiring from `core:common`, `core:model`, `core:network`, and `core:ui`
- **Analyzed:** Composition opportunities for other duplicate plugins
- **Documented:** Future optimization paths and consolidation criteria
- **Migrated:** JetBrains Compose Multiplatform dependencies from hard-coded/legacy `compose.xyz` references to proper version catalog entries.
---
## 📌 Key Decisions
### ✅ Decision: Test Dependencies → Convention
**Result:** Deployed ✅
**Rationale:** Large duplication (7 places), single configuration, all KMP modules benefit
**Impact:** Immediate value, easy maintenance
### ⚠️ Decision: Keep Compose Plugins Separate
**Result:** Documented duplication ✅
**Rationale:** Different extension types, explicit intent matters, low cost of duplication
**Future Path:** Can consolidate with `CommonExtension` if Application/Library handling diverges
### ⚠️ Decision: Keep Flavor Plugins Separate
**Result:** Documented opportunity ✅
**Rationale:** Different extension types, low duplication cost, Gradle conventions prefer specific types
**Future Path:** Can consolidate if flavor handling becomes more complex
---
## 🚀 Next Steps
### Immediate
- ✅ Use test dependency pattern for new modules
- ✅ Refer to guides when modifying build-logic
### Short Term
- [ ] Consider plugin validation test suite
- [ ] Review other configuration functions for consolidation opportunities
- [ ] Investigate factoring out JetBrains CMP dependencies into `meshtastic.kmp.library.compose` convention.
### Long Term
- [ ] Monitor if Android Application/Library handling diverges
- [ ] Revisit consolidation decisions annually
- [ ] Build optimization playbook for AI agents
---
## 📞 Questions?
- **How do test dependencies work now?**`BUILD_CONVENTION_TEST_DEPS.md`
- **Why keep duplicate plugins?**`BUILD_LOGIC_CONVENTIONS_GUIDE.md` (Duplication Heuristics)
- **What's planned for the future?**`BUILD_LOGIC_OPTIMIZATION_SUMMARY.md` (Recommendations)
- **How do I add a new convention?**`BUILD_LOGIC_CONVENTIONS_GUIDE.md` (How to Add)
---
## 📝 Version Control
**Last Updated:** March 12, 2026
**Status:** ✅ COMPLETE AND DEPLOYED
**Test Coverage:** All changes verified with spotless, detekt, and full test suite
**Production Ready:** YES ✅
## Related Files
- `build-logic/convention/build.gradle.kts`
- `build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt`
- `build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/FlavorResolution.kt`
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `GEMINI.md`

View file

@ -17,7 +17,7 @@ Run in this order for routine changes:
Notes:
- This order aligns with repository guidance in `AGENTS.md` and `.github/copilot-instructions.md`.
- CI additionally runs `testDebugUnitTest` in `.github/workflows/reusable-check.yml`.
- CI runs host verification and Android build/device verification in separate jobs inside `.github/workflows/reusable-check.yml`.
## 2) Change-type matrix
@ -53,20 +53,26 @@ Run these when relevant to map/provider/flavor-specific behavior:
Current reusable check workflow includes:
- `spotlessCheck detekt`
- `testDebugUnitTest testFdroidDebugUnitTest testGoogleDebugUnitTest`
- `koverXmlReport app:koverXmlReportFdroidDebug app:koverXmlReportGoogleDebug`
- JVM smoke compile (all 16 core + all 6 feature modules + `desktop:test`):
`:core:proto:compileKotlinJvm :core:common:compileKotlinJvm :core:model:compileKotlinJvm :core:repository:compileKotlinJvm :core:di:compileKotlinJvm :core:navigation:compileKotlinJvm :core:resources:compileKotlinJvm :core:datastore:compileKotlinJvm :core:database:compileKotlinJvm :core:domain:compileKotlinJvm :core:prefs:compileKotlinJvm :core:network:compileKotlinJvm :core:data:compileKotlinJvm :core:ble:compileKotlinJvm :core:service:compileKotlinJvm :core:ui:compileKotlinJvm :feature:intro:compileKotlinJvm :feature:messaging:compileKotlinJvm :feature:map:compileKotlinJvm :feature:node:compileKotlinJvm :feature:settings:compileKotlinJvm :feature:firmware:compileKotlinJvm :desktop:test`
- `assembleDebug`
- `lintDebug`
- `connectedDebugAndroidTest` (when emulator tests are enabled)
- Android lint for all directly runnable Android modules:
`app:lintFdroidDebug app:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug core:api:lintDebug mesh_service_example:lintDebug`
- Host tests plus coverage aggregation:
`test koverXmlReport app:koverXmlReportFdroidDebug app:koverXmlReportGoogleDebug core:api:koverXmlReportDebug core:barcode:koverXmlReportFdroidDebug core:barcode:koverXmlReportGoogleDebug mesh_service_example:koverXmlReportDebug`
- JVM smoke compile for all KMP JVM targets (all compile-only modules remain explicit):
`:core:proto:compileKotlinJvm :core:common:compileKotlinJvm :core:model:compileKotlinJvm :core:repository:compileKotlinJvm :core:di:compileKotlinJvm :core:navigation:compileKotlinJvm :core:resources:compileKotlinJvm :core:datastore:compileKotlinJvm :core:database:compileKotlinJvm :core:domain:compileKotlinJvm :core:prefs:compileKotlinJvm :core:network:compileKotlinJvm :core:data:compileKotlinJvm :core:ble:compileKotlinJvm :core:nfc:compileKotlinJvm :core:service:compileKotlinJvm :core:testing:compileKotlinJvm :core:ui:compileKotlinJvm :feature:intro:compileKotlinJvm :feature:messaging:compileKotlinJvm :feature:connections:compileKotlinJvm :feature:map:compileKotlinJvm :feature:node:compileKotlinJvm :feature:settings:compileKotlinJvm :feature:firmware:compileKotlinJvm`
- Android build tasks:
`app:assembleFdroidDebug app:assembleGoogleDebug mesh_service_example:assembleDebug`
- Instrumented tests (when emulator tests are enabled):
`app:connectedFdroidDebugAndroidTest app:connectedGoogleDebugAndroidTest core:barcode:connectedFdroidDebugAndroidTest core:barcode:connectedGoogleDebugAndroidTest`
- Coverage uploads happen once from the host job; instrumented test results upload once from the first Android matrix API to avoid duplicate reporting.
Reference: `.github/workflows/reusable-check.yml`
PR workflow note:
- `.github/workflows/pull-request.yml` ignores docs-only changes (`**.md`, `docs/**`), so doc-only PRs may skip Android CI by design.
- Android CI on PRs runs with `run_instrumented_tests: false`; emulator tests are handled in other workflow contexts.
- `.github/workflows/pull-request.yml` ignores docs-only changes (`**/*.md`, `docs/**`), so doc-only PRs may skip Android CI by design.
- PR change detection includes workflow/build/config paths such as `.github/workflows/**`, `desktop/**`, `mesh_service_example/**`, `config/**`, `gradle/**`, `settings.gradle.kts`, and `test.gradle.kts`.
- Android CI on PRs runs with `run_instrumented_tests: false`; merge queue keeps the full emulator matrix on API 26 and 35.
- Gradle cache writes are enabled for trusted refs/events (`main`, `merge_group`, and `gh-readonly-queue/*`); other refs run in read-only cache mode.
## 5) Practical guidance for agents

View file

@ -227,7 +227,7 @@ Add unit tests to `build-logic` verifying:
## Related Documentation
- `docs/BUILD_CONVENTION_TEST_DEPS.md` - Details on test dependency centralization
- `docs/BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md` - Full analysis of optimization opportunities
- `docs/archive/BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md` - Full analysis of optimization opportunities
- `AGENTS.md` - Updated testing + KMP hierarchy guidelines (Section 3.B)

View file

@ -109,13 +109,13 @@ AFTER:
- Summary of changes and impact
- Benefits for module developers
### 2. `docs/BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md`
### 2. `docs/archive/BUILD_LOGIC_OPTIMIZATION_ANALYSIS.md`
- Complete analysis of 4 optimization opportunities
- High/Medium/Low priority classification
- Implementation cost/benefit analysis
- Future recommendations
### 3. `docs/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` ⭐ PRIMARY REFERENCE
### 3. `docs/archive/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` ⭐ PRIMARY REFERENCE
- Full summary of all optimizations
- Build-logic plugin inventory with duplication status
- Future opportunities with effort estimates
@ -263,7 +263,7 @@ AFTER: 1 opt-in convention plugin
### For Developers
- Use `docs/BUILD_LOGIC_CONVENTIONS_GUIDE.md` when modifying build-logic
- Follow test dependency patterns when creating new KMP modules
- Reference `docs/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` for consolidation opportunities
- Reference `docs/archive/BUILD_LOGIC_OPTIMIZATIONS_COMPLETE.md` for consolidation opportunities
### For Code Reviewers
- Watch for duplicate convention plugins (can consolidate if appropriate)

View file

@ -1,6 +1,6 @@
# Roadmap
> Last updated: 2026-03-16
> Last updated: 2026-03-17
Forward-looking priorities for the Meshtastic KMP multi-target effort. For current state, see [`kmp-status.md`](./kmp-status.md). For the full gap analysis, see [`decisions/architecture-review-2026-03.md`](./decisions/architecture-review-2026-03.md).
@ -16,7 +16,7 @@ These items address structural gaps identified in the March 2026 architecture re
| Add feature module `commonTest` (settings, node, messaging) | Medium | Medium | ✅ |
| Desktop Koin `checkModules()` integration test | Medium | Low | ✅ |
| Auto-wire Desktop ViewModels via K2 Compiler (eliminate manual wiring) | Medium | Low | ✅ |
| **Migrate to JetBrains Compose Multiplatform dependencies** | High | Low | ✅ |
here| **Migrate to JetBrains Compose Multiplatform dependencies** | High | Low | ✅ |
## Active Work
@ -81,7 +81,7 @@ These items address structural gaps identified in the March 2026 architecture re
4. **`feature:connections` module** — ✅ Done: Extracted connections UI into KMP feature module with dynamic transport availability detection
5. **Navigation 3 parity baseline** — ✅ Done: shared `TopLevelDestination` in `core:navigation`; both shells use same enum; parity tests in `core:navigation/commonTest` and `desktop/test`
6. **iOS CI gate** — add `iosArm64()`/`iosSimulatorArm64()` to convention plugins and CI (compile-only, no implementations)
7. **Build-logic consolidation****Planned:** Consolidate expansive build-logic convention plugins. There is currently some duplication in Compose dependencies that should be factored into common conventions (`meshtastic.kmp.library.compose` vs manually specifying JetBrains CMP deps in feature modules).
7. **Build-logic consolidation**✅ Done: Created `meshtastic.kmp.feature` convention plugin (modelled after NiA's `AndroidFeatureImplConventionPlugin`). Composes `kmp.library` + `kmp.library.compose` + `koin` and wires common Compose/Lifecycle/Koin/androidMain deps. All 7 feature modules migrated; ~100 duplicated dep lines eliminated.
## Medium-Term Priorities (60 days)