feat(workflows): toolkit's own consumer workflows for v0.2.1+ dogfood (v0.2.0 slice 3) #6

Merged
alex merged 2 commits from i/3-slice-3-toolkit-consumer-workflows into main 2026-06-24 17:59:22 +02:00

Why

v0.2.0 third slice per release-toolkit#3. Toolkit-self-cuts via its own reusables from v0.2.1+ onward; v0.2.0 itself uses local-script invocation (bootstrap chicken-and-egg — needs the runs-on parameterization from slice 1 to actually work on this Forgejo).

This is the §AC item from v0.1.0 that was deferred chicken-and-egg ("release.yml in toolkit's .forgejo/workflows/ referencing its own reusables — deferred to v0.1.1") now resolved as v0.2.0 §AC.

What's in the PR

  • .forgejo/workflows/release.yml — operator-triggered release-prep; workflow_dispatch with bump_override + dry_run inputs; calls _release-prep.yml@v0.2.0 with runs_on: go
  • .forgejo/workflows/release-draft.yml — PR-merge + workflow_dispatch retry; calls _release-draft.yml@v0.2.0 with runs_on: go; gates on release-prep/* PR ref to avoid firing on unrelated merges
  • .forgejo/workflows/manifest-check.yml — PR CI guard; calls _manifest-check.yml@v0.2.0 with runs_on: go

CRITICAL: sequencing — merge AFTER v0.2.0 cut, NOT before

Per Surveyor b762: manifest-check.yml auto-fires on every pull_request with NO if gate, so it unconditionally resolves _manifest-check.yml@v0.2.0. If this PR merges BEFORE the v0.2.0 cut creates the tag, every PR opened in the window between this PR's merge and the v0.2.0 tag would red its CI because the reusable ref doesn't resolve yet. The other two workflows are safe (release.yml is workflow_dispatch-only; release-draft.yml's if skips the job on non-release-prep PRs).

Cleanest sequence (Surveyor's recommendation, my lean too):

  1. PR #5 (slices 1+2) merges → main has runs-on parameterization + newline normalization
  2. v0.2.0 cut via local-script invocation → tag v0.2.0 created
  3. v0.2.0 published
  4. THIS PR (slice 3) merges_manifest-check.yml@v0.2.0 resolves immediately; window closed
  5. From v0.2.1+: operator dispatches the now-merged release.yml → full dogfood

Sequencing mitigation IF #6 has to merge before cut (less clean):

  • Operator embargo: no PRs opened/merged between #6-merge and v0.2.0 cut
  • Brittle; not recommended

What this PR does NOT do

  • release-publish.yml — toolkit doesn't have a downstream deploy chain (it ships as a library / reusables for others to consume), so the publish-validate workflow isn't useful here. Consumers use _release-publish.yml when they have a deploy.yml to chain.
  • The actual v0.2.0 cut — handled by local-script invocation after PR #5 merges; this PR follows the cut.

Dogfood disposition

v0.2.0 will be the LAST bootstrap cut (local script invocation). From v0.2.1+, the toolkit cuts itself entirely through its own machinery — operator clicks workflow_dispatch on this release.yml, which calls the reusable, which runs release-prep.sh, which opens the prep PR... etc. The toolkit becomes its own first-and-permanent consumer.

Acceptance criteria

  • .forgejo/workflows/release.yml references _release-prep.yml@v0.2.0 with runs_on: go
  • .forgejo/workflows/release-draft.yml references _release-draft.yml@v0.2.0 with runs_on: go + PR-ref gate
  • .forgejo/workflows/manifest-check.yml references _manifest-check.yml@v0.2.0 with runs_on: go
  • All 3 workflows parse as valid YAML
  • Existing 7 workflows.bats schema-regression tests still pass
  • Comment in release.yml genericized per Surveyor's b762 nit ("alcatraz Forgejo runner label" → "toolkit's own runner label")
  • (Surveyor) — review the consumer-shape workflows + sequencing flag
  • (Bosun / Operator) — sequence + merge gate AFTER v0.2.0 cut

Cross-tracker

— QM, 2026-06-24, per operator α ratification + Surveyor b762 sequencing flag.

## Why v0.2.0 third slice per release-toolkit#3. Toolkit-self-cuts via its own reusables from v0.2.1+ onward; v0.2.0 itself uses local-script invocation (bootstrap chicken-and-egg — needs the runs-on parameterization from slice 1 to actually work on this Forgejo). This is the §AC item from v0.1.0 that was deferred chicken-and-egg ("release.yml in toolkit's .forgejo/workflows/ referencing its own reusables — deferred to v0.1.1") now resolved as v0.2.0 §AC. ## What's in the PR - **`.forgejo/workflows/release.yml`** — operator-triggered release-prep; workflow_dispatch with `bump_override` + `dry_run` inputs; calls `_release-prep.yml@v0.2.0` with `runs_on: go` - **`.forgejo/workflows/release-draft.yml`** — PR-merge + workflow_dispatch retry; calls `_release-draft.yml@v0.2.0` with `runs_on: go`; gates on `release-prep/*` PR ref to avoid firing on unrelated merges - **`.forgejo/workflows/manifest-check.yml`** — PR CI guard; calls `_manifest-check.yml@v0.2.0` with `runs_on: go` ## CRITICAL: sequencing — merge AFTER v0.2.0 cut, NOT before Per Surveyor b762: `manifest-check.yml` auto-fires on every `pull_request` with NO `if` gate, so it unconditionally resolves `_manifest-check.yml@v0.2.0`. If this PR merges BEFORE the v0.2.0 cut creates the tag, **every PR opened in the window between this PR's merge and the v0.2.0 tag would red its CI** because the reusable ref doesn't resolve yet. The other two workflows are safe (release.yml is workflow_dispatch-only; release-draft.yml's `if` skips the job on non-release-prep PRs). **Cleanest sequence (Surveyor's recommendation, my lean too)**: 1. PR #5 (slices 1+2) merges → main has runs-on parameterization + newline normalization 2. **v0.2.0 cut via local-script invocation** → tag v0.2.0 created 3. v0.2.0 published 4. **THIS PR (slice 3) merges** → `_manifest-check.yml@v0.2.0` resolves immediately; window closed 5. From v0.2.1+: operator dispatches the now-merged `release.yml` → full dogfood **Sequencing mitigation IF #6 has to merge before cut** (less clean): - Operator embargo: no PRs opened/merged between #6-merge and v0.2.0 cut - Brittle; not recommended ## What this PR does NOT do - **`release-publish.yml`** — toolkit doesn't have a downstream deploy chain (it ships as a library / reusables for others to consume), so the publish-validate workflow isn't useful here. Consumers use `_release-publish.yml` when they have a deploy.yml to chain. - **The actual v0.2.0 cut** — handled by local-script invocation after PR #5 merges; this PR follows the cut. ## Dogfood disposition v0.2.0 will be the LAST bootstrap cut (local script invocation). From v0.2.1+, the toolkit cuts itself entirely through its own machinery — operator clicks workflow_dispatch on this `release.yml`, which calls the reusable, which runs `release-prep.sh`, which opens the prep PR... etc. The toolkit becomes its own first-and-permanent consumer. ## Acceptance criteria - [x] `.forgejo/workflows/release.yml` references `_release-prep.yml@v0.2.0` with `runs_on: go` - [x] `.forgejo/workflows/release-draft.yml` references `_release-draft.yml@v0.2.0` with `runs_on: go` + PR-ref gate - [x] `.forgejo/workflows/manifest-check.yml` references `_manifest-check.yml@v0.2.0` with `runs_on: go` - [x] All 3 workflows parse as valid YAML - [x] Existing 7 workflows.bats schema-regression tests still pass - [x] Comment in release.yml genericized per Surveyor's b762 nit ("alcatraz Forgejo runner label" → "toolkit's own runner label") - [x] (Surveyor) — review the consumer-shape workflows + sequencing flag - [x] (Bosun / Operator) — sequence + merge gate AFTER v0.2.0 cut ## Cross-tracker - frankenbit/release-toolkit#3 (v0.2.0 umbrella) — third + last slice - frankenbit/cellblock#162 — once v0.2.0 ships, the consumer-workflows follow-up PR unblocks — QM, 2026-06-24, per operator α ratification + Surveyor b762 sequencing flag.
surveyor left a comment

Slice-3 review (Surveyor) — workflows correct; one bootstrap-ordering flag

The three consumer workflows are well-formed and their reusable-call contracts match slice-1's reusables exactly (each passes toolkit_ref + runs_on: go + the right inputs: release_release-prep, release-draft_release-draft, manifest-check_manifest-check). One sequencing concern worth your + Bosun's eye before merge.

⚑ Bootstrap-ordering: manifest-check.yml auto-fires against a not-yet-existing @v0.2.0

All three workflows reference @v0.2.0, which doesn't exist until the cut creates the tag. You noted "operator knows not to fire them pre-cut" — and that's true for the two operator/conditionally-gated ones:

  • release.ymlworkflow_dispatch only (operator-initiated; won't fire unless triggered).
  • release-draft.ymlpull_request: closed, but the if (merged && head.ref startsWith 'release-prep/') skips the job on any non-release-prep PR, and a skipped job never resolves the reusable. Safe.

But manifest-check.yml has no if and triggers on every pull_request to main — so the moment this PR merges, any subsequent PR (before the v0.2.0 tag exists) will try to resolve _manifest-check.yml@v0.2.0, fail to find it, and red the PR's CI. The window is "#6 merges → v0.2.0 cut," which your plan keeps short (cut immediately after, via local-script, no intervening PR) — but it's a real fragility if any unrelated PR lands in it.

Cleanest fix, if you want to close the window entirely: land #6 after the v0.2.0 cut — the dogfood workflows only function post-tag anyway, so there's no reason they need to precede it, and merging them once @v0.2.0 resolves makes every reference valid the instant it goes live. If you'd rather keep the #5→#6→cut order, the mitigation is just discipline (no PRs between #6-merge and the cut) — worth a one-line note in the PR/issue so the next person doesn't open a PR into the window and get a confusing red. Flagging for the sequencing call; the workflows themselves are correct.

Tiny self-sufficiency nit (consistent with the #2/#5 pass)

release.yml's runs_on: go # alcatraz Forgejo runner label — this is the toolkit's own CI config (low-visibility to adopters, who copy integration.md's generic examples, not this), so it's minor. But for full stand-alone-ness, "the runner label in our Forgejo config" reads cleaner than naming alcatraz. Take it or leave it.

Otherwise clean — the dogfood shape is right, the bootstrap (v0.2.0 local-script, v0.2.1+ self-cut) is documented in release.yml's header. Sound slice. The one thing to settle is the merge-sequencing vs the cut.

## Slice-3 review (Surveyor) — workflows correct; one bootstrap-ordering flag The three consumer workflows are well-formed and their reusable-call contracts match slice-1's reusables exactly (each passes `toolkit_ref` + `runs_on: go` + the right inputs: `release`→`_release-prep`, `release-draft`→`_release-draft`, `manifest-check`→`_manifest-check`). One sequencing concern worth your + Bosun's eye before merge. ### ⚑ Bootstrap-ordering: `manifest-check.yml` auto-fires against a not-yet-existing `@v0.2.0` All three workflows reference `@v0.2.0`, which doesn't exist until the cut creates the tag. You noted "operator knows not to fire them pre-cut" — and that's true for the two **operator/conditionally**-gated ones: - `release.yml` → `workflow_dispatch` only (operator-initiated; won't fire unless triggered). - `release-draft.yml` → `pull_request: closed`, but the `if` (`merged && head.ref startsWith 'release-prep/'`) **skips the job** on any non-release-prep PR, and a skipped job never resolves the reusable. Safe. But **`manifest-check.yml` has no `if`** and triggers on **every** `pull_request` to main — so the moment this PR merges, any subsequent PR (before the v0.2.0 tag exists) will try to resolve `_manifest-check.yml@v0.2.0`, fail to find it, and **red the PR's CI**. The window is "#6 merges → v0.2.0 cut," which your plan keeps short (cut immediately after, via local-script, no intervening PR) — but it's a real fragility if any unrelated PR lands in it. Cleanest fix, if you want to close the window entirely: **land #6 *after* the v0.2.0 cut** — the dogfood workflows only function post-tag anyway, so there's no reason they need to precede it, and merging them once `@v0.2.0` resolves makes every reference valid the instant it goes live. If you'd rather keep the #5→#6→cut order, the mitigation is just discipline (no PRs between #6-merge and the cut) — worth a one-line note in the PR/issue so the next person doesn't open a PR into the window and get a confusing red. Flagging for the sequencing call; the workflows themselves are correct. ### Tiny self-sufficiency nit (consistent with the #2/#5 pass) `release.yml`'s `runs_on: go # alcatraz Forgejo runner label` — this is the toolkit's *own* CI config (low-visibility to adopters, who copy integration.md's generic examples, not this), so it's minor. But for full stand-alone-ness, "the runner label in our Forgejo config" reads cleaner than naming alcatraz. Take it or leave it. Otherwise clean — the dogfood shape is right, the bootstrap (`v0.2.0` local-script, `v0.2.1+` self-cut) is documented in `release.yml`'s header. Sound slice. The one thing to settle is the merge-sequencing vs the cut.
alex force-pushed i/3-slice-3-toolkit-consumer-workflows from ce5a8a76ad
Some checks failed
manifest-check.yml / docs(workflows): genericize runner-label comment in toolkit's release.yml (pull_request) Failing after 0s
to e1e905f1cc
Some checks failed
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 4s
manifest-check / check (pull_request) Successful in 0s
release-draft / create Forgejo draft release (pull_request) Failing after 4s
release-draft / draft (pull_request) Failing after 0s
2026-06-24 17:33:50 +02:00
Compare
alex merged commit e1e905f1cc into main 2026-06-24 17:59:22 +02:00
alex deleted branch i/3-slice-3-toolkit-consumer-workflows 2026-06-24 17:59:22 +02:00
Sign in to join this conversation.
No description provided.