mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-07-09 21:05:24 -04:00
ci: merge-queue contention fixes, desktop builds on main, and 22.04-runner exit for desktop releases (#6174)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
15
.github/workflows/main-check.yml
vendored
15
.github/workflows/main-check.yml
vendored
@@ -15,12 +15,20 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Every commit on main arrives via the merge queue, which already ran lint, tests,
|
||||
# screenshot validation, and rb-check on this exact merge commit. Re-running them here
|
||||
# would be pure duplication — this workflow builds the debug APKs for the snapshot
|
||||
# release below (run_lint: false also skips screenshot-check and rb-check) plus the
|
||||
# desktop distributables. Desktop packaging runs here post-merge rather than in the
|
||||
# merge queue: :desktopApp:test in the queue's shard-app already covers compilation,
|
||||
# and the 4-OS matrix (macos/windows queue times) would slow every merge.
|
||||
validate-and-build:
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android'
|
||||
uses: ./.github/workflows/reusable-check.yml
|
||||
with:
|
||||
run_lint: true
|
||||
run_lint: false
|
||||
run_unit_tests: false
|
||||
run_desktop_builds: true
|
||||
upload_artifacts: true
|
||||
secrets: inherit
|
||||
|
||||
@@ -30,7 +38,10 @@ jobs:
|
||||
# expire after 7 days).
|
||||
publish-snapshot:
|
||||
needs: validate-and-build
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android'
|
||||
# !cancelled(): a desktop-matrix failure fails validate-and-build as a whole, but the
|
||||
# Android APKs may still have built fine — attempt the snapshot regardless. If the
|
||||
# APK build itself failed, the artifact download below fails and this job goes red.
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android' && !cancelled()
|
||||
runs-on: ubuntu-24.04-arm
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
70
.github/workflows/merge-queue.yml
vendored
70
.github/workflows/merge-queue.yml
vendored
@@ -7,13 +7,74 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Note: github.ref is unique per merge-group entry (gh-readonly-queue/main/pr-N-<sha>),
|
||||
# so this group never dedupes across re-queues of the same PR — the cancel-superseded
|
||||
# job below handles that explicitly.
|
||||
concurrency:
|
||||
group: build-mq-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
android-check:
|
||||
# When a PR is re-queued (an entry ahead of it failed or was removed), GitHub creates a
|
||||
# new merge group but does NOT cancel the workflow runs of the destroyed one. Those stale
|
||||
# runs sit queued/running and starve the runner pool. Cancel any older merge-queue run
|
||||
# for the same PR — only the newest merge group per PR is ever valid.
|
||||
cancel-superseded:
|
||||
name: Cancel Superseded Queue Runs
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android'
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- name: Cancel older merge-queue runs for the same PR
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
# github.ref_name: gh-readonly-queue/main/pr-<num>-<base-sha>
|
||||
PR_PREFIX=$(echo "${{ github.ref_name }}" | grep -oE 'gh-readonly-queue/.+/pr-[0-9]+-')
|
||||
if [ -z "$PR_PREFIX" ]; then
|
||||
echo "Could not parse PR from ref '${{ github.ref_name }}'; skipping."
|
||||
exit 0
|
||||
fi
|
||||
for status in queued in_progress; do
|
||||
gh api "repos/${{ github.repository }}/actions/runs?event=merge_group&status=${status}&per_page=100" \
|
||||
--jq ".workflow_runs[] | select(.head_branch | startswith(\"$PR_PREFIX\")) | select(.id < ${{ github.run_id }}) | .id"
|
||||
done | sort -u | while read -r run_id; do
|
||||
echo "Cancelling superseded run $run_id"
|
||||
gh run cancel "$run_id" --repo "${{ github.repository }}" || true
|
||||
done
|
||||
|
||||
# Docs-only queue entries (changelog updates, markdown fixes) cannot affect the build;
|
||||
# skip the heavy pipeline for them. Anything outside docs/ and *.md runs full CI.
|
||||
# Mirrors the paths-ignore list in main-check.yml.
|
||||
check-changes:
|
||||
name: Check Changes
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android'
|
||||
runs-on: ubuntu-24.04-arm
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
android: ${{ steps.filter.outputs.android }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7.0.0
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Diff merge group against its base
|
||||
id: filter
|
||||
run: |
|
||||
git fetch --depth=1 origin "${{ github.event.merge_group.base_sha }}"
|
||||
changed=$(git diff --name-only "${{ github.event.merge_group.base_sha }}" "${{ github.event.merge_group.head_sha }}")
|
||||
echo "Changed files:"
|
||||
echo "$changed"
|
||||
if echo "$changed" | grep -qvE '^docs/|\.md$|^$'; then
|
||||
echo "android=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "android=false" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
android-check:
|
||||
needs: check-changes
|
||||
if: github.repository == 'meshtastic/Meshtastic-Android' && needs.check-changes.outputs.android == 'true'
|
||||
uses: ./.github/workflows/reusable-check.yml
|
||||
with:
|
||||
run_lint: true
|
||||
@@ -27,12 +88,17 @@ jobs:
|
||||
timeout-minutes: 5
|
||||
permissions: {}
|
||||
needs:
|
||||
- check-changes
|
||||
- android-check
|
||||
if: always()
|
||||
steps:
|
||||
- name: Check Workflow Status
|
||||
run: |
|
||||
if [[ "${{ needs.android-check.result }}" == "failure" || "${{ needs.android-check.result }}" == "cancelled" ]]; then
|
||||
if [[ "${{ needs.check-changes.result }}" != "success" ]]; then
|
||||
echo "::error::Change detection failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.check-changes.outputs.android }}" == "true" && ("${{ needs.android-check.result }}" == "failure" || "${{ needs.android-check.result }}" == "cancelled") ]]; then
|
||||
echo "::error::Android Check failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
35
.github/workflows/release.yml
vendored
35
.github/workflows/release.yml
vendored
@@ -264,7 +264,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 }}
|
||||
@@ -286,7 +286,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies for AppImage
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y libfuse2
|
||||
run: sudo apt-get update && sudo apt-get install -y libfuse2t64
|
||||
|
||||
- name: Package Native Distributions
|
||||
env:
|
||||
@@ -308,6 +308,33 @@ jobs:
|
||||
${{ contains(runner.os, 'macOS') && ':desktopApp:packageReleaseUberJarForCurrentOS' || '' }}
|
||||
'-PaboutLibraries.release=true' --no-daemon
|
||||
|
||||
# jpackage computes the .deb Depends: line from the build host's package names.
|
||||
# Ubuntu 24.04 records time_t64 transition names (libasound2t64, libpng16-16t64)
|
||||
# that don't exist on Debian 12 Bookworm / Raspberry Pi OS, making the .deb
|
||||
# uninstallable there (#5233 pinned ubuntu-22.04 for this; those runners retire
|
||||
# 2027-04, brownouts from 2026-09). Strip the t64 suffix instead: Bookworm ships
|
||||
# the plain names, and on Trixie / Ubuntu 24.04+ the t64 packages Provide them.
|
||||
# Rewriting the control file is the only host-independent fix — jpackage's
|
||||
# --linux-package-deps is additive-only, and the Compose plugin clears its
|
||||
# --resource-dir during the task, so a custom control template can't be injected.
|
||||
- name: Rewrite t64 dependency names in .deb (Debian Bookworm / Pi OS compatibility)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
for deb in desktopApp/build/compose/binaries/main-release/deb/*.deb; do
|
||||
work=$(mktemp -d)
|
||||
dpkg-deb -R "$deb" "$work"
|
||||
echo "$(basename "$deb") before: $(grep '^Depends:' "$work/DEBIAN/control")"
|
||||
sed -i -E '/^(Depends|Pre-Depends|Recommends):/ s/(lib[a-z0-9.+-]*)t64([, (]|$)/\1\2/g' "$work/DEBIAN/control"
|
||||
echo "$(basename "$deb") after: $(grep '^Depends:' "$work/DEBIAN/control")"
|
||||
if grep -nE '^[A-Za-z-]+:.*\blib[a-z0-9.+-]*t64\b' "$work/DEBIAN/control"; then
|
||||
echo "::error::t64 dependency name survived rewrite in $(basename "$deb") — extend the sed above"
|
||||
exit 1
|
||||
fi
|
||||
dpkg-deb -b --root-owner-group "$work" "$deb"
|
||||
rm -rf "$work"
|
||||
done
|
||||
|
||||
- name: List Desktop Binaries
|
||||
if: runner.os == 'Linux' || runner.os == 'macOS'
|
||||
run: ls -R desktopApp/build/compose/binaries/main-release
|
||||
@@ -348,7 +375,9 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-22.04-arm]
|
||||
# No .deb host-coupling here (pure-Java uber jar + URL manifest) — free to track
|
||||
# the current LTS image.
|
||||
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
||||
env:
|
||||
GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }}
|
||||
GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }}
|
||||
|
||||
14
.github/workflows/reusable-check.yml
vendored
14
.github/workflows/reusable-check.yml
vendored
@@ -12,6 +12,9 @@ on:
|
||||
run_coverage:
|
||||
type: boolean
|
||||
default: true
|
||||
run_desktop_builds:
|
||||
type: boolean
|
||||
default: false
|
||||
run_desktop_flatpak_src:
|
||||
type: boolean
|
||||
default: false
|
||||
@@ -93,6 +96,7 @@ jobs:
|
||||
contents: read
|
||||
timeout-minutes: 30
|
||||
needs: setup
|
||||
if: inputs.run_lint == true
|
||||
env:
|
||||
VERSION_CODE: ${{ needs.setup.outputs.version_code }}
|
||||
|
||||
@@ -112,13 +116,8 @@ jobs:
|
||||
install_jetbrains_jdk: 'true'
|
||||
|
||||
- name: Lint, Analysis & KMP Smoke Compile
|
||||
if: inputs.run_lint == true
|
||||
run: ./gradlew spotlessCheck detekt androidApp:lintFdroidDebug androidApp:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug kmpSmokeCompile -Pci=true --continue
|
||||
|
||||
- name: KMP Smoke Compile (lint skipped)
|
||||
if: inputs.run_lint == false
|
||||
run: ./gradlew kmpSmokeCompile -Pci=true --continue
|
||||
|
||||
# ── Screenshot Test Validation ──────────────────────────────────────
|
||||
screenshot-check:
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -156,13 +155,14 @@ jobs:
|
||||
if-no-files-found: warn
|
||||
|
||||
# ── Reproducible Build Verification ─────────────────────────────────
|
||||
# Only runs on main push and merge-queue (not PRs) to keep PR feedback fast.
|
||||
# Only runs in the merge queue (not PRs, to keep PR feedback fast; not main pushes,
|
||||
# which are the same merge commit the queue just verified).
|
||||
rb-check:
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
timeout-minutes: 30
|
||||
if: inputs.run_lint == true && (github.event_name == 'push' || github.event_name == 'merge_group')
|
||||
if: inputs.run_lint == true && github.event_name == 'merge_group'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
||||
5
.github/workflows/verify-flatpak.yml
vendored
5
.github/workflows/verify-flatpak.yml
vendored
@@ -8,6 +8,11 @@ on:
|
||||
- 'build.gradle.kts'
|
||||
- 'settings.gradle.kts'
|
||||
- '.github/workflows/verify-flatpak.yml'
|
||||
# The desktop module's build config shapes the uber jar the flatpak wraps.
|
||||
- 'desktopApp/**'
|
||||
# The offline manifest pins the Gradle distribution independently of the wrapper —
|
||||
# a wrapper bump without a manifest update breaks the offline build silently.
|
||||
- 'gradle/wrapper/**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
||||
@@ -131,6 +131,7 @@ CI is defined in `.github/workflows/reusable-check.yml` and structured as parall
|
||||
- **`fail-fast: false`:** Test sharding does not cancel other shards on failure.
|
||||
- **Explicit Gradle task paths:** Prefer `app:lintFdroidDebug` over shorthand `lintDebug` in CI.
|
||||
- **Pull request CI:** Main-only (`.github/workflows/pull-request.yml` targets `main`).
|
||||
- **Merge queue hygiene:** `merge-queue.yml` cancels superseded runs for the same PR (GitHub does not auto-cancel destroyed merge-group runs) and skips the heavy pipeline for docs-only entries (`docs/**`, `*.md`). `rb-check` runs ONLY in the merge queue. `main-check.yml` passes `run_lint: false` — every main commit is a merge-queue-verified merge commit, so main pushes only rebuild the debug APKs for the snapshot release.
|
||||
- **Cache writes:** Trusted on `main` and merge queue runs; other refs use read-only cache.
|
||||
- **Path filtering:** `check-changes` in `pull-request.yml` must include module dirs plus build/workflow entrypoints (`build-logic/**`, `gradle/**`, `.github/workflows/**`, `gradlew`, `settings.gradle.kts`, etc.).
|
||||
- **AboutLibraries:** Runs in `offlineMode` by default (no GitHub/SPDX API calls). Release builds pass `-PaboutLibraries.release=true` via Fastlane/Gradle CLI to enable remote license fetching. Do NOT re-gate on `CI` or `GITHUB_TOKEN` alone.
|
||||
|
||||
Reference in New Issue
Block a user