ci: split release into firmware and PCB tag-triggered workflows#8
Merged
ci: split release into firmware and PCB tag-triggered workflows#8
Conversation
- docs/brainstorms/2026-04-23-001-split-release-tags-requirements.md: requirements for splitting the unified release workflow into two tag-triggered streams (firmware on v*.*.*, PCB on pcb-*.*.*) with separate CHANGELOGs and a shared concurrency group. - docs/plans/2026-04-23-001-refactor-split-release-tags-plan.md: implementation plan covering 5 units from seed tag push through README runbook update, with fromTag/toTag + grep -v -Fx prev_tag computation, refname-exact tag-on-main guard, and seed-tag guardrails.
Replace the single tag-triggered release.yml (v*.*.*) with two mirror workflows keyed by tag prefix, each writing to its own CHANGELOG and publishing the asset profile that matches its component. - .github/workflows/release-firmware.yml — tags v*.*.*. Writes CHANGELOG.md with excludeScopes: changelog,pcb and excludeTypes: chore,style,build. No asset attached. makeLatest: legacy (unchanged). - .github/workflows/release-pcb.yml — tags pcb-*.*.*. Writes pcb/CHANGELOG.md. Zips pcb/src into gerber.zip with Garde C12 validation. makeLatest: false so the PCB release never shadows the firmware 'latest' badge. Job-level guard 'if: github.ref_name != pcb-0.1.0' makes the workflow idempotent to the seed baseline. - .github/workflows/release.yml removed — the conditional 'PCB inchangé depuis X' note disappears with it. - README 'Couper une release' split into two procedures (firmware and PCB), each documenting regex, tag-push steps, and forward-looking retag. Explicit guardrail that pcb-0.1.0 is an immutable seed baseline and must never be deleted, moved, or retagged. Both workflows: - Use requarks/changelog-action in fromTag/toTag mode with the previous tag precomputed via 'git tag --list <prefix>* --sort=-v:refname | grep -v -Fx <current> | head -n1' (skip-by-name, not by sort position, so non-monotonic retags stay correct). Guard empty result loudly instead of falling through to silent malformed release. - Share 'concurrency: group: release-main' so a combined push 'v0.2.0 pcb-0.1.1' serialises cleanly on the main auto-commit. - Upgrade the tag-on-main guard to refname-exact match (closes a residual risk from the hardening learning doc's 'origin/main$' suffix-match fragility). The seed baseline tag pcb-0.1.0 was pushed separately to 7ea5eab before this commit lands; the PCB workflow depends on its presence to compute prev_tag for pcb-0.1.1 onwards. See docs/plans/2026-04-23-001-refactor-split-release-tags-plan.md for implementation units and docs/brainstorms/2026-04-23-001-split-release-tags-requirements.md for the product decisions this plan implements. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Applied from the ce-code-review pass on this branch (.context/compound-engineering/ce-code-review/20260423-072851-f135194c/): Safe-auto fixes: - Tightened tag-list globs in both workflows to match the trigger regex quantifier (v[0-9][0-9]*... instead of v[0-9]*..., and pcb- analogue). Prevents a malformed historical tag like v.1.0 from ever being selected as prev_tag. - Made the Gerber validation grep case-insensitive. Protects against a future EDA toolchain export using lowercase extensions. - Clarified the README PCB section: gerber.zip is now attached only to pcb-* releases, never firmware. P1 fix (seed-tag baseline): - Retargeted the pcb-0.1.0 seed tag from 7ea5eab to b5573bb. The original import commit 7ea5eab was squash-merged in PR #7 and is unreachable from main; git merge-base pcb-0.1.0 HEAD returned c73abbf, meaning the first pcb-0.1.1 release would have pulled 6 non-PCB commits (monorepo fusion, docs, gitignore, ci-split itself) into the release notes. The squash-merge commit b5573bb is the first reachable commit on main that contains pcb/ and is the correct baseline anchor. - Updated README seed-tag guardrail + plan references to cite b5573bb rather than 7ea5eab, with a one-line note explaining why. Residual P2 findings documented in the run artifact (not blocking): - TOCTOU on auto-commit (concurrency group serializes job start, not push vs main). Commit-before-publish ordering means the failure mode is clean (no half-published release), recoverable by retag. - No actionlint in CI. Scope creep vs this plan; track as follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Summary
Firmware and PCB now release on separate tag prefixes with separate CHANGELOGs.
v*.*.*tags cut a firmware release (CHANGELOG.md, no asset).pcb-*.*.*tags cut a PCB release (pcb/CHANGELOG.md,gerber.zipattached,makeLatest: false). The unifiedrelease.ymland its conditional "PCB inchangé" body note are retired.The split eliminates the forced shared lifecycle: a PCB revision no longer requires a firmware bump (and vice versa), and release notes for either component no longer pull in commits from the other.
What changed
v*.*.*trigger, no asset,makeLatest: legacy, writesCHANGELOG.md.pcb-*.*.*trigger,gerber.zipvalidated via Garde C12,makeLatest: false, writespcb/CHANGELOG.md..github/workflows/release.yml— unified workflow + the PCB-unchanged conditional body note.pcb-0.1.0onb5573bb(the squash-merge wherepcb/landed on main) as the anchor forgit tag --list 'pcb-*'. First real PCB release will bepcb-0.1.1.Key design decisions
fromTag/toTagwith a shell pre-step, not the action'stag:mode.requarks/changelog-action's default mode runs a prefix-blindgit describe— on apcb-0.1.1push it would return the latest firmware tag, producing either an action failure (latestTag.name !== tag) or a PCB changelog full of firmware commits. The pre-step computes the component-scoped previous tag withgit tag --list '<prefix>[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -v -Fx "${ref}" | head -n1and fails loudly on empty. Skip-by-name is correct under forward-looking retags of older versions; positionalsed '2p'would not be.concurrency: release-mainacross both workflows. Per-workflow groups would only serialize retags of the same component. The real concern is a combinedgit push origin main v0.2.0 pcb-0.1.1racing two CHANGELOG auto-commits againstmain. A shared group closes that window.grep 'origin/main$'→git branch -r --format='%(refname)' | grep -Fxq 'refs/remotes/origin/main'. Closes a residual risk from the hardening learning doc —origin/main$would matchfeat-mainor a second remote'smain.b5573bb, not on the original import commit7ea5eab. PR feat: fusionner frangipool/pcb dans le monorepo + release workflow #7 was squash-merged, so7ea5eabis unreachable frommain.git merge-base pcb-0.1.0 HEADwould otherwise returnc73abbfand pollute the first PCB release notes with the monorepo fusion itself.b5573bb— the squash-merge — is the correct anchor for a post-monorepo PCB lifecycle.Known residual risks
mainbetween checkout andgit-auto-commit-actionactionlint— new workflow YAML is first validated on a real tag pushworkflow_dispatchdry-run pathpcb-0.1.0deletion would break all future PCB releasesif: github.ref_name != 'pcb-0.1.0') + README "NE JAMAIS supprimer" encart. Repo-level tag protection rule recommended but not yet configuredPost-Deploy Monitoring & Validation
No CI-level monitoring to configure — the GitHub Actions tab is sufficient. The first real release cycle is the end-to-end test:
v0.2.0): release-firmware.yml only fires (not release-pcb.yml).CHANGELOG.mdgets a new## [v0.2.0]entry excluding scopespcb,changelogand typeschore,style,build. No asset attached. "Latest release" badge updates.pcb-0.1.1): release-pcb.yml only fires.pcb/CHANGELOG.mdgets a new## [pcb-0.1.1]entry above the archived## [v0.1.0] - 2023-06-08.gerber.zipattached, C12 pattern passes. "Latest release" badge unchanged — stays on firmware.git push origin main v0.2.1 pcb-0.1.2): both workflows queue onrelease-main, serialize cleanly. Both releases land without non-fast-forward errors.Full post-merge checklist in
docs/plans/2026-04-23-001-refactor-split-release-tags-plan.mdunder "Post-merge validation checklist". Failure signal: an unexpected asset on a firmware release, missing asset on a PCB release, or a CHANGELOG commit without a corresponding GitHub Release (commit-before-publish drift). Rollback:gh release delete <tag> --yes,git tag -d <tag>,git push origin :refs/tags/<tag>, re-tag after fixing the workflow.References
docs/brainstorms/2026-04-23-001-split-release-tags-requirements.mddocs/plans/2026-04-23-001-refactor-split-release-tags-plan.mddocs/solutions/architecture/tag-triggered-release-workflow-hardening.md.context/compound-engineering/ce-code-review/20260423-072851-f135194c/— 4 safe_auto applied; P1 seed-tag retarget resolved during review; 2 P2 residuals tracked above