ci: require stable releases from main#5
Conversation
jwfing
left a comment
There was a problem hiding this comment.
Review: ci: require stable releases from main
Summary: A tightly-scoped, correct CI change that gates stable pub.dev releases on the release tag pointing to a commit contained in main, using the canonical fetch-depth: 0 + git merge-base --is-ancestor pattern applied identically to both publish workflows.
Requirements context
No spec/plan under docs/superpowers/ matches this PR — the specs/plans there all cover the SDK feature work (core, auth, database, storage, functions, ai, umbrella). Assessed against the PR description and the documented release process in CONTRIBUTING.md:127-153. That checklist mandates "commit, open a PR, merge to main" and then tag the release commit — so this change directly enforces the already-documented convention. Nicely in-scope.
Findings
Critical
(none)
Suggestion
- Software engineering — duplicated validation logic across both workflows (
.github/workflows/publish-insforge.yml:36-45,.github/workflows/publish-insforge-flutter.yml:37-46). The stable-detection + ancestry-check block is now copy-pasted verbatim in both files. This PR only extends pre-existing duplication rather than introducing it, so it's not blocking, but as the release logic grows, consider factoring it into a reusable composite action or a smalltool/script invoked by both. Non-blocking. - Functionality — error exit codes are conflated with a failed ancestry check (
publish-insforge.yml:39-42,publish-insforge-flutter.yml:40-43).git merge-base --is-ancestorreturns1when the commit is not an ancestor and a different non-zero code (e.g.128) on error — for instance iforigin/mainwere ever unavailable or$release_commitwere unresolvable. Theif ! ...guard maps both to the samemust point to a commit contained in mainmessage. This fails closed (blocks the publish), which is the safe direction, but a genuine environment error would surface a misleading diagnostic. Optionally distinguish a hard error from a legitimate "not on main" rejection. Non-blocking.
Information
- Functionality —
fetch-depth: 0is required and correct here. The ancestry check needs both full history and a populatedrefs/remotes/origin/main;actions/checkoutwithfetch-depth: 0fetches all branches/tags (+refs/heads/*:refs/remotes/origin/*), soorigin/mainresolves as the check assumes. Good call adding it — without itmerge-basewould fail. - Functionality — behavior matches the PR claims. Verified the version regex:
1.2.3/1.2.3+5→stable=true(gated),1.2.3-beta.1/1.2.3-rc.1+build→stable=false(prerelease publishes untouched, no GitHub Release, no ancestry gate). This preserves prerelease tags from non-main branches as stated.RELEASE_TAG(github.ref_name) is defined in the stepenvand${RELEASE_TAG}^{commit}correctly peels an annotated tag to its commit — consistent with the annotated-tag release flow inCONTRIBUTING.md:132-146. - Security — no security-relevant surface changes. No new user-controlled input reaches a shell in an unsafe way;
RELEASE_TAG/release_commitare quoted throughout. Job permissions are unchanged (validatestayscontents: read). No secrets, tokens, or PII introduced or logged. - Performance — negligible.
fetch-depth: 0fetches full history, but this only runs on release-tag pushes (infrequent) and the repo is small; acceptable trade-off for the correctness it buys. - Testing — appropriate for a workflow-only change. No unit tests apply to YAML; the PR reports
actionlint, format/analysis, version-sync, Dart/Flutter tests, and publish dry-runs, which is the right verification surface here.
Verdict
approved — zero Critical findings. The change is correct, well-scoped, consistent across both packages, and faithfully enforces the documented release process. The two Suggestions are optional polish. (Informational verdict; the green-checkmark GitHub approval remains a separate human action.)
Summary
mainVerification
actionlint