Skip to content

feat: branch-per-major release model#172

Merged
MuncleUscles merged 1 commit into
v1from
feat/release-flow-v1
May 20, 2026
Merged

feat: branch-per-major release model#172
MuncleUscles merged 1 commit into
v1from
feat/release-flow-v1

Conversation

@MuncleUscles
Copy link
Copy Markdown
Member

Summary

Aligns genlayer-js with the branch-per-major release model used by genlayer-node (branches v0.3, v0.4, v0.5 with the current major as default; no main) and genvm (branches v0.2.x, v0.3.x; tags within each line).

Concretely:

  • Branch model: v1 is the current stable major (this PR targets it). v<next>-dev (or v2) exists when a next-major is in progress. main is being retired.
  • Release flow: human-driven via scripts/release.sh. CI publishes from the tag push, never from a branch push.
  • Skill: .claude/skills/release/SKILL.md wraps the flow for Claude Code, including pre-flight checks and roll-back guidance.

Why now: twice already a conventional-commit BREAKING CHANGE footer in a PR body triggered an accidental major bump (0.28.7 → 1.0.0 here; yanked v1/v2 tags on genlayer-testing-suite). The fix isn't tighter heuristics — it's putting a human checkpoint between "PR merged" and "release published".

Changes

File Change
.github/workflows/publish.yml Trigger: push: branches: [main]push: tags: ['v*']. No more version bumping in CI — it now sanity-checks tag == package.json.version, builds, publishes to npm, and cuts the GitHub Release.
scripts/release.sh (new, +x) The release entry point. Pre-flight: on a v<major> branch, clean tree, in sync with origin, latest CI green. Refuses major bumps without --allow-major (those need a new branch). Runs release-it with an explicit version + --no-npm.publish --no-github.release so the dev machine doesn't need npm auth and the GH release is cut by CI from the tag arrival.
.claude/skills/release/SKILL.md (new) Claude skill: when to invoke, what to confirm, what to refuse, roll-back path (deprecate-don't-unpublish).
CONTRIBUTING.md Branch model section + release section pointing at the skill.
package.json npm run release./scripts/release.sh (was bare release-it --ci, which bypassed every pre-flight check).
.github/e2e-track mainv0.5 (the runner's current stable matrix track).

Verification

Locally:

# Refuses from feature branch
$ scripts/release.sh patch
Refusing to release from 'feat/release-flow-v1'.
...

# Refuses major bump without --allow-major
$ git checkout v1 && scripts/release.sh major
Refusing major bump 1.1.8 → 2.0.0 without --allow-major.
...

# Refuses dirty tree, out-of-sync HEAD, red CI — each with a clear message

End-to-end test of the new publish.yml: I'll do a dry run by tagging a no-op version bump (e.g. v1.1.9-rc.0) once this lands and the default branch is flipped — call out if you'd rather see that first against this PR.

Follow-up (separate PRs, not in scope here)

After this lands:

  1. GitHub admin: switch default branch from main to v1. Then git push origin :main.
  2. Other repos: same shape applied to genlayer-py (v0.18), genlayer-cli (v0.39), genlayer-testing-suite (v0.29), genlayer-explorer (TBD branch — no prior tags).
  3. Runner matrix: ci-core-e2e-runner/matrix/v0.5.yaml tooling refs from tag pins → branch pins (genlayer-js: v1, etc.). Open matrix/v0.6-dev.yaml as a stub.
  4. 0.x repos auto-bump cap: the cap-at-minor whatBump in .release-it.cjs is now belt-and-suspenders (the manual script passes explicit versions) but stays as a safety net. For the 0.x-versioned tooling repos (py / cli / testing-suite), even the script's "minor" bump is a major in semver terms — those scripts will refuse minor without --allow-major too.

Test plan

  • scripts/release.sh refuses from a non-v branch
  • scripts/release.sh major refuses without --allow-major
  • scripts/release.sh refuses on dirty tree
  • scripts/release.sh refuses when local HEAD diverges from origin
  • After merge: tag-push triggers publish.yml and a release ships end-to-end (will validate with a dry-run rc tag)
  • Skill walks Claude through a release without surprises (will validate once the dry-run lands)

Aligns this repo with genlayer-node + genvm: branches per major (v1
today; v2 / v2-dev when fees lands), no main, deliberate releases via
script + skill.

What changes:
- publish.yml fires on `push: tags v*` instead of `push: main`. The
  workflow no longer bumps versions — it just sanity-checks that the
  tag matches package.json, builds, publishes to npm, and creates the
  GitHub Release. No commits back to the branch.
- scripts/release.sh is the new release entry point. Pre-flight checks:
  on a v<major> branch, clean tree, in sync with origin, latest CI
  green. Refuses major bumps without --allow-major (those need a new
  branch in this model). Then runs release-it with an explicit
  version to bump package.json, prepend CHANGELOG.md, commit, tag,
  push — but with npm/github plugins disabled so the dev machine
  doesn't need npm auth and the GH release is cut by CI from the tag.
- .claude/skills/release/SKILL.md documents the flow for Claude: when
  to use it, what to confirm with the user, what to refuse, and the
  roll-back path (deprecate, never unpublish blind).
- CONTRIBUTING.md explains the branch model + points at the skill.
- npm run release → ./scripts/release.sh so the convenience script
  routes through pre-flight checks (the previous `release-it --ci`
  invocation bypassed every guard).
- .github/e2e-track on this branch points at runner track v0.5
  (current stable). v2-dev (when it exists) will point at v0.6-dev.

Why kill auto-bump:
- Twice landed accidental majors when a BREAKING CHANGE footer in a
  PR body triggered the conventional-commit bump algorithm — once on
  this repo (0.28.7 → 1.0.0), once on genlayer-testing-suite (yanked
  v1/v2 tags). The whatBump cap mitigated future jumps but didn't
  address the underlying issue: shipping a release shouldn't be a
  side-effect of merging a PR.
- The new flow puts a human checkpoint between "code lands" and
  "users get it" without losing the bump-and-tag automation.

Follow-up (separate PRs):
- After this lands: switch default branch on github.com from main to
  v1, then delete origin/main.
- Same shape applied to genlayer-py, genlayer-cli,
  genlayer-testing-suite, genlayer-explorer (per their existing major).
- Runner matrix updates: matrix/v0.5.yaml tooling refs switch from
  tag pins to branch pins (genlayer-js: v1).
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 53f58cea-d7de-443e-99c8-f400b825c50e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/release-flow-v1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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