chore(ci): reap closed-PR runs, add missing timeouts and concurrency guards (#6406)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
James RichandClaude Fable 5 authored and GitHub committed 2026-07-24 16:27:38 +00:00
1 parent 84aae4b589
commit dc4a7345f5
15 files changed
+108

No files matched your search

@@ -28,9 +28,16 @@ permissions:
id-token: write
attestations: write
# Never allow two release pipelines to run at once — they race on tags,
# release objects, and Play track state. Later dispatches queue.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
determine-tags:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
outputs:
tag_to_process: ${{ steps.calculate_tags.outputs.tag_to_process }}
release_name: ${{ steps.calculate_tags.outputs.release_name }}
@@ -158,6 +165,7 @@ jobs:
needs: [determine-tags, call-release-workflow]
if: ${{ (failure() || cancelled()) && !inputs.dry_run && inputs.channel == 'internal' }}
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v7.0.1
+2
View File
@@ -33,6 +33,7 @@ jobs:
build:
if: github.repository == 'meshtastic/Meshtastic-Android'
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
@@ -82,6 +83,7 @@ jobs:
if: github.repository == 'meshtastic/Meshtastic-Android'
needs: build
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
+2
View File
@@ -19,6 +19,7 @@ jobs:
build:
if: github.repository == 'meshtastic/Meshtastic-Android'
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
@@ -101,6 +102,7 @@ jobs:
if: github.repository == 'meshtastic/Meshtastic-Android'
needs: build
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
+1
View File
@@ -50,6 +50,7 @@ jobs:
# 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
timeout-minutes: 10
permissions:
contents: write
env:
+7
View File
@@ -26,12 +26,19 @@ on:
permissions:
contents: read
# Partner Center submissions must never race (a release event overlapping a
# manual retry would collide on the same in-progress submission). Serialize.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
msstore:
# Belt and braces for release events — `released` should already exclude
# these. workflow_dispatch has no release payload and passes through.
if: ${{ !github.event.release.prerelease && !github.event.release.draft }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
# Secrets aren't readable in step `if:` expressions; skip cleanly until
# Partner Center is configured. Presence is gated on PRODUCT_ID alone so
@@ -16,9 +16,16 @@ on:
permissions:
contents: write
# Destructive (deletes releases + tags): serialize dispatches so two cleanups
# can never interleave.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
cleanup_prereleases:
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7.0.1
+42
View File
@@ -0,0 +1,42 @@
name: PR Closed Cleanup
# When a PR is closed (merged or abandoned) its in-flight CI runs keep burning
# runner slots to completion: per-PR concurrency groups only cancel on a NEW
# push, and nothing pushes to a closed PR. Reap queued/in-progress
# pull_request-event runs for the closed PR's head SHA (pull-request.yml,
# verify-flatpak.yml, ...). Runs for older SHAs were already cancelled by the
# per-PR concurrency group when that SHA was superseded.
#
# pull_request_target is required: the plain pull_request event gets a
# read-only GITHUB_TOKEN for fork PRs, which cannot cancel runs. Per the
# pull_request_target warnings, this workflow must never check out or execute
# PR code — it only calls the Actions API.
on:
pull_request_target:
types: [closed]
permissions:
actions: write
jobs:
cancel-pr-runs:
if: github.repository == 'meshtastic/Meshtastic-Android'
runs-on: ubuntu-24.04-arm
timeout-minutes: 5
steps:
- name: Cancel in-flight CI runs for the closed PR
env:
GH_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
ids_file="$(mktemp)"
trap 'rm -f "$ids_file"' EXIT
for status in queued in_progress; do
gh api --paginate "repos/${{ github.repository }}/actions/runs?event=pull_request&status=${status}&head_sha=${HEAD_SHA}&per_page=100" \
--jq '.workflow_runs[].id'
done >"$ids_file"
sort -u "$ids_file" | while read -r run_id; do
echo "Cancelling run $run_id"
gh run cancel "$run_id" --repo "${{ github.repository }}" || true
done
+4
View File
@@ -69,6 +69,7 @@ permissions:
jobs:
prepare-build-info:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
outputs:
APP_VERSION_NAME: ${{ steps.prep_version.outputs.APP_VERSION_NAME }}
APP_VERSION_CODE: ${{ steps.calculate_version_code.outputs.versionCode }}
@@ -106,6 +107,7 @@ jobs:
promote-release:
runs-on: ubuntu-24.04-arm
timeout-minutes: 30
needs: [ prepare-build-info ]
env:
FROM_TRACK: ${{ inputs.from_channel == 'closed' && 'NewAlpha' || (inputs.from_channel == 'open' && 'beta' || 'internal') }}
@@ -144,6 +146,7 @@ jobs:
update-github-release:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
needs: [ prepare-build-info, promote-release ]
# actions: write is scoped here — only this job's publish-workflow
# dispatch needs it, and the other jobs must not get it. Job-level
@@ -345,6 +348,7 @@ jobs:
update-homebrew-cask:
if: ${{ inputs.channel == 'production' }}
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs: [ update-github-release ]
steps:
- name: Checkout code
@@ -15,6 +15,7 @@ jobs:
contents: read
pull-requests: write
runs-on: ubuntu-24.04-arm
timeout-minutes: 5
steps:
- name: Auto-label PR
uses: actions/github-script@v9
+7
View File
@@ -90,6 +90,7 @@ permissions:
jobs:
prepare-build-info:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
outputs:
APP_VERSION_NAME: ${{ steps.prep_version.outputs.APP_VERSION_NAME }}
APP_VERSION_CODE: ${{ steps.calculate_version_code.outputs.versionCode }}
@@ -130,6 +131,7 @@ jobs:
release-google:
runs-on: ubuntu-24.04
timeout-minutes: 90
needs: [prepare-build-info]
env:
GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }}
@@ -214,6 +216,7 @@ jobs:
release-fdroid:
runs-on: ubuntu-24.04
timeout-minutes: 90
needs: [prepare-build-info]
env:
GRADLE_CACHE_URL: ${{ secrets.GRADLE_CACHE_URL }}
@@ -274,6 +277,7 @@ jobs:
release-desktop:
if: ${{ inputs.build_desktop }}
runs-on: ${{ matrix.os }}
timeout-minutes: 90
needs: [prepare-build-info]
strategy:
fail-fast: false
@@ -431,6 +435,7 @@ jobs:
create-flatpak-src:
if: ${{ inputs.build_flatpak_src }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
needs: [prepare-build-info]
strategy:
fail-fast: false
@@ -487,6 +492,7 @@ jobs:
release-flatpak-src:
if: ${{ inputs.build_flatpak_src }}
runs-on: ubuntu-24.04
timeout-minutes: 30
needs: [create-flatpak-src]
steps:
- name: Download Flatpak source artifacts
@@ -524,6 +530,7 @@ jobs:
github-release:
if: ${{ !cancelled() && !failure() }}
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
needs:
- prepare-build-info
- release-google
+7
View File
@@ -8,9 +8,16 @@ on:
- cron: '0 0 * * *'
workflow_dispatch: # Allow manual triggering
# Emulator runs take up to ~1 h; a manual dispatch overlapping the daily cron
# would race on the scheduled-baseline branch. Later runs queue, never stack.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
regenerate:
runs-on: ubuntu-24.04
timeout-minutes: 90
if: github.repository == 'meshtastic/Meshtastic-Android'
permissions:
contents: write # To commit files and push branches
+7
View File
@@ -7,9 +7,16 @@ on:
- cron: '0 * * * *'
workflow_dispatch: # Allow manual triggering
# Hourly cron + manual dispatch must never stack: overlapping runs race on the
# scheduled-updates branch force-push. Later runs queue (at most one pending).
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
update_assets:
runs-on: ubuntu-24.04
timeout-minutes: 30
if: github.repository == 'meshtastic/Meshtastic-Android'
permissions:
contents: write # To commit files and push branches
+5
View File
@@ -8,10 +8,15 @@ permissions:
issues: write
pull-requests: write
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
stale_issues:
name: Close Stale Issues
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
if: github.repository == 'meshtastic/Meshtastic-Android'
steps:
+1
View File
@@ -19,6 +19,7 @@ concurrency:
jobs:
update-changelog:
runs-on: ubuntu-24.04-arm
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7.0.1
+7
View File
@@ -25,12 +25,19 @@ on:
# nothing in this repo is written.
permissions: {}
# Serialize submissions: a release event overlapping a manual retry would open
# duplicate winget-pkgs PRs for the same version.
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
jobs:
winget:
# Belt and braces for release events — `released` should already exclude
# these. workflow_dispatch has no release payload and passes through.
if: ${{ !github.event.release.prerelease && !github.event.release.draft }}
runs-on: ubuntu-latest
timeout-minutes: 30
env:
# Secrets aren't readable in step `if:` expressions; skip cleanly until
# the token is configured.