From 5866428f693ffedf2d30daf232313eece09b5a74 Mon Sep 17 00:00:00 2001 From: Louis King Date: Sun, 14 Jun 2026 22:16:57 +0100 Subject: [PATCH] chore(ci): optimise GitHub workflows Add concurrency (PR-cancel only), dependency caching, timeouts, and path filters across all four workflows. Pin opencode action to v1.17.7 and tighten the /oc trigger. Skip MQTT broker rebuild when upstream SHA is unchanged. Gate sdist/wheel build job to main-only pushes. --- .github/workflows/ci.yml | 28 ++++++++++++- .github/workflows/docker-mqtt-broker.yml | 53 ++++++++++++++++++++++-- .github/workflows/docker.yml | 14 +++++-- .github/workflows/opencode.yml | 21 +++++++--- 4 files changed, 104 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54e96ec..e8672fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,13 +3,33 @@ name: CI on: push: branches: [main] + paths-ignore: + - "**/*.md" + - "docs/**" + - ".env.example" + - "LICENSE" + - "FUNDING.yml" pull_request: branches: [main] + paths-ignore: + - "**/*.md" + - "docs/**" + - ".env.example" + - "LICENSE" + - "FUNDING.yml" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: lint: name: Lint runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -17,6 +37,7 @@ jobs: uses: actions/setup-python@v6 with: python-version-file: ".python-version" + cache: pip - name: Run pre-commit uses: pre-commit/action@v3.0.1 @@ -24,6 +45,7 @@ jobs: test: name: Test runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v6 @@ -31,6 +53,7 @@ jobs: uses: actions/setup-python@v6 with: python-version-file: ".python-version" + cache: pip - name: Install dependencies run: | @@ -39,7 +62,7 @@ jobs: - name: Run tests with pytest run: | - pytest --cov=meshcore_hub --cov-report=xml --cov-report=term-missing --junitxml=junit.xml -o junit_family=legacy + pytest -nauto --cov=meshcore_hub --cov-report=xml --cov-report=term-missing --junitxml=junit.xml -o junit_family=legacy - name: Upload coverage to Codecov uses: codecov/codecov-action@v7 @@ -60,7 +83,9 @@ jobs: build: name: Build Package runs-on: ubuntu-latest + timeout-minutes: 15 needs: [lint, test] + if: github.event_name == 'push' steps: - uses: actions/checkout@v6 @@ -68,6 +93,7 @@ jobs: uses: actions/setup-python@v6 with: python-version-file: ".python-version" + cache: pip - name: Install build tools run: | diff --git a/.github/workflows/docker-mqtt-broker.yml b/.github/workflows/docker-mqtt-broker.yml index 0a98a4a..d6779b9 100644 --- a/.github/workflows/docker-mqtt-broker.yml +++ b/.github/workflows/docker-mqtt-broker.yml @@ -15,38 +15,79 @@ env: UPSTREAM_REPO: michaelhart/meshcore-mqtt-broker IMAGE_NAME: ipnet-mesh/meshcore-mqtt-broker +permissions: + contents: read + packages: write + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + jobs: build: name: Build and Push MQTT Broker runs-on: ubuntu-latest - permissions: - contents: read - packages: write + timeout-minutes: 60 steps: + - name: Check upstream for new commits + id: check + run: | + set -euo pipefail + UPSTREAM_SHA="$(git ls-remote "https://github.com/${UPSTREAM_REPO}.git" "refs/heads/${{ inputs.ref || 'main' }}" | awk '{print $1}')" + if [ -z "${UPSTREAM_SHA}" ]; then + UPSTREAM_SHA="$(git ls-remote "https://github.com/${UPSTREAM_REPO}.git" "${{ inputs.ref || 'main' }}" | awk '{print $1}')" + fi + echo "upstream_sha=${UPSTREAM_SHA}" >> "$GITHUB_OUTPUT" + echo "Latest upstream SHA: ${UPSTREAM_SHA}" + + - name: Cache last-built upstream SHA + id: cache + uses: actions/cache@v4 + with: + path: .last-upstream-sha + key: mqtt-broker-upstream-${{ steps.check.outputs.upstream_sha }} + + - name: Decide whether to build + id: decide + if: steps.cache.outputs.cache-hit != 'true' + run: echo "changed=true" >> "$GITHUB_OUTPUT" + + - name: Persist upstream SHA for cache write + if: steps.decide.outputs.changed == 'true' + run: echo "${{ steps.check.outputs.upstream_sha }}" > .last-upstream-sha + - name: Checkout this repo (sparse) + if: steps.decide.outputs.changed == 'true' uses: actions/checkout@v6 with: + persist-credentials: false sparse-checkout: | etc/docker/meshcore-mqtt-broker - name: Checkout upstream source + if: steps.decide.outputs.changed == 'true' uses: actions/checkout@v6 with: + persist-credentials: false repository: ${{ env.UPSTREAM_REPO }} ref: ${{ inputs.ref || 'main' }} path: upstream - name: Copy Dockerfile into upstream source + if: steps.decide.outputs.changed == 'true' run: cp etc/docker/meshcore-mqtt-broker/Dockerfile upstream/Dockerfile - name: Set up QEMU + if: steps.decide.outputs.changed == 'true' uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx + if: steps.decide.outputs.changed == 'true' uses: docker/setup-buildx-action@v4 - name: Log in to Container Registry + if: steps.decide.outputs.changed == 'true' uses: docker/login-action@v4 with: registry: ${{ env.REGISTRY }} @@ -54,6 +95,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata + if: steps.decide.outputs.changed == 'true' id: meta uses: docker/metadata-action@v6 with: @@ -63,6 +105,7 @@ jobs: type=sha - name: Build and push Docker image + if: steps.decide.outputs.changed == 'true' uses: docker/build-push-action@v7 with: context: ./upstream @@ -73,3 +116,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + + - name: Skip build (unchanged) + if: steps.decide.outputs.changed != 'true' + run: echo "Upstream ${{ steps.check.outputs.upstream_sha }} already built; skipping." diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6290c7e..3c6fcf0 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,16 +10,24 @@ env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} +permissions: + contents: read + packages: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: build: name: Build Docker Image runs-on: ubuntu-latest - permissions: - contents: read - packages: write + timeout-minutes: 60 steps: - uses: actions/checkout@v6 + with: + persist-credentials: false - name: Set up QEMU uses: docker/setup-qemu-action@v4 diff --git a/.github/workflows/opencode.yml b/.github/workflows/opencode.yml index ef97dae..024f549 100644 --- a/.github/workflows/opencode.yml +++ b/.github/workflows/opencode.yml @@ -6,17 +6,28 @@ on: pull_request_review_comment: types: [created] +permissions: + contents: read + pull-requests: read + issues: read + id-token: write + +concurrency: + group: opencode-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }} + cancel-in-progress: false + jobs: opencode: if: | (contains(github.event.comment.author_association, 'OWNER') || contains(github.event.comment.author_association, 'MEMBER') || contains(github.event.comment.author_association, 'COLLABORATOR')) && - (contains(github.event.comment.body, ' /oc') || - startsWith(github.event.comment.body, '/oc') || - contains(github.event.comment.body, ' /opencode') || - startsWith(github.event.comment.body, '/opencode')) + (startsWith(github.event.comment.body, '/oc') || + contains(github.event.comment.body, '\n/oc') || + startsWith(github.event.comment.body, '/opencode') || + contains(github.event.comment.body, '\n/opencode')) runs-on: ubuntu-latest + timeout-minutes: 30 permissions: id-token: write contents: read @@ -29,7 +40,7 @@ jobs: persist-credentials: false - name: Run opencode - uses: anomalyco/opencode/github@latest + uses: anomalyco/opencode/github@v1.17.7 env: ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }} with: