mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: build logic (#4829)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
807db83f53
commit
7d63f8b824
33 changed files with 479 additions and 486 deletions
14
.github/copilot-instructions.md
vendored
14
.github/copilot-instructions.md
vendored
|
|
@ -27,7 +27,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
| Directory | Description |
|
||||
| :--- | :--- |
|
||||
| `app/` | Main application module. Contains `MainActivity`, Koin DI modules, and app-level logic. Uses package `org.meshtastic.app`. |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.library`, `meshtastic.koin`). |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.feature`, `meshtastic.kmp.library`, `meshtastic.koin`). |
|
||||
| `config/` | Detekt static analysis rules (`config/detekt/detekt.yml`) and Spotless formatting config (`config/spotless/.editorconfig`). |
|
||||
| `docs/` | Architecture docs and agent playbooks. See `docs/agent-playbooks/README.md` for version baseline and task recipes. |
|
||||
| `core/model` | Domain models and common data structures. |
|
||||
|
|
@ -50,7 +50,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
| `core/ble/` | Bluetooth Low Energy stack using Nordic libraries. |
|
||||
| `core/resources/` | Centralized string and image resources (Compose Multiplatform). |
|
||||
| `core/testing/` | **Shared test doubles, fakes, and utilities for `commonTest` across all KMP modules.** |
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. |
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. Use `meshtastic.kmp.feature` convention plugin. |
|
||||
| `desktop/` | Compose Desktop application — first non-Android KMP target. Nav 3 shell, full Koin DI graph, TCP transport with `want_config` handshake. |
|
||||
| `mesh_service_example/` | Sample app showing `core:api` service integration. |
|
||||
|
||||
|
|
@ -77,6 +77,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
- **JetBrains fork aliases:** Version catalog aliases for JetBrains-forked AndroidX artifacts use the `jetbrains-*` prefix (e.g., `jetbrains-lifecycle-runtime-compose`, `jetbrains-navigation3-ui`). Plain `androidx-*` aliases are true Google AndroidX artifacts. Never mix them up in `commonMain`.
|
||||
- **Room KMP:** Always use `factory = { MeshtasticDatabaseConstructor.initialize() }` in `Room.databaseBuilder` and `inMemoryDatabaseBuilder`. DAOs and Entities reside in `commonMain`.
|
||||
- **Testing:** Write ViewModel and business logic tests in `commonTest`. Use `core:testing` shared fakes.
|
||||
- **Build-logic conventions:** In `build-logic/convention`, prefer lazy Gradle configuration (`configureEach`, `withPlugin`, provider APIs). Avoid `afterEvaluate` in convention plugins unless there is no viable lazy alternative.
|
||||
|
||||
### C. Namespacing
|
||||
- **Standard:** Use the `org.meshtastic.*` namespace for all code.
|
||||
|
|
@ -116,6 +117,15 @@ Always run commands in the following order to ensure reliability. Do not attempt
|
|||
```
|
||||
*Note: If testing Compose UI on the JVM (Robolectric) with Java 17, pin your tests to `@Config(sdk = [34])` to avoid SDK 35 compatibility crashes.*
|
||||
|
||||
**CI workflow conventions (GitHub Actions):**
|
||||
- Reusable CI is split into a host job and an Android matrix job in `.github/workflows/reusable-check.yml`.
|
||||
- Host job runs style/static checks, explicit Android lint tasks, unit tests, and Kover XML coverage uploads once.
|
||||
- Android matrix job runs explicit assemble tasks for `app` and `mesh_service_example`; instrumentation is enabled by input and matrix API.
|
||||
- Prefer explicit Gradle task paths in CI (for example `app:lintFdroidDebug`, `app:connectedGoogleDebugAndroidTest`) instead of shorthand tasks like `lintDebug`.
|
||||
- Pull request CI is main-only (`.github/workflows/pull-request.yml` targets `main` branch).
|
||||
- Gradle cache writes are trusted on `main` and merge queue runs (`merge_group` / `gh-readonly-queue/*`); other refs use read-only cache mode in reusable CI.
|
||||
- PR `check-changes` path filtering lives in `.github/workflows/pull-request.yml` and must include module dirs plus build/workflow entrypoints (`build-logic/**`, `gradle/**`, `.github/workflows/**`, `gradlew`, `settings.gradle.kts`, etc.) so CI is not skipped for infra-only changes.
|
||||
|
||||
### C. Documentation Sync
|
||||
Update documentation continuously as part of the same change. If you modify architecture, module targets, CI tasks, validation commands, or agent workflow rules, update the relevant docs (`AGENTS.md`, `.github/copilot-instructions.md`, `GEMINI.md`, `docs/agent-playbooks/*`, `docs/kmp-status.md`, and `docs/decisions/architecture-review-2026-03.md`).
|
||||
|
||||
|
|
|
|||
3
.github/workflows/merge-queue.yml
vendored
3
.github/workflows/merge-queue.yml
vendored
|
|
@ -13,6 +13,9 @@ jobs:
|
|||
if: github.repository == 'meshtastic/Meshtastic-Android'
|
||||
uses: ./.github/workflows/reusable-check.yml
|
||||
with:
|
||||
run_lint: true
|
||||
run_unit_tests: true
|
||||
run_instrumented_tests: true
|
||||
api_levels: '[26, 35]' # Comprehensive testing for Merge Queue
|
||||
upload_artifacts: false
|
||||
secrets: inherit
|
||||
|
|
|
|||
74
.github/workflows/pull-request.yml
vendored
74
.github/workflows/pull-request.yml
vendored
|
|
@ -2,9 +2,9 @@ name: Pull Request CI
|
|||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
branches: [ main ]
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**/*.md'
|
||||
- 'docs/**'
|
||||
- '.gitignore'
|
||||
|
||||
|
|
@ -26,17 +26,78 @@ jobs:
|
|||
with:
|
||||
filters: |
|
||||
android:
|
||||
# CI/workflow implementation
|
||||
- '.github/workflows/**'
|
||||
- '.github/actions/**'
|
||||
# Product modules validated by reusable-check
|
||||
- 'app/**'
|
||||
- 'baselineprofile/**'
|
||||
- 'desktop/**'
|
||||
- 'core/**'
|
||||
- 'feature/**'
|
||||
- 'mesh_service_example/**'
|
||||
# Shared build infrastructure
|
||||
- 'build-logic/**'
|
||||
- 'config/**'
|
||||
- 'gradle/**'
|
||||
# Root build entrypoints/config that can alter task graph or outputs
|
||||
- 'build.gradle.kts'
|
||||
- 'config.properties'
|
||||
- 'compose_compiler_config.conf'
|
||||
- 'gradle.properties'
|
||||
- 'gradlew'
|
||||
- 'gradlew.bat'
|
||||
- 'settings.gradle.kts'
|
||||
- 'test.gradle.kts'
|
||||
|
||||
# 1b. FILTER DRIFT CHECK: Ensures check-changes stays aligned with module roots
|
||||
verify-check-changes-filter:
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android' && !( github.head_ref == 'scheduled-updates' || github.head_ref == 'l10n_main' )
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Verify module roots are represented in check-changes filter
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
settings = Path('settings.gradle.kts').read_text()
|
||||
workflow = Path('.github/workflows/pull-request.yml').read_text()
|
||||
|
||||
module_roots = {
|
||||
module.split(':')[0]
|
||||
for module in re.findall(r'":([^"]+)"', settings)
|
||||
}
|
||||
|
||||
allowed_extra_roots = {'baselineprofile'}
|
||||
expected_roots = module_roots | allowed_extra_roots
|
||||
|
||||
filter_paths = {
|
||||
path.split('/')[0]
|
||||
for path in re.findall(r"-\s*'([^']+/\*\*)'", workflow)
|
||||
}
|
||||
|
||||
actual_module_roots = filter_paths & expected_roots
|
||||
|
||||
missing = sorted(expected_roots - actual_module_roots)
|
||||
unexpected = sorted(actual_module_roots - expected_roots)
|
||||
|
||||
if missing or unexpected:
|
||||
print('check-changes filter drift detected:')
|
||||
if missing:
|
||||
print(' Missing roots:', ', '.join(missing))
|
||||
if unexpected:
|
||||
print(' Unexpected roots:', ', '.join(unexpected))
|
||||
raise SystemExit(1)
|
||||
|
||||
print('check-changes filter is aligned with settings.gradle module roots.')
|
||||
PY
|
||||
|
||||
# 2. VALIDATION & BUILD: Delegate to reusable-check.yml
|
||||
# We disable instrumented tests for PRs to keep feedback fast (< 10 mins).
|
||||
validate-and-build:
|
||||
needs: check-changes
|
||||
needs: [check-changes, verify-check-changes-filter]
|
||||
if: needs.check-changes.outputs.android == 'true'
|
||||
uses: ./.github/workflows/reusable-check.yml
|
||||
with:
|
||||
|
|
@ -51,11 +112,16 @@ jobs:
|
|||
check-workflow-status:
|
||||
name: Check Workflow Status
|
||||
runs-on: ubuntu-latest
|
||||
needs: [check-changes, validate-and-build]
|
||||
needs: [check-changes, verify-check-changes-filter, validate-and-build]
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check Workflow Status
|
||||
run: |
|
||||
if [[ "${{ needs.verify-check-changes-filter.result }}" == "failure" || "${{ needs.verify-check-changes-filter.result }}" == "cancelled" ]]; then
|
||||
echo "::error::check-changes filter verification failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If changes were detected but build failed, fail the status check
|
||||
if [[ "${{ needs.check-changes.outputs.android }}" == "true" && ("${{ needs.validate-and-build.result }}" == "failure" || "${{ needs.validate-and-build.result }}" == "cancelled") ]]; then
|
||||
echo "::error::Android Check failed"
|
||||
|
|
|
|||
197
.github/workflows/reusable-check.yml
vendored
197
.github/workflows/reusable-check.yml
vendored
|
|
@ -36,25 +36,22 @@ on:
|
|||
GRADLE_CACHE_PASSWORD:
|
||||
required: false
|
||||
|
||||
env:
|
||||
DATADOG_APPLICATION_ID: ${{ secrets.DATADOG_APPLICATION_ID }}
|
||||
DATADOG_CLIENT_TOKEN: ${{ secrets.DATADOG_CLIENT_TOKEN }}
|
||||
MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }}
|
||||
GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }}
|
||||
GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }}
|
||||
|
||||
jobs:
|
||||
check:
|
||||
host-check:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
api_level: ${{ fromJson(inputs.api_levels) }}
|
||||
env:
|
||||
DATADOG_APPLICATION_ID: ${{ secrets.DATADOG_APPLICATION_ID }}
|
||||
DATADOG_CLIENT_TOKEN: ${{ secrets.DATADOG_CLIENT_TOKEN }}
|
||||
MAPS_API_KEY: ${{ secrets.GOOGLE_MAPS_API_KEY }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }}
|
||||
GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }}
|
||||
GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }}
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
|
@ -74,7 +71,7 @@ jobs:
|
|||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
with:
|
||||
dependency-graph: generate-and-submit
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.event_name != 'merge_group' && !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
|
||||
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
|
||||
cache-cleanup: on-success
|
||||
build-scan-publish: true
|
||||
|
|
@ -82,34 +79,125 @@ jobs:
|
|||
build-scan-terms-of-use-agree: 'yes'
|
||||
add-job-summary: always
|
||||
|
||||
- name: Determine Tasks
|
||||
id: tasks
|
||||
run: |
|
||||
IS_FIRST_API=$(echo '${{ inputs.api_levels }}' | jq -r '.[0] == ${{ matrix.api_level }}')
|
||||
|
||||
# Matrix-specific tasks
|
||||
TASKS="assembleDebug "
|
||||
[ "${{ inputs.run_lint }}" = "true" ] && TASKS="$TASKS lintDebug "
|
||||
|
||||
# Instrumented Test Tasks
|
||||
if [ "${{ inputs.run_instrumented_tests }}" = "true" ]; then
|
||||
TASKS="$TASKS connectedDebugAndroidTest "
|
||||
fi
|
||||
|
||||
echo "tasks=$TASKS" >> $GITHUB_OUTPUT
|
||||
echo "is_first_api=$IS_FIRST_API" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Code Style & Static Analysis
|
||||
if: steps.tasks.outputs.is_first_api == 'true'
|
||||
if: inputs.run_lint == true
|
||||
run: ./gradlew spotlessCheck detekt -Pci=true --scan
|
||||
|
||||
- name: Shared Unit Tests
|
||||
if: steps.tasks.outputs.is_first_api == 'true' && inputs.run_unit_tests == true
|
||||
run: ./gradlew testDebugUnitTest testFdroidDebugUnitTest testGoogleDebugUnitTest koverXmlReport app:koverXmlReportFdroidDebug app:koverXmlReportGoogleDebug -Pci=true --continue --scan
|
||||
- name: Android Lint
|
||||
if: inputs.run_lint == true
|
||||
run: ./gradlew app:lintFdroidDebug app:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug core:api:lintDebug mesh_service_example:lintDebug -Pci=true --continue --scan
|
||||
|
||||
- name: Shared Unit Tests & Coverage
|
||||
if: inputs.run_unit_tests == true
|
||||
run: ./gradlew test koverXmlReport app:koverXmlReportFdroidDebug app:koverXmlReportGoogleDebug core:api:koverXmlReportDebug core:barcode:koverXmlReportFdroidDebug core:barcode:koverXmlReportGoogleDebug mesh_service_example:koverXmlReportDebug -Pci=true --continue --scan
|
||||
|
||||
- name: KMP JVM Smoke Compile
|
||||
if: steps.tasks.outputs.is_first_api == 'true'
|
||||
run: ./gradlew :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:ui:compileKotlinJvm :feature:intro:compileKotlinJvm :feature:messaging:compileKotlinJvm :feature:connections:compileKotlinJvm :feature:map:compileKotlinJvm :feature:node:compileKotlinJvm :feature:settings:compileKotlinJvm :feature:firmware:compileKotlinJvm :desktop:test -Pci=true --continue --scan
|
||||
run: ./gradlew :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 -Pci=true --continue --scan
|
||||
|
||||
- name: Upload coverage results to Codecov
|
||||
if: ${{ !cancelled() && inputs.run_unit_tests }}
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: meshtastic/Meshtastic-Android
|
||||
flags: host-unit
|
||||
fail_ci_if_error: false
|
||||
files: "**/build/reports/kover/report*.xml"
|
||||
|
||||
- name: Upload unit test results to Codecov
|
||||
if: ${{ !cancelled() && inputs.run_unit_tests }}
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: meshtastic/Meshtastic-Android
|
||||
flags: host-unit
|
||||
fail_ci_if_error: false
|
||||
report_type: test_results
|
||||
files: "**/build/test-results/**/*.xml"
|
||||
|
||||
- name: Upload host reports
|
||||
if: ${{ always() && inputs.upload_artifacts }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: reports-host
|
||||
path: |
|
||||
**/build/reports
|
||||
**/build/test-results
|
||||
retention-days: 7
|
||||
|
||||
android-check:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
api_level: ${{ fromJson(inputs.api_levels) }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Validate Gradle Wrapper
|
||||
uses: gradle/actions/wrapper-validation@v5
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v5
|
||||
with:
|
||||
cache-read-only: ${{ github.ref != 'refs/heads/main' && github.event_name != 'merge_group' && !startsWith(github.ref, 'refs/heads/gh-readonly-queue/') }}
|
||||
cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
|
||||
cache-cleanup: on-success
|
||||
build-scan-publish: true
|
||||
build-scan-terms-of-use-url: 'https://gradle.com/terms-of-service'
|
||||
build-scan-terms-of-use-agree: 'yes'
|
||||
add-job-summary: always
|
||||
|
||||
- name: Determine matrix metadata
|
||||
id: matrix_meta
|
||||
shell: bash
|
||||
run: |
|
||||
first_api=$(python3 - <<'PY'
|
||||
import json
|
||||
print(json.loads('${{ inputs.api_levels }}')[0])
|
||||
PY
|
||||
)
|
||||
|
||||
if [[ "${{ matrix.api_level }}" == "$first_api" ]]; then
|
||||
echo "is_first_api=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "is_first_api=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Determine Android tasks
|
||||
id: tasks
|
||||
shell: bash
|
||||
run: |
|
||||
tasks=(
|
||||
"app:assembleFdroidDebug"
|
||||
"app:assembleGoogleDebug"
|
||||
"mesh_service_example:assembleDebug"
|
||||
)
|
||||
|
||||
if [[ "${{ inputs.run_instrumented_tests }}" == "true" ]]; then
|
||||
tasks+=(
|
||||
"app:connectedFdroidDebugAndroidTest"
|
||||
"app:connectedGoogleDebugAndroidTest"
|
||||
"core:barcode:connectedFdroidDebugAndroidTest"
|
||||
"core:barcode:connectedGoogleDebugAndroidTest"
|
||||
)
|
||||
fi
|
||||
|
||||
printf 'tasks=%s\n' "${tasks[*]}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Enable KVM group perms
|
||||
if: inputs.run_instrumented_tests == true
|
||||
|
|
@ -118,7 +206,7 @@ jobs:
|
|||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: Run Flavor Check (with Emulator)
|
||||
- name: Run Android Build & Instrumented Tests
|
||||
if: inputs.run_instrumented_tests == true
|
||||
uses: reactivecircus/android-emulator-runner@v2
|
||||
with:
|
||||
|
|
@ -127,30 +215,25 @@ jobs:
|
|||
force-avd-creation: false
|
||||
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
|
||||
disable-animations: true
|
||||
script: ./gradlew ${{ steps.tasks.outputs.tasks }} -Pci=true -PenableComposeCompilerMetrics=true -PenableComposeCompilerReports=true --parallel --configuration-cache --continue --scan
|
||||
script: ./gradlew ${{ steps.tasks.outputs.tasks }} -Pci=true --parallel --configuration-cache --continue --scan
|
||||
|
||||
- name: Run Flavor Check (no Emulator)
|
||||
- name: Run Android Build
|
||||
if: inputs.run_instrumented_tests == false
|
||||
run: ./gradlew ${{ steps.tasks.outputs.tasks }} -Pci=true -PenableComposeCompilerMetrics=true -PenableComposeCompilerReports=true --parallel --configuration-cache --continue --scan
|
||||
run: ./gradlew ${{ steps.tasks.outputs.tasks }} -Pci=true --parallel --configuration-cache --continue --scan
|
||||
|
||||
- name: Upload coverage results to Codecov
|
||||
if: ${{ !cancelled() }}
|
||||
- name: Upload instrumented test results to Codecov
|
||||
if: ${{ !cancelled() && inputs.run_instrumented_tests && steps.matrix_meta.outputs.is_first_api == 'true' }}
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: meshtastic/Meshtastic-Android
|
||||
files: "**/build/reports/kover/report*.xml"
|
||||
|
||||
- name: Upload test results to Codecov
|
||||
if: ${{ !cancelled() }}
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
flags: android-instrumented
|
||||
fail_ci_if_error: false
|
||||
report_type: test_results
|
||||
files: "**/build/test-results/**/*.xml,**/build/outputs/androidTest-results/**/*.xml"
|
||||
files: "**/build/outputs/androidTest-results/**/*.xml"
|
||||
|
||||
- name: Upload debug artifact
|
||||
if: ${{ steps.tasks.outputs.is_first_api == 'true' && inputs.upload_artifacts }}
|
||||
if: ${{ steps.matrix_meta.outputs.is_first_api == 'true' && inputs.upload_artifacts }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: app-debug-apks
|
||||
|
|
@ -158,20 +241,18 @@ jobs:
|
|||
retention-days: 14
|
||||
|
||||
- name: Report App Size
|
||||
if: always() && steps.tasks.outputs.is_first_api == 'true'
|
||||
if: ${{ always() && steps.matrix_meta.outputs.is_first_api == 'true' }}
|
||||
run: |
|
||||
echo "### 📦 App Size Report" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Artifact | Size |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| --- | --- |" >> $GITHUB_STEP_SUMMARY
|
||||
find app/build/outputs/apk -name "*.apk" -exec du -h {} + | awk '{print "| " $2 " | " $1 " |"}' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- name: Upload reports
|
||||
- name: Upload Android reports
|
||||
if: ${{ always() && inputs.upload_artifacts }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: reports-api-${{ matrix.api_level }}
|
||||
name: reports-android-api-${{ matrix.api_level }}
|
||||
path: |
|
||||
**/build/reports
|
||||
**/build/test-results
|
||||
**/build/outputs/androidTest-results
|
||||
retention-days: 7
|
||||
|
|
|
|||
14
AGENTS.md
14
AGENTS.md
|
|
@ -27,7 +27,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
| Directory | Description |
|
||||
| :--- | :--- |
|
||||
| `app/` | Main application module. Contains `MainActivity`, Koin DI modules, and app-level logic. Uses package `org.meshtastic.app`. |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.library`, `meshtastic.koin`). |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.feature`, `meshtastic.kmp.library`, `meshtastic.koin`). |
|
||||
| `config/` | Detekt static analysis rules (`config/detekt/detekt.yml`) and Spotless formatting config (`config/spotless/.editorconfig`). |
|
||||
| `docs/` | Architecture docs and agent playbooks. See `docs/agent-playbooks/README.md` for version baseline and task recipes. |
|
||||
| `core/model` | Domain models and common data structures. |
|
||||
|
|
@ -50,7 +50,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
| `core/ble/` | Bluetooth Low Energy stack using Nordic libraries. |
|
||||
| `core/resources/` | Centralized string and image resources (Compose Multiplatform). |
|
||||
| `core/testing/` | **Shared test doubles, fakes, and utilities for `commonTest` across all KMP modules.** |
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. |
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. Use `meshtastic.kmp.feature` convention plugin. |
|
||||
| `desktop/` | Compose Desktop application — first non-Android KMP target. Nav 3 shell, full Koin DI graph, TCP transport with `want_config` handshake. |
|
||||
| `mesh_service_example/` | Sample app showing `core:api` service integration. |
|
||||
|
||||
|
|
@ -78,6 +78,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
- **Compose Multiplatform:** Version catalog aliases for Compose Multiplatform artifacts use the `compose-multiplatform-*` prefix (e.g., `compose-multiplatform-material3`, `compose-multiplatform-foundation`). Never use plain `androidx.compose` dependencies in common Main.
|
||||
- **Room KMP:** Always use `factory = { MeshtasticDatabaseConstructor.initialize() }` in `Room.databaseBuilder` and `inMemoryDatabaseBuilder`. DAOs and Entities reside in `commonMain`.
|
||||
- **Testing:** Write ViewModel and business logic tests in `commonTest`. Use `core:testing` shared fakes.
|
||||
- **Build-logic conventions:** In `build-logic/convention`, prefer lazy Gradle configuration (`configureEach`, `withPlugin`, provider APIs). Avoid `afterEvaluate` in convention plugins unless there is no viable lazy alternative.
|
||||
|
||||
### C. Namespacing
|
||||
- **Standard:** Use the `org.meshtastic.*` namespace for all code.
|
||||
|
|
@ -117,6 +118,15 @@ Always run commands in the following order to ensure reliability. Do not attempt
|
|||
```
|
||||
*Note: If testing Compose UI on the JVM (Robolectric) with Java 17, pin your tests to `@Config(sdk = [34])` to avoid SDK 35 compatibility crashes.*
|
||||
|
||||
**CI workflow conventions (GitHub Actions):**
|
||||
- Reusable CI is split into a host job and an Android matrix job in `.github/workflows/reusable-check.yml`.
|
||||
- Host job runs style/static checks, explicit Android lint tasks, unit tests, and Kover XML coverage uploads once.
|
||||
- Android matrix job runs explicit assemble tasks for `app` and `mesh_service_example`; instrumentation is enabled by input and matrix API.
|
||||
- Prefer explicit Gradle task paths in CI (for example `app:lintFdroidDebug`, `app:connectedGoogleDebugAndroidTest`) instead of shorthand tasks like `lintDebug`.
|
||||
- Pull request CI is main-only (`.github/workflows/pull-request.yml` targets `main` branch).
|
||||
- Gradle cache writes are trusted on `main` and merge queue runs (`merge_group` / `gh-readonly-queue/*`); other refs use read-only cache mode in reusable CI.
|
||||
- PR `check-changes` path filtering lives in `.github/workflows/pull-request.yml` and must include module dirs plus build/workflow entrypoints (`build-logic/**`, `gradle/**`, `.github/workflows/**`, `gradlew`, `settings.gradle.kts`, etc.) so CI is not skipped for infra-only changes.
|
||||
|
||||
### C. Documentation Sync
|
||||
Update documentation continuously as part of the same change. If you modify architecture, module targets, CI tasks, validation commands, or agent workflow rules, update the relevant docs (`AGENTS.md`, `.github/copilot-instructions.md`, `GEMINI.md`, `docs/agent-playbooks/*`, `docs/kmp-status.md`, and `docs/decisions/architecture-review-2026-03.md`).
|
||||
|
||||
|
|
|
|||
14
GEMINI.md
14
GEMINI.md
|
|
@ -27,7 +27,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
| Directory | Description |
|
||||
| :--- | :--- |
|
||||
| `app/` | Main application module. Contains `MainActivity`, Koin DI modules, and app-level logic. Uses package `org.meshtastic.app`. |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.library`, `meshtastic.koin`). |
|
||||
| `build-logic/` | Convention plugins for shared build configuration (e.g., `meshtastic.kmp.feature`, `meshtastic.kmp.library`, `meshtastic.koin`). |
|
||||
| `config/` | Detekt static analysis rules (`config/detekt/detekt.yml`) and Spotless formatting config (`config/spotless/.editorconfig`). |
|
||||
| `docs/` | Architecture docs and agent playbooks. See `docs/agent-playbooks/README.md` for version baseline and task recipes. |
|
||||
| `core/model` | Domain models and common data structures. |
|
||||
|
|
@ -50,7 +50,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
| `core/ble/` | Bluetooth Low Energy stack using Nordic libraries. |
|
||||
| `core/resources/` | Centralized string and image resources (Compose Multiplatform). |
|
||||
| `core/testing/` | **Shared test doubles, fakes, and utilities for `commonTest` across all KMP modules.** |
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. |
|
||||
| `feature/` | Feature modules (e.g., `settings`, `map`, `messaging`, `node`, `intro`, `connections`). All are KMP with `jvm()` target. Use `meshtastic.kmp.feature` convention plugin. |
|
||||
| `desktop/` | Compose Desktop application — first non-Android KMP target. Nav 3 shell, full Koin DI graph, TCP transport with `want_config` handshake. |
|
||||
| `mesh_service_example/` | Sample app showing `core:api` service integration. |
|
||||
|
||||
|
|
@ -78,6 +78,7 @@ Meshtastic-Android is a Kotlin Multiplatform (KMP) application for off-grid, dec
|
|||
- **Compose Multiplatform:** Version catalog aliases for Compose Multiplatform artifacts use the `compose-multiplatform-*` prefix (e.g., `compose-multiplatform-material3`, `compose-multiplatform-foundation`). Never use plain `androidx.compose` dependencies in common Main.
|
||||
- **Room KMP:** Always use `factory = { MeshtasticDatabaseConstructor.initialize() }` in `Room.databaseBuilder` and `inMemoryDatabaseBuilder`. DAOs and Entities reside in `commonMain`.
|
||||
- **Testing:** Write ViewModel and business logic tests in `commonTest`. Use `core:testing` shared fakes.
|
||||
- **Build-logic conventions:** In `build-logic/convention`, prefer lazy Gradle configuration (`configureEach`, `withPlugin`, provider APIs). Avoid `afterEvaluate` in convention plugins unless there is no viable lazy alternative.
|
||||
|
||||
### C. Namespacing
|
||||
- **Standard:** Use the `org.meshtastic.*` namespace for all code.
|
||||
|
|
@ -117,6 +118,15 @@ Always run commands in the following order to ensure reliability. Do not attempt
|
|||
```
|
||||
*Note: If testing Compose UI on the JVM (Robolectric) with Java 17, pin your tests to `@Config(sdk = [34])` to avoid SDK 35 compatibility crashes.*
|
||||
|
||||
**CI workflow conventions (GitHub Actions):**
|
||||
- Reusable CI is split into a host job and an Android matrix job in `.github/workflows/reusable-check.yml`.
|
||||
- Host job runs style/static checks, explicit Android lint tasks, unit tests, and Kover XML coverage uploads once.
|
||||
- Android matrix job runs explicit assemble tasks for `app` and `mesh_service_example`; instrumentation is enabled by input and matrix API.
|
||||
- Prefer explicit Gradle task paths in CI (for example `app:lintFdroidDebug`, `app:connectedGoogleDebugAndroidTest`) instead of shorthand tasks like `lintDebug`.
|
||||
- Pull request CI is main-only (`.github/workflows/pull-request.yml` targets `main` branch).
|
||||
- Gradle cache writes are trusted on `main` and merge queue runs (`merge_group` / `gh-readonly-queue/*`); other refs use read-only cache mode in reusable CI.
|
||||
- PR `check-changes` path filtering lives in `.github/workflows/pull-request.yml` and must include module dirs plus build/workflow entrypoints (`build-logic/**`, `gradle/**`, `.github/workflows/**`, `gradlew`, `settings.gradle.kts`, etc.) so CI is not skipped for infra-only changes.
|
||||
|
||||
### C. Documentation Sync
|
||||
Update documentation continuously as part of the same change. If you modify architecture, module targets, CI tasks, validation commands, or agent workflow rules, update the relevant docs (`AGENTS.md`, `.github/copilot-instructions.md`, `GEMINI.md`, `docs/agent-playbooks/*`, `docs/kmp-status.md`, and `docs/decisions/architecture-review-2026-03.md`).
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ plugins {
|
|||
alias(libs.plugins.meshtastic.android.application.compose)
|
||||
id("meshtastic.koin")
|
||||
alias(libs.plugins.kotlin.parcelize)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
alias(libs.plugins.secrets)
|
||||
alias(libs.plugins.aboutlibraries)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ dependencies {
|
|||
compileOnly(libs.secrets.gradlePlugin)
|
||||
compileOnly(libs.spotless.gradlePlugin)
|
||||
compileOnly(libs.test.retry.gradlePlugin)
|
||||
compileOnly(libs.truth)
|
||||
|
||||
detektPlugins(libs.detekt.formatting)
|
||||
}
|
||||
|
|
@ -177,6 +176,11 @@ gradlePlugin {
|
|||
implementationClass = "KmpLibraryComposeConventionPlugin"
|
||||
}
|
||||
|
||||
register("kmpFeature") {
|
||||
id = "meshtastic.kmp.feature"
|
||||
implementationClass = "KmpFeatureConventionPlugin"
|
||||
}
|
||||
|
||||
register("dokka") {
|
||||
id = "meshtastic.dokka"
|
||||
implementationClass = "DokkaConventionPlugin"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.meshtastic.buildlogic.library
|
||||
import org.meshtastic.buildlogic.libs
|
||||
|
||||
/**
|
||||
* Convention plugin for KMP feature modules.
|
||||
*
|
||||
* Composes [KmpLibraryConventionPlugin], [KmpLibraryComposeConventionPlugin], and
|
||||
* [KoinConventionPlugin] and wires the common Compose / Lifecycle / Koin dependencies
|
||||
* that every feature module needs. Feature `build.gradle.kts` files only declare
|
||||
* their module-specific deps.
|
||||
*
|
||||
* Modelled after the `AndroidFeatureImplConventionPlugin` pattern from
|
||||
* [Now in Android](https://github.com/android/nowinandroid).
|
||||
*/
|
||||
class KmpFeatureConventionPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
apply(plugin = "meshtastic.kmp.library")
|
||||
apply(plugin = "meshtastic.kmp.library.compose")
|
||||
apply(plugin = "meshtastic.koin")
|
||||
|
||||
extensions.configure<KotlinMultiplatformExtension> {
|
||||
sourceSets.getByName("commonMain").dependencies {
|
||||
// Compose Multiplatform UI
|
||||
implementation(libs.library("compose-multiplatform-material3"))
|
||||
implementation(libs.library("compose-multiplatform-materialIconsExtended"))
|
||||
|
||||
// Lifecycle & ViewModel (JetBrains KMP forks — safe in commonMain)
|
||||
implementation(libs.library("jetbrains-lifecycle-viewmodel-compose"))
|
||||
implementation(libs.library("jetbrains-lifecycle-runtime-compose"))
|
||||
|
||||
// Koin ViewModel wiring
|
||||
implementation(libs.library("koin-compose-viewmodel"))
|
||||
|
||||
// Logging
|
||||
implementation(libs.library("kermit"))
|
||||
}
|
||||
|
||||
sourceSets.getByName("androidMain").dependencies {
|
||||
// Compose BOM for consistent Android Compose versions
|
||||
implementation(target.dependencies.platform(libs.library("androidx-compose-bom")))
|
||||
|
||||
// Common Android Compose dependencies
|
||||
implementation(libs.library("accompanist-permissions"))
|
||||
implementation(libs.library("androidx-activity-compose"))
|
||||
implementation(libs.library("androidx-compose-material3"))
|
||||
implementation(libs.library("androidx-compose-material-iconsExtended"))
|
||||
implementation(libs.library("androidx-compose-ui-text"))
|
||||
implementation(libs.library("androidx-compose-ui-tooling-preview"))
|
||||
}
|
||||
|
||||
sourceSets.getByName("commonTest").dependencies {
|
||||
implementation(project(":core:testing"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -17,10 +17,11 @@
|
|||
|
||||
package org.meshtastic.buildlogic
|
||||
|
||||
import com.android.build.api.attributes.ProductFlavorAttr
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.attributes.Attribute
|
||||
|
||||
private const val MARKETPLACE_ATTRIBUTE_NAME = "com.android.build.api.attributes.ProductFlavor:marketplace"
|
||||
private const val LEGACY_MARKETPLACE_ATTRIBUTE_NAME = "marketplace"
|
||||
|
||||
internal fun Project.configureAndroidMarketplaceFallback() {
|
||||
val defaultMarketplace =
|
||||
|
|
@ -29,13 +30,16 @@ internal fun Project.configureAndroidMarketplaceFallback() {
|
|||
.orElse(MeshtasticFlavor.entries.first { it.default }.name)
|
||||
.get()
|
||||
|
||||
val marketplaceAttr = Attribute.of(MARKETPLACE_ATTRIBUTE_NAME, String::class.java)
|
||||
val marketplaceAttr = ProductFlavorAttr.of(MeshtasticFlavor.fdroid.dimension.name)
|
||||
val legacyMarketplaceAttr = Attribute.of(LEGACY_MARKETPLACE_ATTRIBUTE_NAME, String::class.java)
|
||||
|
||||
afterEvaluate {
|
||||
configurations.all {
|
||||
if (!isCanBeResolved || isCanBeConsumed) return@all
|
||||
if (!name.contains("android", ignoreCase = true)) return@all
|
||||
if (attributes.getAttribute(marketplaceAttr) != null) return@all
|
||||
configurations.configureEach {
|
||||
if (!isCanBeResolved || isCanBeConsumed) return@configureEach
|
||||
if (!name.contains("android", ignoreCase = true)) return@configureEach
|
||||
if (attributes.getAttribute(marketplaceAttr) != null && attributes.getAttribute(legacyMarketplaceAttr) != null) {
|
||||
return@configureEach
|
||||
}
|
||||
|
||||
// Prefer explicit flavor from configuration name; otherwise use configurable default.
|
||||
val inferredMarketplace =
|
||||
|
|
@ -45,7 +49,8 @@ internal fun Project.configureAndroidMarketplaceFallback() {
|
|||
else -> defaultMarketplace
|
||||
}
|
||||
|
||||
attributes.attribute(marketplaceAttr, inferredMarketplace)
|
||||
attributes.attribute(marketplaceAttr, objects.named(ProductFlavorAttr::class.java, inferredMarketplace))
|
||||
attributes.attribute(legacyMarketplaceAttr, inferredMarketplace)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ internal enum class PluginType(val id: String, val ref: String, val style: Strin
|
|||
ref = "jvm-library",
|
||||
style = "fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000",
|
||||
),
|
||||
KmpFeature(
|
||||
id = "meshtastic.kmp.feature",
|
||||
ref = "kmp-feature",
|
||||
style = "fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000",
|
||||
),
|
||||
KmpLibrary(
|
||||
id = "meshtastic.kmp.library",
|
||||
ref = "kmp-library",
|
||||
|
|
@ -123,6 +128,7 @@ internal fun Project.configureGraphTasks() {
|
|||
val type = when {
|
||||
pluginManager.hasPlugin("meshtastic.android.application") || pluginManager.hasPlugin("meshtastic.android.application.compose") -> PluginType.AndroidApplication
|
||||
targetProjectPath.startsWith(":desktop") -> PluginType.ComposeDesktopApplication
|
||||
pluginManager.hasPlugin("meshtastic.kmp.feature") -> PluginType.KmpFeature
|
||||
targetProjectPath.startsWith(":feature:") -> PluginType.AndroidFeature
|
||||
else -> PluginType.entries.firstOrNull { pluginManager.hasPlugin(it.id) } ?: Unknown
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ kotlin {
|
|||
commonMain.dependencies {
|
||||
api(libs.aboutlibraries.core)
|
||||
implementation(libs.aboutlibraries.compose.m3)
|
||||
implementation(libs.javax.inject)
|
||||
implementation(libs.kotlinx.atomicfu)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
api(libs.kotlinx.datetime)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ kotlin {
|
|||
implementation(libs.kotlinx.coroutines.test)
|
||||
implementation(libs.androidx.room.testing)
|
||||
}
|
||||
androidMain.dependencies { implementation(libs.javax.inject) }
|
||||
|
||||
val androidHostTest by getting {
|
||||
dependencies {
|
||||
|
|
|
|||
|
|
@ -29,10 +29,5 @@ kotlin {
|
|||
androidResources.enable = false
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
api(libs.javax.inject)
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
}
|
||||
}
|
||||
sourceSets { commonMain.dependencies { implementation(libs.kotlinx.coroutines.core) } }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.devtools.ksp)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +40,6 @@ kotlin {
|
|||
implementation(projects.core.datastore)
|
||||
implementation(projects.core.resources)
|
||||
|
||||
api(libs.javax.inject)
|
||||
implementation(libs.kermit)
|
||||
implementation(libs.compose.multiplatform.resources)
|
||||
implementation(libs.okio)
|
||||
|
|
|
|||
|
|
@ -64,11 +64,3 @@ kotlin {
|
|||
commonTest.dependencies { implementation(libs.kotlinx.coroutines.test) }
|
||||
}
|
||||
}
|
||||
|
||||
val marketplaceAttr = Attribute.of("marketplace", String::class.java)
|
||||
|
||||
configurations.all {
|
||||
if (name.contains("android", ignoreCase = true)) {
|
||||
attributes.attribute(marketplaceAttr, "fdroid")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ kotlin {
|
|||
|
||||
androidMain.dependencies {
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.compose.multiplatform.runtime)
|
||||
implementation(libs.compose.multiplatform.ui)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.prefs.di
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class AnalyticsDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class HomoglyphEncodingDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class AppDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class CustomEmojiDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MapDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MapConsentDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MapTileProviderDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MeshDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class RadioDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class UiDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class MeshLogDataStore
|
||||
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
annotation class FilterDataStore
|
||||
|
|
@ -48,8 +48,6 @@ kotlin {
|
|||
implementation(libs.compose.multiplatform.materialIconsExtended)
|
||||
implementation(libs.compose.multiplatform.ui)
|
||||
implementation(libs.compose.multiplatform.foundation)
|
||||
implementation(libs.compose.multiplatform.runtime)
|
||||
implementation(libs.compose.multiplatform.resources)
|
||||
implementation(libs.compose.multiplatform.ui.tooling)
|
||||
|
||||
implementation(libs.kermit)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
plugins { alias(libs.plugins.meshtastic.kmp.feature) }
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
|
|
@ -33,8 +29,6 @@ kotlin {
|
|||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.compose.multiplatform.material3)
|
||||
implementation(libs.compose.multiplatform.materialIconsExtended)
|
||||
implementation(libs.compose.multiplatform.foundation)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.data)
|
||||
|
|
@ -53,25 +47,10 @@ kotlin {
|
|||
implementation(projects.core.network)
|
||||
implementation(projects.feature.settings)
|
||||
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.jetbrains.navigation3.runtime)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.kermit)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.jetbrains.lifecycle.runtime.compose)
|
||||
implementation(libs.usb.serial.android)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
androidMain.dependencies { implementation(libs.usb.serial.android) }
|
||||
|
||||
androidUnitTest.dependencies {
|
||||
implementation(libs.mockk)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@
|
|||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.kmp.feature)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -49,22 +47,12 @@ kotlin {
|
|||
implementation(projects.core.ui)
|
||||
|
||||
implementation(libs.kable.core)
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.kermit)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
implementation(libs.ktor.client.core)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.nordic.dfu)
|
||||
implementation(libs.coil)
|
||||
implementation(libs.coil.network.okhttp)
|
||||
|
|
@ -73,8 +61,6 @@ kotlin {
|
|||
implementation(libs.markdown.renderer)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
|
||||
val androidHostTest by getting {
|
||||
dependencies {
|
||||
implementation(libs.junit)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@
|
|||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.kmp.feature)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -40,23 +38,10 @@ kotlin {
|
|||
implementation(projects.core.ui)
|
||||
implementation(projects.core.resources)
|
||||
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.jetbrains.navigation3.runtime)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.jetbrains.navigation3.ui)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
androidMain.dependencies { implementation(libs.jetbrains.navigation3.ui) }
|
||||
|
||||
androidUnitTest.dependencies {
|
||||
implementation(libs.junit)
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.kmp.feature)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -45,34 +43,19 @@ kotlin {
|
|||
implementation(projects.core.resources)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.di)
|
||||
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
implementation(libs.androidx.datastore)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.annotation)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.jetbrains.lifecycle.runtime.compose)
|
||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||
implementation(libs.androidx.lifecycle.viewmodel.ktx)
|
||||
implementation(libs.androidx.navigation.common)
|
||||
implementation(libs.androidx.savedstate.compose)
|
||||
implementation(libs.androidx.savedstate.ktx)
|
||||
implementation(libs.material)
|
||||
implementation(libs.kermit)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
|
||||
androidUnitTest.dependencies {
|
||||
implementation(libs.junit)
|
||||
implementation(libs.mockk)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
plugins { alias(libs.plugins.meshtastic.kmp.feature) }
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
|
|
@ -33,8 +29,6 @@ kotlin {
|
|||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.compose.multiplatform.material3)
|
||||
implementation(libs.compose.multiplatform.materialIconsExtended)
|
||||
implementation(libs.compose.multiplatform.foundation)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.data)
|
||||
|
|
@ -48,10 +42,7 @@ kotlin {
|
|||
implementation(projects.core.service)
|
||||
implementation(projects.core.ui)
|
||||
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.jetbrains.navigation3.runtime)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.kermit)
|
||||
implementation(libs.androidx.paging.common)
|
||||
|
||||
// JetBrains Material 3 Adaptive (multiplatform ListDetailPaneScaffold)
|
||||
|
|
@ -61,21 +52,10 @@ kotlin {
|
|||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
implementation(libs.jetbrains.lifecycle.runtime.compose)
|
||||
|
||||
implementation(libs.androidx.paging.compose)
|
||||
implementation(libs.androidx.work.runtime.ktx)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
|
||||
androidUnitTest.dependencies {
|
||||
implementation(libs.mockk)
|
||||
implementation(libs.androidx.work.testing)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@
|
|||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.kmp.feature)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -34,8 +32,6 @@ kotlin {
|
|||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.compose.multiplatform.material3)
|
||||
implementation(libs.compose.multiplatform.materialIconsExtended)
|
||||
implementation(libs.coil)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.data)
|
||||
|
|
@ -52,11 +48,7 @@ kotlin {
|
|||
implementation(projects.core.di)
|
||||
implementation(projects.feature.map)
|
||||
|
||||
implementation(libs.jetbrains.lifecycle.runtime.compose)
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.jetbrains.navigation3.runtime)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.kermit)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
implementation(libs.markdown.renderer)
|
||||
implementation(libs.markdown.renderer.m3)
|
||||
|
|
@ -71,15 +63,7 @@ kotlin {
|
|||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
|
||||
implementation(libs.coil)
|
||||
implementation(libs.markdown.renderer.android)
|
||||
|
|
@ -87,8 +71,6 @@ kotlin {
|
|||
implementation(libs.markdown.renderer)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
|
||||
androidUnitTest.dependencies {
|
||||
implementation(libs.junit)
|
||||
implementation(libs.mockk)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@
|
|||
*/
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.meshtastic.kmp.library)
|
||||
alias(libs.plugins.meshtastic.kmp.library.compose)
|
||||
alias(libs.plugins.meshtastic.kmp.feature)
|
||||
alias(libs.plugins.meshtastic.kotlinx.serialization)
|
||||
alias(libs.plugins.meshtastic.koin)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
|
@ -33,8 +31,6 @@ kotlin {
|
|||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.compose.multiplatform.material3)
|
||||
implementation(libs.compose.multiplatform.materialIconsExtended)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.data)
|
||||
implementation(projects.core.database)
|
||||
|
|
@ -49,10 +45,6 @@ kotlin {
|
|||
implementation(projects.core.ui)
|
||||
implementation(projects.core.di)
|
||||
|
||||
implementation(libs.jetbrains.lifecycle.viewmodel.compose)
|
||||
implementation(libs.jetbrains.lifecycle.runtime.compose)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.kermit)
|
||||
implementation(libs.kotlinx.collections.immutable)
|
||||
implementation(libs.aboutlibraries.compose.m3)
|
||||
}
|
||||
|
|
@ -60,14 +52,7 @@ kotlin {
|
|||
androidMain.dependencies {
|
||||
implementation(projects.core.barcode)
|
||||
implementation(projects.core.nfc)
|
||||
implementation(project.dependencies.platform(libs.androidx.compose.bom))
|
||||
implementation(libs.accompanist.permissions)
|
||||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.androidx.compose.material.iconsExtended)
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.compose.ui.text)
|
||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||
|
||||
implementation(libs.coil)
|
||||
implementation(libs.markdown.renderer.android)
|
||||
|
|
@ -75,8 +60,6 @@ kotlin {
|
|||
implementation(libs.markdown.renderer)
|
||||
}
|
||||
|
||||
commonTest.dependencies { implementation(projects.core.testing) }
|
||||
|
||||
androidUnitTest.dependencies {
|
||||
implementation(libs.junit)
|
||||
implementation(libs.mockk)
|
||||
|
|
|
|||
|
|
@ -49,10 +49,13 @@ ktor = "3.4.1"
|
|||
# Other
|
||||
aboutlibraries = "13.2.1"
|
||||
coil = "3.4.0"
|
||||
datadog-gradle = "1.24.0"
|
||||
dd-sdk-android = "3.7.1"
|
||||
detekt = "1.23.8"
|
||||
dokka = "2.2.0-Beta"
|
||||
devtools-ksp = "2.3.6"
|
||||
firebase-crashlytics-gradle = "3.0.6"
|
||||
google-services-gradle = "4.4.4"
|
||||
markdownRenderer = "0.39.2"
|
||||
okio = "3.17.0"
|
||||
osmdroid-android = "6.1.20"
|
||||
|
|
@ -159,7 +162,6 @@ mlkit-barcode-scanning = { module = "com.google.mlkit:barcode-scanning", version
|
|||
play-services-maps = { module = "com.google.android.gms:play-services-maps", version = "20.0.0" }
|
||||
wire-runtime = { module = "com.squareup.wire:wire-runtime", version.ref = "wire" }
|
||||
zxing-core = { module = "com.google.zxing:core", version = "3.5.4" }
|
||||
truth = { module = "com.google.truth:truth", version = "1.4.5" }
|
||||
|
||||
# Jetbrains
|
||||
kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
|
|
@ -208,7 +210,6 @@ dd-sdk-android-timber = { module = "com.datadoghq:dd-sdk-android-timber", versio
|
|||
dd-sdk-android-trace = { module = "com.datadoghq:dd-sdk-android-trace", version.ref = "dd-sdk-android" }
|
||||
dd-sdk-android-trace-otel = { module = "com.datadoghq:dd-sdk-android-trace-otel", version.ref = "dd-sdk-android" }
|
||||
dokka-android-documentation-plugin = { module = "org.jetbrains.dokka:android-documentation-plugin", version.ref = "dokka" }
|
||||
javax-inject = { module = "javax.inject:javax.inject", version = "1" }
|
||||
markdown-renderer = { module = "com.mikepenz:multiplatform-markdown-renderer", version.ref = "markdownRenderer" }
|
||||
markdown-renderer-m3 = { module = "com.mikepenz:multiplatform-markdown-renderer-m3", version.ref = "markdownRenderer" }
|
||||
markdown-renderer-android = { module = "com.mikepenz:multiplatform-markdown-renderer-android", version.ref = "markdownRenderer" }
|
||||
|
|
@ -235,12 +236,12 @@ android-tools-common = { module = "com.android.tools:common", version = "32.1.0"
|
|||
androidx-room-gradlePlugin = { module = "androidx.room:room-gradle-plugin", version.ref = "room" }
|
||||
compose-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
|
||||
compose-multiplatform-gradlePlugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-multiplatform" }
|
||||
datadog-gradlePlugin = { module = "com.datadoghq.dd-sdk-android-gradle-plugin:com.datadoghq.dd-sdk-android-gradle-plugin.gradle.plugin", version = "1.24.0" }
|
||||
datadog-gradlePlugin = { module = "com.datadoghq.dd-sdk-android-gradle-plugin:com.datadoghq.dd-sdk-android-gradle-plugin.gradle.plugin", version.ref = "datadog-gradle" }
|
||||
detekt-compose = { module = "io.nlopez.compose.rules:detekt", version = "0.5.6" }
|
||||
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
|
||||
detekt-gradlePlugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
|
||||
firebase-crashlytics-gradlePlugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version = "3.0.6" }
|
||||
google-services-gradlePlugin = { module = "com.google.gms.google-services:com.google.gms.google-services.gradle.plugin", version = "4.4.4" }
|
||||
firebase-crashlytics-gradlePlugin = { module = "com.google.firebase:firebase-crashlytics-gradle", version.ref = "firebase-crashlytics-gradle" }
|
||||
google-services-gradlePlugin = { module = "com.google.gms.google-services:com.google.gms.google-services.gradle.plugin", version.ref = "google-services-gradle" }
|
||||
koin-gradlePlugin = { module = "io.insert-koin.compiler.plugin:io.insert-koin.compiler.plugin.gradle.plugin", version.ref = "koin-plugin" }
|
||||
kover-gradlePlugin = { module = "org.jetbrains.kotlinx.kover:org.jetbrains.kotlinx.kover.gradle.plugin", version.ref = "kover" }
|
||||
ksp-gradlePlugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "devtools-ksp" }
|
||||
|
|
@ -267,16 +268,16 @@ kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
|
|||
|
||||
# Google
|
||||
devtools-ksp = { id = "com.google.devtools.ksp", version.ref = "devtools-ksp" }
|
||||
google-services = { id = "com.google.gms.google-services", version = "4.4.4" }
|
||||
google-services = { id = "com.google.gms.google-services", version.ref = "google-services-gradle" }
|
||||
secrets = { id = "com.google.android.libraries.mapsplatform.secrets-gradle-plugin", version = "2.0.1" }
|
||||
|
||||
# Firebase
|
||||
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version = "3.0.6" }
|
||||
firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebase-crashlytics-gradle" }
|
||||
firebase-perf = { id = "com.google.firebase.firebase-perf", version = "2.0.2" }
|
||||
|
||||
# Other
|
||||
aboutlibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }
|
||||
datadog = { id = "com.datadoghq.dd-sdk-android-gradle-plugin", version = "1.24.0" }
|
||||
datadog = { id = "com.datadoghq.dd-sdk-android-gradle-plugin", version.ref = "datadog-gradle" }
|
||||
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
|
||||
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
|
||||
wire = { id = "com.squareup.wire", version.ref = "wire" }
|
||||
|
|
@ -299,6 +300,7 @@ meshtastic-android-test = { id = "meshtastic.android.test" }
|
|||
meshtastic-detekt = { id = "meshtastic.detekt" }
|
||||
meshtastic-koin = { id = "meshtastic.koin" }
|
||||
meshtastic-kotlinx-serialization = { id = "meshtastic.kotlinx.serialization" }
|
||||
meshtastic-kmp-feature = { id = "meshtastic.kmp.feature" }
|
||||
meshtastic-kmp-library = { id = "meshtastic.kmp.library" }
|
||||
meshtastic-kmp-library-compose = { id = "meshtastic.kmp.library.compose" }
|
||||
meshtastic-root = { id = "meshtastic.root" }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue