From 86ddb87f54cefa76e9378d9ba8ea3cedc695d8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Martin?= Date: Tue, 6 Oct 2026 14:19:56 +0200 Subject: [PATCH] CI: a push runs the tests, a pull request also builds the firmware Rebuilding both firmwares on every push was more than anyone looked at. A push now runs the host tests with their coverage (under two minutes); a pull request adds the release firmware and the Debug Build, and is how changes reach main; a tag still does everything before it releases. Pull requests from forks don't run. scripts/ci.sh takes 'tests' or 'builds' for one half; coverage.sh now fails when a test fails. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT --- .gitea/workflows/ci.yml | 26 +++++++++++++++----------- README.md | 2 +- docs/milestones/R1.md | 2 +- scripts/ci.sh | 9 ++++++++- scripts/coverage.sh | 4 ++-- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 2ee7dce..1cf942d 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,7 +1,8 @@ # CI and releases (docs/milestones/R1.md). -# Any push: host tests, the release firmware and the Debug Build, then the tests' -# coverage of lib/; on main, its badge is published to the branch `badges`. -# A tag v*: the same, then a Gitea release with the signed Update File. +# A push: the host tests, with their coverage of lib/. On main, the README's badges +# are published to the branch `badges`. +# A pull request: the same, then the release firmware and the Debug Build. +# A tag v*: all of it, then a Gitea release with the signed Update File. # Run by hand: the release of a tag that exists already (the ones from before CI). # # The job runs in a plain Python image, as scripts/ci.sh does on a developer's machine, with the @@ -10,8 +11,9 @@ name: CI on: push: - branches: ['**', '!badges'] # badges holds what CI itself publishes: the coverage badge + branches: ['**', '!badges'] # badges holds what CI itself publishes tags: ['v*'] + pull_request: workflow_dispatch: inputs: tag: @@ -21,6 +23,8 @@ on: jobs: build: runs-on: ubuntu + # A pull request from a fork would run someone else's code on our runner: not without us (Q154). + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository container: image: python:3.12-slim volumes: @@ -42,18 +46,18 @@ jobs: git config --global --add safe.directory '*' git init -q . git remote add origin "${{ github.server_url }}/${{ github.repository }}.git" - git fetch -q --tags origin '+refs/heads/*:refs/remotes/origin/*' + git fetch -q --tags origin '+refs/heads/*:refs/remotes/origin/*' '+refs/pull/*/head:refs/remotes/pull/*' git checkout -q --detach "${{ github.sha }}" git describe --tags --always - - name: Host tests and both builds - if: github.event_name == 'push' - run: scripts/ci.sh - - - name: Coverage of lib/ by the host tests - if: github.event_name == 'push' + - name: Host tests, and their coverage of lib/ + if: github.event_name != 'workflow_dispatch' run: scripts/coverage.sh + - name: The release firmware and the Debug Build + if: github.event_name == 'pull_request' || github.ref_type == 'tag' + run: scripts/ci.sh builds + # The README's badges are files on a branch of their own, replaced at each push to main. - name: Publish the badges if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/coverage') diff --git a/README.md b/README.md index dd52b03..3f28204 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ The framework is rebuilt with the TLS settings in `platformio.ini` (`custom_sdkc ## CI and releases -Gitea Actions runs the same thing on every push (`.gitea/workflows/ci.yml`, docs/milestones/R1.md). Pushing a tag `v*` also publishes a release on Gitea with: +Gitea Actions (`.gitea/workflows/ci.yml`, docs/milestones/R1.md) runs the host tests on every push, and on a pull request also builds the release firmware and the Debug Build: changes reach `main` through pull requests. Pushing a tag `v*` runs all of it and publishes a release on Gitea with: - `roro9stack-.ota`, the signed Update File; - `roro9stack--factory.bin`, the whole flash image for a first install over USB; diff --git a/docs/milestones/R1.md b/docs/milestones/R1.md index 9447cf7..c01b7a5 100644 --- a/docs/milestones/R1.md +++ b/docs/milestones/R1.md @@ -12,7 +12,7 @@ Until now the tests, the builds, the signing and the flashing all happened on on | # | Decision | |---|---| -| Q151 | Every push, to any branch: the host tests and both builds. A tag `v*`: the same, then a release. | +| Q151 | A push, to any branch: the host tests (with their coverage). A pull request: the same and both builds; changes reach `main` through pull requests. A tag `v*`: all of it, then a release. (First: everything on every push, which rebuilt the firmware far more often than anyone looked at it.) | | Q152 | **CI signs.** The signing key is the repository secret `OTA_SIGNING_KEY`; a tag push makes a complete, signed release with no manual step (ADR 0008). | | Q153 | The Debug Build is built in CI with a token of the runner's own, to prove it compiles, and **isn't published**: it would hand everyone its Debug Console token. | | Q154 | Pull requests from forks don't start a run. | diff --git a/scripts/ci.sh b/scripts/ci.sh index 4f289b7..34ea0b1 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -1,7 +1,14 @@ #!/usr/bin/env bash # Local CI: run host unit tests, then build the firmware. +# Usage: scripts/ci.sh [tests|builds] one half only; both by default set -euo pipefail source "$(dirname "$0")/_docker.sh" DOCKER_EXTRA=() -run_in_container bash -c 'git config --global --add safe.directory "$PWD" && pio test -e native && pio run -e cardputer-adv -e cardputer-adv-debug' +case "${1:-all}" in + tests) STEPS='pio test -e native' ;; + builds) STEPS='pio run -e cardputer-adv -e cardputer-adv-debug' ;; + all) STEPS='pio test -e native && pio run -e cardputer-adv -e cardputer-adv-debug' ;; + *) echo "Usage: scripts/ci.sh [tests|builds]" >&2; exit 1 ;; +esac +run_in_container bash -c 'git config --global --add safe.directory "$PWD" && '"$STEPS" diff --git a/scripts/coverage.sh b/scripts/coverage.sh index 40c7a97..01ab695 100755 --- a/scripts/coverage.sh +++ b/scripts/coverage.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# How much of lib/ the host tests run: builds them with coverage counters, runs them, and reports. +# Runs the host tests and says how much of lib/ they run: they're built with coverage counters. # Usage: scripts/coverage.sh [out folder, default .pio/coverage] # Out: summary.json (gcovr), coverage.svg (the README's badge), index.html (line by line). # What it measures: the lines of lib/ that compile on a PC. Not lib/SD (the card's driver) and not @@ -10,7 +10,7 @@ DOCKER_EXTRA=() OUT="${1:-.pio/coverage}" run_in_container bash -c ' - set -e + set -eo pipefail # a failing test fails this script, tail or not git config --global --add safe.directory "$PWD" rm -rf .pio/build/native-coverage "'"$OUT"'" mkdir -p "'"$OUT"'"