Public Access
CI / build (push) Successful in 1m6s
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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
42 lines
4.4 KiB
Markdown
42 lines
4.4 KiB
Markdown
# R1 — Releases
|
|
|
|
**Status:** in progress. CI and signed releases on Gitea (issue #5) are in place since 2026-10-06: every tag from v0.1.0 to v0.10.0 has its release. Next: updates from Gitea (#6), which waited for this, and the Issues App (#4).
|
|
|
|
**Goal:** a tag is a release, built the same way every time and published where a device can find it.
|
|
|
|
## CI and releases (issue #5)
|
|
|
|
Until now the tests, the builds, the signing and the flashing all happened on one machine, through `scripts/ci.sh` and `scripts/flash.sh`. Nothing was published.
|
|
|
|
### Decisions (design round 2026-10-06)
|
|
|
|
| # | Decision |
|
|
|---|---|
|
|
| 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. |
|
|
| Q155 | A release carries `roro9stack-<version>.ota` (signed), `-factory.bin` for USB, `.elf.gz` to decode crashes, and `SHA256SUMS`. |
|
|
| Q156 | Its text is the tag's message, what the files are, and the commits since the tag before. |
|
|
| Q157 | No cache service to begin with: measure first. |
|
|
| Q158 | Reproducible builds aren't needed for signing any more (Q152); not pursued here. |
|
|
| Q159 | **The tags from before CI get their releases too**, v0.1.0 to v0.10.0, built from each tag's own sources by running the workflow by hand. |
|
|
| Q160 | Actions is switched on for the repository. |
|
|
|
|
### As built
|
|
|
|
- **One workflow, `.gitea/workflows/ci.yml`, one job**, on the runner `runner0` (label `ubuntu`). The job asks for a `python:3.12-slim` container, installs git, a compiler, openssl and PlatformIO, and runs the same scripts as a developer's machine. No Docker inside the job.
|
|
- **The cache is a Docker volume**, `roro9stack-pio`, mounted at `/pio`; the runner's `config.yaml` allows it under `container.valid_volumes`. A first run downloads about 1 GB and rebuilds the framework (17 minutes); with the volume filled, tests and both builds take about 6.
|
|
- **No JavaScript actions**, so the image needs no Node and nothing is fetched from GitHub: the checkout is four git commands.
|
|
- **`scripts/_docker.sh`** runs the command in place when `RORO_NO_DOCKER` is set (a CI job is already in a build container), and in the project's image otherwise. The Debug Build's token is made on the spot in CI and goes with the container.
|
|
- **`scripts/release_build.sh <checkout> <out>`** builds a tag's own sources with today's tools, signs, verifies against the public key in those sources, and writes the files and the release's text. **`scripts/release_publish.py`** creates the Gitea release or completes it; run twice, it replaces what's there. Both run the same on a developer's machine.
|
|
- **`scripts/ota_verify.py`** checks an Update File as a device does, on a PC.
|
|
- **The job's own token** (`secrets.GITEA_TOKEN`) is enough to create a release and upload its files.
|
|
- **Old tags.** v0.1.0 to v0.3.0 are from before the framework was rebuilt with our settings (ADR 0006) and can't link against a rebuilt one left in the cache: the release build puts the stock framework libraries back for them. v0.1.0 to v0.2.1 have no public key in their sources (Firmware Updates came with v0.3.0); their files are checked against today's.
|
|
|
|
### How it went
|
|
|
|
- **The runner's label took three tries.** Registered as `ubuntu://docker:ubuntu:resolute` and then as `ubuntu::docker://...`, Gitea took the whole string for the label's name; with the first, jobs ran on the runner's host itself. The first version of the workflow was written for that (plain shell, `docker run` for the build) and published v0.10.0 that way. `ubuntu:docker://docker.gitea.com/runner-images:ubuntu-latest` is the form that works.
|
|
- **Gitea 1.27's API can't cancel a run that isn't finished**, only delete a finished one; switching Actions off and on for the repository doesn't either. Runs queued for a label that no longer exists stay queued until cancelled in the web UI.
|
|
- **CI's image isn't byte-identical to a local build of the same tag** (same size, different bytes). Not pursued (Q158).
|