diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 50d1255db..8dea1e55c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -137,6 +137,13 @@ Always run commands in the following order to ensure reliability. Do not attempt - 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. +- **Runner strategy (three tiers):** + - **`ubuntu-24.04-arm`** — Lightweight/utility jobs (status checks, labelers, triage, changelog, release metadata, stale, moderation). These run only shell scripts or GitHub API calls and benefit from ARM runners' shorter queue times. + - **`ubuntu-24.04`** — Gradle-heavy jobs (CI host-check, android-check, release builds, Dokka, CodeQL, publish, dependency-submission). Pinned for reproducibility; avoid `ubuntu-latest` to prevent breakage when GitHub rolls the alias forward. + - **Desktop release matrix** — `[macos-latest, windows-latest, ubuntu-24.04, ubuntu-24.04-arm]` for cross-platform native packaging (DMG, MSI, deb/rpm/AppImage for x64 and ARM). +- **CI JVM tuning:** `gradle.properties` is tuned for local dev (8g heap, 4g Kotlin daemon). CI workflows override via `GRADLE_OPTS` env var to fit the 7GB RAM budget of standard runners: `-Xmx4g` Gradle heap, `-Xmx2g` Kotlin daemon, VFS watching disabled, workers capped at 4. +- **KMP Smoke Compile:** Use `./gradlew kmpSmokeCompile` instead of listing individual module compile tasks. The `kmpSmokeCompile` lifecycle task (registered in `RootConventionPlugin`) auto-discovers all KMP modules and depends on their `compileKotlinJvm` + `compileKotlinIosSimulatorArm64` tasks. +- **`mavenLocal()` gated:** The `mavenLocal()` repository is disabled by default to prevent CI cache poisoning. For local JitPack testing, pass `-PuseMavenLocal` to Gradle. - **Terminal Pagers:** When running shell commands like `git diff` or `git log`, ALWAYS use `--no-pager` (e.g., `git --no-pager diff`) to prevent the agent from getting stuck in an interactive prompt. - **Text Search:** Prefer using `rg` (ripgrep) over `grep` or `find` for fast text searching across the codebase. diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b84fc8607..250e34253 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -28,7 +28,7 @@ jobs: # - https://gh.io/supported-runners-and-hardware-resources # - https://gh.io/using-larger-runners (GitHub.com only) # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-24.04' }} if: github.repository == 'meshtastic/Meshtastic-Android' permissions: # required for all workflows diff --git a/.github/workflows/create-or-promote-release.yml b/.github/workflows/create-or-promote-release.yml index 053174c00..0d5877270 100644 --- a/.github/workflows/create-or-promote-release.yml +++ b/.github/workflows/create-or-promote-release.yml @@ -29,7 +29,7 @@ permissions: jobs: determine-tags: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm outputs: tag_to_process: ${{ steps.calculate_tags.outputs.tag_to_process }} release_name: ${{ steps.calculate_tags.outputs.release_name }} @@ -142,7 +142,7 @@ jobs: cleanup-on-failure: needs: [determine-tags, call-release-workflow] if: ${{ (failure() || cancelled()) && !inputs.dry_run && inputs.channel == 'internal' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/dependency-submission.yml b/.github/workflows/dependency-submission.yml index 10f2463f3..4e14783bf 100644 --- a/.github/workflows/dependency-submission.yml +++ b/.github/workflows/dependency-submission.yml @@ -10,7 +10,7 @@ permissions: jobs: dependency-submission: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.repository == 'meshtastic/Meshtastic-Android' steps: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e6e16c0af..12cee4d46 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -38,7 +38,7 @@ concurrency: jobs: build-docs: if: github.repository == 'meshtastic/Meshtastic-Android' - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout code uses: actions/checkout@v6 @@ -70,7 +70,7 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: build-docs steps: - name: Deploy to GitHub Pages diff --git a/.github/workflows/main-push-changelog.yml b/.github/workflows/main-push-changelog.yml index fb6f4a75e..09446c50b 100644 --- a/.github/workflows/main-push-changelog.yml +++ b/.github/workflows/main-push-changelog.yml @@ -16,7 +16,7 @@ concurrency: jobs: main-push-changelog: name: Generate main push changelog - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: - name: Checkout code uses: actions/checkout@v6 diff --git a/.github/workflows/merge-queue.yml b/.github/workflows/merge-queue.yml index 263246f1e..2818ca939 100644 --- a/.github/workflows/merge-queue.yml +++ b/.github/workflows/merge-queue.yml @@ -25,7 +25,7 @@ jobs: check-workflow-status: name: Check Workflow Status - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm permissions: {} needs: - android-check diff --git a/.github/workflows/models_issue_triage.yml b/.github/workflows/models_issue_triage.yml index f61a15fe6..87756b616 100644 --- a/.github/workflows/models_issue_triage.yml +++ b/.github/workflows/models_issue_triage.yml @@ -15,7 +15,7 @@ concurrency: jobs: triage: if: ${{ github.repository == 'meshtastic/firmware' && github.event.issue.user.type != 'Bot' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: # ───────────────────────────────────────────────────────────────────────── # Step 1: Quality check (spam/AI-slop detection) - runs first, exits early if spam diff --git a/.github/workflows/models_pr_triage.yml b/.github/workflows/models_pr_triage.yml index ef303c02a..af1b04037 100644 --- a/.github/workflows/models_pr_triage.yml +++ b/.github/workflows/models_pr_triage.yml @@ -16,7 +16,7 @@ concurrency: jobs: triage: if: ${{ github.repository == 'meshtastic/firmware' && github.event.pull_request.user.type != 'Bot' }} - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: # ───────────────────────────────────────────────────────────────────────── # Step 1: Check if PR already has automation/type labels (skip if so) diff --git a/.github/workflows/moderate.yml b/.github/workflows/moderate.yml index b576ad9a6..81eff6b59 100644 --- a/.github/workflows/moderate.yml +++ b/.github/workflows/moderate.yml @@ -9,7 +9,7 @@ on: jobs: spam-detection: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm permissions: issues: write pull-requests: write diff --git a/.github/workflows/post-release-cleanup.yml b/.github/workflows/post-release-cleanup.yml index 925d265fa..d62c36ed9 100644 --- a/.github/workflows/post-release-cleanup.yml +++ b/.github/workflows/post-release-cleanup.yml @@ -18,7 +18,7 @@ permissions: jobs: cleanup_prereleases: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm environment: Release steps: - name: Checkout code diff --git a/.github/workflows/pr_enforce_labels.yml b/.github/workflows/pr_enforce_labels.yml index 8669b3c43..05603796f 100644 --- a/.github/workflows/pr_enforce_labels.yml +++ b/.github/workflows/pr_enforce_labels.yml @@ -10,7 +10,7 @@ permissions: jobs: check-label: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: - name: Check for PR labels uses: actions/github-script@v8 diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 2fbba2b2a..2338a6aeb 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -65,7 +65,7 @@ permissions: jobs: prepare-build-info: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm outputs: APP_VERSION_NAME: ${{ steps.prep_version.outputs.APP_VERSION_NAME }} APP_VERSION_CODE: ${{ steps.calculate_version_code.outputs.versionCode }} @@ -102,7 +102,7 @@ jobs: shell: bash promote-release: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm environment: Release needs: [ prepare-build-info ] steps: @@ -116,7 +116,7 @@ jobs: user-fraction: ${{ (inputs.channel == 'production' && '0.1') || (inputs.channel == 'open' && '0.5') || '1.0' }} update-github-release: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: [ prepare-build-info, promote-release ] steps: - name: Checkout code diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index f22634a5d..59c22505a 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -12,7 +12,7 @@ on: jobs: publish: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read packages: write diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml index cebe7e588..7dfe1674b 100644 --- a/.github/workflows/pull-request-target.yml +++ b/.github/workflows/pull-request-target.yml @@ -9,7 +9,7 @@ jobs: permissions: contents: read pull-requests: write - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm steps: - id: label-the-PR uses: actions/labeler@v6 \ No newline at end of file diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c154d0a52..f5bdeb15d 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -19,7 +19,7 @@ jobs: # 1. CHANGE DETECTION: Prevents unnecessary builds check-changes: if: github.repository == 'meshtastic/Meshtastic-Android' && !( github.head_ref == 'scheduled-updates' || github.head_ref == 'l10n_main' ) - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm outputs: android: ${{ steps.filter.outputs.android }} steps: @@ -57,7 +57,7 @@ jobs: # 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 + runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v6 - name: Verify module roots are represented in check-changes filter @@ -115,7 +115,7 @@ jobs: # 3. WORKFLOW STATUS: Ensures required checks are satisfied check-workflow-status: name: Check Workflow Status - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm permissions: {} needs: [check-changes, verify-check-changes-filter, validate-and-build] if: always() diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed6cf0c7f..e03e9618a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,7 +61,7 @@ permissions: jobs: prepare-build-info: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm outputs: APP_VERSION_NAME: ${{ steps.prep_version.outputs.APP_VERSION_NAME }} APP_VERSION_CODE: ${{ steps.calculate_version_code.outputs.versionCode }} @@ -101,13 +101,18 @@ jobs: shell: bash release-google: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [prepare-build-info] environment: Release env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + GRADLE_OPTS: >- + -Dorg.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8 + -Dorg.gradle.vfs.watch=false + -Dorg.gradle.workers.max=4 + -Dkotlin.daemon.jvm.options=-Xmx2g -XX:+UseParallelGC steps: - name: Checkout code uses: actions/checkout@v6 @@ -193,13 +198,18 @@ jobs: subject-path: app/build/outputs/apk/google/release/*.apk release-fdroid: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: [prepare-build-info] environment: Release env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + GRADLE_OPTS: >- + -Dorg.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8 + -Dorg.gradle.vfs.watch=false + -Dorg.gradle.workers.max=4 + -Dkotlin.daemon.jvm.options=-Xmx2g -XX:+UseParallelGC steps: - name: Checkout code uses: actions/checkout@v6 @@ -266,7 +276,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest, windows-latest, ubuntu-22.04, ubuntu-22.04-arm] + os: [macos-latest, windows-latest, ubuntu-24.04, ubuntu-24.04-arm] env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} @@ -324,7 +334,7 @@ jobs: if-no-files-found: ignore github-release: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: [prepare-build-info, release-google, release-fdroid, release-desktop] env: INTERNAL_BUILDS_HOST: ${{ secrets.INTERNAL_BUILDS_HOST }} diff --git a/.github/workflows/reusable-check.yml b/.github/workflows/reusable-check.yml index 7aa1c7f31..c880de771 100644 --- a/.github/workflows/reusable-check.yml +++ b/.github/workflows/reusable-check.yml @@ -44,10 +44,17 @@ env: GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }} GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + # CI JVM tuning: override gradle.properties values (8g heap + 4g Kotlin daemon) + # that exceed the 7GB RAM on ubuntu-24.04 standard runners. + GRADLE_OPTS: >- + -Dorg.gradle.jvmargs=-Xmx4g -XX:+UseParallelGC -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8 + -Dorg.gradle.vfs.watch=false + -Dorg.gradle.workers.max=4 + -Dkotlin.daemon.jvm.options=-Xmx2g -XX:+UseParallelGC jobs: host-check: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read timeout-minutes: 60 @@ -93,7 +100,7 @@ jobs: run: ./gradlew test koverXmlReport app:koverXmlReportFdroidDebug app:koverXmlReportGoogleDebug core:api:koverXmlReportDebug core:barcode:koverXmlReportFdroidDebug core:barcode:koverXmlReportGoogleDebug mesh_service_example:koverXmlReportDebug desktop:koverXmlReport -Pci=true --continue --scan - name: KMP Smoke Compile - 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 :core:proto:compileKotlinIosSimulatorArm64 :core:common:compileKotlinIosSimulatorArm64 :core:model:compileKotlinIosSimulatorArm64 :core:repository:compileKotlinIosSimulatorArm64 :core:di:compileKotlinIosSimulatorArm64 :core:navigation:compileKotlinIosSimulatorArm64 :core:resources:compileKotlinIosSimulatorArm64 :core:datastore:compileKotlinIosSimulatorArm64 :core:database:compileKotlinIosSimulatorArm64 :core:domain:compileKotlinIosSimulatorArm64 :core:prefs:compileKotlinIosSimulatorArm64 :core:network:compileKotlinIosSimulatorArm64 :core:data:compileKotlinIosSimulatorArm64 :core:ble:compileKotlinIosSimulatorArm64 :core:nfc:compileKotlinIosSimulatorArm64 :core:service:compileKotlinIosSimulatorArm64 :core:testing:compileKotlinIosSimulatorArm64 :core:ui:compileKotlinIosSimulatorArm64 :feature:intro:compileKotlinIosSimulatorArm64 :feature:messaging:compileKotlinIosSimulatorArm64 :feature:connections:compileKotlinIosSimulatorArm64 :feature:map:compileKotlinIosSimulatorArm64 :feature:node:compileKotlinIosSimulatorArm64 :feature:settings:compileKotlinIosSimulatorArm64 :feature:firmware:compileKotlinIosSimulatorArm64 -Pci=true --continue --scan + run: ./gradlew kmpSmokeCompile -Pci=true --continue --scan - name: Upload coverage results to Codecov if: ${{ !cancelled() && inputs.run_unit_tests }} @@ -127,7 +134,7 @@ jobs: retention-days: 7 android-check: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: contents: read timeout-minutes: 60 diff --git a/.github/workflows/scheduled-updates.yml b/.github/workflows/scheduled-updates.yml index d7e5a4b7d..3fdec9f9d 100644 --- a/.github/workflows/scheduled-updates.yml +++ b/.github/workflows/scheduled-updates.yml @@ -7,7 +7,7 @@ on: jobs: update_assets: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 if: github.repository == 'meshtastic/Meshtastic-Android' permissions: contents: write # To commit files and push branches @@ -142,7 +142,7 @@ jobs: check-workflow-status: name: Check Workflow Status - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm permissions: {} needs: - update_assets diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index e0647e27e..1b9ee1fd6 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -12,7 +12,7 @@ permissions: jobs: stale_issues: name: Close Stale Issues - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm if: github.repository == 'meshtastic/Meshtastic-Android' steps: diff --git a/AGENTS.md b/AGENTS.md index a4bdbf32a..791689062 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -139,6 +139,13 @@ Always run commands in the following order to ensure reliability. Do not attempt - 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. +- **Runner strategy (three tiers):** + - **`ubuntu-24.04-arm`** — Lightweight/utility jobs (status checks, labelers, triage, changelog, release metadata, stale, moderation). These run only shell scripts or GitHub API calls and benefit from ARM runners' shorter queue times. + - **`ubuntu-24.04`** — Gradle-heavy jobs (CI host-check, android-check, release builds, Dokka, CodeQL, publish, dependency-submission). Pinned for reproducibility; avoid `ubuntu-latest` to prevent breakage when GitHub rolls the alias forward. + - **Desktop release matrix** — `[macos-latest, windows-latest, ubuntu-24.04, ubuntu-24.04-arm]` for cross-platform native packaging (DMG, MSI, deb/rpm/AppImage for x64 and ARM). +- **CI JVM tuning:** `gradle.properties` is tuned for local dev (8g heap, 4g Kotlin daemon). CI workflows override via `GRADLE_OPTS` env var to fit the 7GB RAM budget of standard runners: `-Xmx4g` Gradle heap, `-Xmx2g` Kotlin daemon, VFS watching disabled, workers capped at 4. +- **KMP Smoke Compile:** Use `./gradlew kmpSmokeCompile` instead of listing individual module compile tasks. The `kmpSmokeCompile` lifecycle task (registered in `RootConventionPlugin`) auto-discovers all KMP modules and depends on their `compileKotlinJvm` + `compileKotlinIosSimulatorArm64` tasks. +- **`mavenLocal()` gated:** The `mavenLocal()` repository is disabled by default to prevent CI cache poisoning. For local JitPack testing, pass `-PuseMavenLocal` to Gradle. - **Terminal Pagers:** When running shell commands like `git diff` or `git log`, ALWAYS use `--no-pager` (e.g., `git --no-pager diff`) to prevent the agent from getting stuck in an interactive prompt. - **Text Search:** Prefer using `rg` (ripgrep) over `grep` or `find` for fast text searching across the codebase. diff --git a/GEMINI.md b/GEMINI.md index dd60dc47b..2dede594d 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -135,6 +135,13 @@ Always run commands in the following order to ensure reliability. Do not attempt - 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. +- **Runner strategy (three tiers):** + - **`ubuntu-24.04-arm`** — Lightweight/utility jobs (status checks, labelers, triage, changelog, release metadata, stale, moderation). These run only shell scripts or GitHub API calls and benefit from ARM runners' shorter queue times. + - **`ubuntu-24.04`** — Gradle-heavy jobs (CI host-check, android-check, release builds, Dokka, CodeQL, publish, dependency-submission). Pinned for reproducibility; avoid `ubuntu-latest` to prevent breakage when GitHub rolls the alias forward. + - **Desktop release matrix** — `[macos-latest, windows-latest, ubuntu-24.04, ubuntu-24.04-arm]` for cross-platform native packaging (DMG, MSI, deb/rpm/AppImage for x64 and ARM). +- **CI JVM tuning:** `gradle.properties` is tuned for local dev (8g heap, 4g Kotlin daemon). CI workflows override via `GRADLE_OPTS` env var to fit the 7GB RAM budget of standard runners: `-Xmx4g` Gradle heap, `-Xmx2g` Kotlin daemon, VFS watching disabled, workers capped at 4. +- **KMP Smoke Compile:** Use `./gradlew kmpSmokeCompile` instead of listing individual module compile tasks. The `kmpSmokeCompile` lifecycle task (registered in `RootConventionPlugin`) auto-discovers all KMP modules and depends on their `compileKotlinJvm` + `compileKotlinIosSimulatorArm64` tasks. +- **`mavenLocal()` gated:** The `mavenLocal()` repository is disabled by default to prevent CI cache poisoning. For local JitPack testing, pass `-PuseMavenLocal` to Gradle. - **Terminal Pagers:** When running shell commands like `git diff` or `git log`, ALWAYS use `--no-pager` (e.g., `git --no-pager diff`) to prevent the agent from getting stuck in an interactive prompt. - **Text Search:** Prefer using `rg` (ripgrep) over `grep` or `find` for fast text searching across the codebase. diff --git a/build-logic/convention/src/main/kotlin/RootConventionPlugin.kt b/build-logic/convention/src/main/kotlin/RootConventionPlugin.kt index 4f027414b..86abc2a11 100644 --- a/build-logic/convention/src/main/kotlin/RootConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/RootConventionPlugin.kt @@ -35,6 +35,28 @@ class RootConventionPlugin : Plugin { configureKoverAggregation() subprojects { configureGraphTasks() } + + registerKmpSmokeCompileTask() + } + } +} + +/** + * Registers a `kmpSmokeCompile` lifecycle task that auto-discovers all KMP modules + * and depends on their `compileKotlinJvm` and `compileKotlinIosSimulatorArm64` tasks. + * + * This replaces the long explicit task list in CI, auto-maintaining as modules are added. + */ +private fun Project.registerKmpSmokeCompileTask() { + tasks.register("kmpSmokeCompile") { + group = "verification" + description = "Compile all KMP modules for JVM and iOS Simulator ARM64 targets." + + subprojects.forEach { sub -> + sub.pluginManager.withPlugin("org.jetbrains.kotlin.multiplatform") { + dependsOn(sub.tasks.matching { it.name == "compileKotlinJvm" }) + dependsOn(sub.tasks.matching { it.name == "compileKotlinIosSimulatorArm64" }) + } } } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 22a9f8eb1..2c6074786 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -67,7 +67,8 @@ pluginManagement { dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { - mavenLocal() + // Only enable mavenLocal for local JitPack testing; never in CI. + if (providers.gradleProperty("useMavenLocal").isPresent) mavenLocal() google() mavenCentral() maven {