Move the ARMv6 leg out of core CI into a workflow of its own - #51
Merged
chrisuthe merged 2 commits intoAug 31, 2026
Merged
Conversation
linux-armv6 emulates every compile under qemu-user inside a Raspbian container: 23 minutes measured, against the two or three every other leg in the matrix takes. As a matrix leg it ran whenever the matrix ran -- every branch push, and again on every pull request -- so every push waited half an hour on the one leg that almost never had anything new to say. It is now .github/workflows/build-armv6.yml, one container-only job carrying its own triggers: workflow_call so release.yml can call it, push on main, a pull_request filtered to the workflow itself, scripts/build_armv6_container.sh and CMakeLists.txt, and workflow_dispatch. No unfiltered branch push, which is the cost being removed. Its concurrency guard is conditioned on the ref rather than on the workflow name, so it cannot cancel a run release.yml started whatever github.workflow resolves to inside a called workflow. Every assertion the matrix leg carried survives: QEMU_CPU=arm1176 throughout, the configure-output expectations, Tag_CPU_arch v6 and the hard-float EABI read off the linked binary, the GLIBC_2.36 bookworm ceiling, the EMULATED BUILD-INFO.txt block, the payload diff against both the staged tree and the tarball, and if: always() on the container stop. build.yml loses the leg and everything only it used: the container matrix key, the emulator registration and container start/stop steps, and every [ -n "$IMAGE" ] branch. Its matrix timeout comes down from 40 to 20, that 40 having been sized for ARMv6 alone. release.yml calls both workflows and its release job needs both, so a red ARMv6 build fails the release rather than publishing without its archive. The two expected-asset lists are untouched and still name sendspin-cli-$VERSION-linux-armv6.tar.gz. The trade this buys -- a tag builds one thing a push does not -- is written down rather than left to be discovered: in both workflows' comments, in README's CI section, and in ROADMAP item 12.
…out off a real run - build.yml: drop a stray comment fragment left where the !matrix.container paragraph was, and justify timeout-minutes: 20 against measured job durations rather than an inherited sentence. The slowest remaining leg is linux-armv7 at ~3m09s and macos-arm64 comes in under two minutes, so 20 leaves better than five times the slowest measurement. - build.yml: note that build-armv6.yml holds a third copy of the shared cmake options array, the payload assertion already carrying that kind of cross-reference both ways. - release.yml: say in the no-concurrency comment that the tag-only trigger is also what makes build-armv6.yml's conditional cancel-in-progress hold, so a later workflow_dispatch here cannot silently re-open that window. - scripts/get_started_linux.sh: build_armv6_container.sh is no longer run on every build, and 'the containerised leg' names nothing. - scripts/build_armv6_container.sh: the caller is one job, not a matrix leg. - docs/ROADMAP.md item 10: drop the echo of the retired claim that a release is gated on what a push is gated on. - README, ROADMAP, build-armv6.yml: the tip of main is covered within half an hour of a merge, not every merge -- cancel-in-progress means a superseded run does not finish. - docs/wiki/Installation.md: 'anything not in the matrix' no longer names the set of architectures with no release. - Comments that narrated the split rather than describing the current arrangement, and the overstated claim that the job name is load-bearing.
chrisuthe
marked this pull request as ready for review
August 31, 2026 02:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
linux-armv6emulates every compile underqemu-userinside a Raspbian container: 23 minutes measured, where every other leg in the matrix finishes in under three and a half. As a matrix leg it ran whenever the matrix ran — every branch push, and again on every pull request — so every push waited half an hour on the leg that almost never had anything new to say.The split
.github/workflows/build-armv6.ymlis a new one-job workflow holding that leg with everymatrix.*branch collapsed to the container-only side. It carries its own triggers:workflow_call, sorelease.ymlcalls itpush: branches: [main]— post-merge coveragepull_requestfiltered to.github/workflows/build-armv6.yml,scripts/build_armv6_container.shandCMakeLists.txtworkflow_dispatchNo unfiltered branch
push, which is the cost being removed.build.ymlloses the leg and everything only it used: thecontainermatrix key, the emulator-registration and container start/stop steps, and everyif [ -n "\$IMAGE" ]branch in Configure, Build, Test, Smoke test, Package and the architecture assertion.matrix.arm32stays —linux-armv7still uses it.release.ymlcalls both workflows and itsreleasejob needs both, so a red ARMv6 build fails the release rather than publishing without its archive. The two expected-asset lists are untouched and still namesendspin-cli-\$VERSION-linux-armv6.tar.gz.Nothing the leg proved is lost
Every assertion survives:
QEMU_CPU=arm1176throughout (configure included), the configure-output expectations for backends and mDNS,Tag_CPU_arch: v6andTag_ABI_VFP_args: VFP registersread off the linked binary, theGLIBC_2.36bookworm ceiling, theEMULATEDBUILD-INFO.txtblock with its glibc floor read off the binary, the payload file-list diff against both the staged tree and the tarball,-Wno-error=restrictas the single warning exemption,--initwith a non-root build user, andif: always()on the container stop. The cache key is the same literaldeps-linux-armv6-<hash>, so existing caches still hit.The concurrency guard
build-armv6.ymlkeeps aconcurrencyblock — cancelling a superseded run is worth more on a 25-minute job than anywhere else here — butcancel-in-progressis conditioned on the ref rather than the workflow name:Two runs share a group only if they share a ref, a release run's ref is always a tag, and no tag-ref run cancels anything — so the guard holds whatever
github.workflowresolves to inside a called workflow, which is a fact this repo cannot test without cutting a release.release.yml's no-concurrency comment now says that its tag-only trigger is load-bearing for this, so a laterworkflow_dispatchthere cannot silently re-open the window.The trade, written down
A tag now builds one thing a push does not.
build.yml's header no longer claims a release is gated on exactly what a push is gated on, and neither doesrelease.ymlor ROADMAP item 10. What bounds the cost: the tip ofmaingets an ARMv6 build within half an hour of a merge, and the release path still blocks on a green ARMv6 build. Thepull_requestpath filter is deliberately honest about its reach — it catches infrastructure changes, not the ARMv6-only source breaks this project has actually met (the gcc 12-Wrestrictfalse positive and the-latomicclass), which are caught after the merge instead.Also in here
The matrix
timeout-minutescomes down from 40 to 20. That 40 was sized for ARMv6 alone; 20 is sized off recent runs —linux-armv7is the slowest remaining leg at ~3m09s andmacos-arm64comes in under two minutes, so it leaves better than five times the slowest measurement.Comment debt swept where the old arrangement was named:
ci.yml,scripts/build_armv6_container.sh(including the message it prints to a developer whose container died),scripts/build_arm32.sh,scripts/get_started_linux.sh, README's "## CI", ROADMAP items 10 and 12, anddocs/wiki/Installation.md.Checks
actionlintis clean on all five workflows andshellcheck scripts/*.shpasses. This PR touches its own workflow path, so it runslinux-armv6through the new file's path filter — which is what stands in for aworkflow_dispatchthat is not available until the workflow is on the default branch.