Skip to content

ci(companion): build one firmware per runner with cached toolchains - #9

Merged
Elektr0Vodka merged 2 commits into
mainfrom
Chore/companion-ci-matrix
Oct 16, 2026
Merged

Elektr0Vodka merged 2 commits into
mainfrom
Chore/companion-ci-matrix

Conversation

@Elektr0Vodka

Copy link
Copy Markdown
Owner

What changed

Two commits.

1. ci(companion): one runner per firmware, with caches (.github/workflows/build-companion-firmwares.yml, build.sh)

The workflow is split into three jobs, following the DMC observer workflow:

  • prepare: resolves the version, release tag and pre-release flag once (same rules as before), and gets the board list from the new build.sh get-meshcomod-companion-firmwares-to-build, which prints MESHCOMOD_COMPANION_ENVS. That array stays the only board list.
  • build: a matrix with one runner per board, fail-fast: false. Caches:
    • ~/.platformio/packages and ~/.platformio/platforms, keyed on platformio.ini (with a restore-key fallback). The espressif32 toolchain and framework are pinned there, so this skips the large download and unpack on every runner.
    • .pio/libdeps/<env>, keyed on the board, all ini files, and arch/esp32/AsyncElegantOTA/** (the in-repo file:// library, so its copy cannot go stale). Exact key only: any lib_deps change installs fresh.
    • Compiled objects are not cached: build.sh puts the version and build date in the global flags, which invalidates them anyway.
    • The existing pip and ~/.platformio/.cache cache in setup-build-environment is untouched.
  • release: downloads every fw-<env> artifact into out/, uploads the combined companion-firmwares artifact as before, then creates the release and prunes, both only when there is a tag (unchanged).

One deliberate behaviour change: the release job needs every board to build. With fail-fast off, the other boards still finish and the failure shows in the run, but no release is published without a board. Before, a failure stopped the single sequential job.

2. feat(companion): release the four new usb_tcp boards (build.sh, README.md, docs/CI_RELEASES.md)

Adds heltec_v4_r8_companion_radio_usb_tcp, heltec_v4_r8_tft_companion_radio_usb_tcp, heltec_v4_tft_companion_radio_usb_tcp and Heltec_WSL3_companion_radio_usb_tcp (from #7) to MESHCOMOD_COMPANION_ENVS, and updates the README supported devices table, the CI releases table and the build.sh help text. The README touch note now says "touch UI builds", because a non-touch V4 TFT build ships from here.

A companion release now builds 10 boards: V4, V3, Wireless Paper, Xiao, V4 R8, V4 R8 TFT, V4 TFT and WSL3 (all _usb_tcp), plus ThinkNode M7 BLE and Ethernet.

Why

The release built everything one board after another on a single runner and downloaded the toolchains every time. With 10 boards that gets slow. The four new boards were defined in #7 but were never built by the release.

How it was tested

  • bash build.sh get-meshcomod-companion-firmwares-to-build prints the 10 envs. Each one resolves to an [env:...] section in variants/, and the jq conversion gives the matrix JSON.
  • actionlint on the workflow: no findings in the workflow itself. It reports that .github/actions/setup-build-environment/action.yml has no description, which predates this PR.
  • The four new boards built locally with build.sh build-firmware in feat(companion): add usb_tcp envs for V4 R8, V4 R8 TFT, V4 TFT and WSL3 #7 (sizes are in that PR).
  • Not yet run on GitHub Actions. The first real check is a manual run (Actions, Build Companion Firmwares, Run workflow, without prerelease), which builds everything and uploads artifacts without publishing.

Firmware and build impact

No firmware source changes. Release assets gain the four new boards (<env>.bin, -merged.bin, .partsig, plus the timestamped copies merge-bin.py writes). The web flasher still needs entries for them; the OTA server picks them up by suffix. The new boards are not tested on hardware.

No issue to close.

The companion release built all boards one after another on a single
runner, re-downloading the PlatformIO toolchains every time. Split it
like the DMC observer workflow:

- prepare: resolve the version and release tag once, and read the board
  list from the new `build.sh get-meshcomod-companion-firmwares-to-build`
  (MESHCOMOD_COMPANION_ENVS stays the single list).
- build: a matrix with one runner per board, fail-fast off, caching
  ~/.platformio packages and platforms per platformio.ini and each
  board's libdeps per ini files (plus the in-repo AsyncElegantOTA copy).
- release: collect all boards, upload the combined companion-firmwares
  artifact as before, then create the (pre-)release and prune.

The release only runs when every board built, so a failed board blocks
the release instead of it shipping without that board. Tag handling,
pre-release numbering and retention are unchanged.
The four usb_tcp envs from #7 were defined but not in
MESHCOMOD_COMPANION_ENVS, so the companion release never built them.
Add them; with the matrix workflow each gets its own runner, and the OTA
server picks them up by their _companion_radio_usb_tcp suffix.

Board lists follow: README supported devices, the CI releases table and
the build.sh help text. The README touch note now says touch UI builds,
since a non-touch V4 TFT build is released from here.

The new boards build but have not been tested on hardware.
@Elektr0Vodka
Elektr0Vodka merged commit a6cda50 into main Oct 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant