Files
get-shit-done/VERSIONING.md
Tom Boucher 85316d62d5 feat: 3-tier release strategy with hotfix, release, and CI workflows (#1289)
* feat: 3-tier release strategy with hotfix, release, and CI workflows

Supersedes PRs #1208 and #1210 with a consolidated approach:

- VERSIONING.md: Strategy document with 3 release tiers (patch/minor/major)
- hotfix.yml: Emergency patch releases to latest
- release.yml: Standard release cycle with RC/beta pre-releases to next
- auto-branch.yml: Create branches from issue labels
- branch-naming.yml: Convention validation (advisory)
- pr-gate.yml: PR size analysis and labeling
- stale.yml: Weekly cleanup of inactive issues/PRs
- dependabot.yml: Automated dependency updates

npm dist-tags: latest (stable) and next (pre-release) only,
following Angular/Next.js convention.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review findings for release workflow security and correctness

- Move all ${{ }} expression interpolation from run: blocks into env: mappings
  in both hotfix.yml (~12 instances) and release.yml (~16 instances) to prevent
  potential command injection via GitHub Actions expression evaluation
- Reorder rc job in release.yml to run npm ci and test:coverage before pushing
  the git tag, preventing broken tagged commits when tests fail
- Update VERSIONING.md to accurately describe the implementation: major releases
  use beta pre-releases only, minor releases use rc pre-releases only (no
  beta-then-rc progression)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* security: harden release workflows — SHA pinning, provenance, dry-run guards

Addresses deep adversarial review + best practices research:

HIGH:
- Fix release.yml rc/finalize: dry_run now gates tag+push (not just npm publish)
- Fix hotfix.yml finalize: reorder tag-before-publish (was publish-before-tag)

MEDIUM — Security hardening:
- Pin ALL actions to SHA hashes (actions/checkout@11bd7190,
  actions/setup-node@39370e39, actions/github-script@60a0d830)
- Add --provenance --access public to all npm publish commands
- Add id-token: write permission for npm provenance OIDC
- Add concurrency groups (cancel-in-progress: false) on both workflows
- Add branch-naming.yml permissions: {} (deny-all default)
- Scope permissions per-job instead of workflow-level where possible

MEDIUM — Reliability:
- Add post-publish verification (npm view + dist-tag check) after every publish
- Add npm publish --dry-run validation step before actual publish
- Add branch existence pre-flight check in create jobs

LOW:
- Fix VERSIONING.md Semver Rules: MINOR = "enhancements" not "new features"
  (aligns with Release Tiers table)

Tests: 1166/1166 pass

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* security: pin actions/stale to SHA hash

Last remaining action using a mutable version tag. Now all actions
across all workflow files are pinned to immutable SHA hashes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address all Copilot review findings on release strategy workflows

- Configure git identity in all committing jobs (hotfix + release)
- Base hotfix on latest patch tag instead of vX.Y.0
- Add issues: write permission for PR size labeling
- Remove stale size labels before adding new one
- Make tagging and PR creation idempotent for reruns
- Run dry-run publish validation unconditionally
- Paginate listFiles for large PRs
- Fix VERSIONING.md table formatting and docs accuracy

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: clean up next dist-tag after finalize in release and hotfix workflows

After finalizing a release, the next dist-tag was left pointing at the
last RC pre-release. Anyone running npm install @next would get a stale
version older than @latest. Now both workflows point next to the stable
release after finalize, matching Angular/Next.js convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(ci): address blocking issues in 3-tier release workflows

- Move back-merge PR creation before npm publish in hotfix/release finalize
- Move version bump commit after test step in rc workflow
- Gate hotfix create branch push behind dry_run check
- Add confirmed-bug and confirmed to stale.yml exempt labels
- Fix auto-branch priority: critical prefix collision with hotfix/ naming

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 23:08:31 -04:00

5.2 KiB

Versioning & Release Strategy

GSD follows Semantic Versioning 2.0.0 with three release tiers mapped to npm dist-tags.

Release Tiers

Tier What ships Version format npm tag Branch Install
Patch Bug fixes only 1.27.1 latest hotfix/1.27.1 npx get-shit-done-cc@latest
Minor Fixes + enhancements 1.28.0 latest (after RC) release/1.28.0 npx get-shit-done-cc@next (RC)
Major Fixes + enhancements + features 2.0.0 latest (after beta) release/2.0.0 npx get-shit-done-cc@next (beta)

npm Dist-Tags

Only two tags, following Angular/Next.js convention:

Tag Meaning Installed by
latest Stable production release npm install get-shit-done-cc (default)
next Pre-release (RC or beta) npm install get-shit-done-cc@next (opt-in)

The version string (-rc.1 vs -beta.1) communicates stability level. Users never get pre-releases unless they explicitly opt in.

Semver Rules

Increment When Examples
PATCH (1.27.x) Bug fixes, typo corrections, test additions Hook filter fix, config corruption fix
MINOR (1.x.0) Non-breaking enhancements, new commands, new runtime support New workflow command, discuss-mode feature
MAJOR (x.0.0) Breaking changes to config format, CLI flags, or runtime API; new features that alter existing behavior Removing a command, changing config schema

Pre-Release Version Progression

Major and minor releases use different pre-release types:

Minor: 1.28.0-rc.1  →  1.28.0-rc.2  →  1.28.0
Major: 2.0.0-beta.1 →  2.0.0-beta.2 →  2.0.0
  • beta (major releases only): Feature-complete but not fully tested. API mostly stable. Used for major releases to signal a longer testing cycle.
  • rc (minor releases only): Production-ready candidate. Only critical fixes expected.
  • Each version uses one pre-release type throughout its cycle. The rc action in the release workflow automatically selects the correct type based on the version.

Branch Structure

main                              ← stable, always deployable
  │
  ├── hotfix/1.27.1               ← patch: cherry-pick fix from main, publish to latest
  │
  ├── release/1.28.0              ← minor: accumulate fixes + enhancements, RC cycle
  │     ├── v1.28.0-rc.1          ← tag: published to next
  │     └── v1.28.0               ← tag: promoted to latest
  │
  ├── release/2.0.0               ← major: features + breaking changes, beta cycle
  │     ├── v2.0.0-beta.1         ← tag: published to next
  │     ├── v2.0.0-beta.2         ← tag: published to next
  │     └── v2.0.0                ← tag: promoted to latest
  │
  ├── fix/1200-bug-description    ← bug fix branch (merges to main)
  ├── feat/925-feature-name       ← feature branch (merges to main)
  └── chore/1206-maintenance      ← maintenance branch (merges to main)

Release Workflows

Patch Release (Hotfix)

For critical bugs that can't wait for the next minor release.

  1. Trigger hotfix.yml with version (e.g., 1.27.1)
  2. Workflow creates hotfix/1.27.1 branch from the latest patch tag for that minor version (e.g., v1.27.0 or v1.27.1)
  3. Cherry-pick or apply fix on the hotfix branch
  4. Push — CI runs tests automatically
  5. Trigger hotfix.yml finalize action
  6. Workflow runs full test suite, bumps version, tags, publishes to latest
  7. Merge hotfix branch back to main

Minor Release (Standard Cycle)

For accumulated fixes and enhancements.

  1. Trigger release.yml with action create and version (e.g., 1.28.0)
  2. Workflow creates release/1.28.0 branch from main, bumps package.json
  3. Trigger release.yml with action rc to publish 1.28.0-rc.1 to next
  4. Test the RC: npx get-shit-done-cc@next
  5. If issues found: fix on release branch, publish rc.2, rc.3, etc.
  6. Trigger release.yml with action finalize — publishes 1.28.0 to latest
  7. Merge release branch to main

Major Release

Same as minor but uses -beta.N instead of -rc.N, signaling a longer testing cycle.

  1. Trigger release.yml with action create and version (e.g., 2.0.0)
  2. Trigger release.yml with action rc to publish 2.0.0-beta.1 to next
  3. If issues found: fix on release branch, publish beta.2, beta.3, etc.
  4. Trigger release.yml with action finalize -- publishes 2.0.0 to latest
  5. Merge release branch to main

Conventional Commits

Branch names map to commit types:

Branch prefix Commit type Version bump
fix/ fix: PATCH
feat/ feat: MINOR
hotfix/ fix: PATCH (immediate)
chore/ chore: none
docs/ docs: none
refactor/ refactor: none

Publishing Commands (Reference)

# Stable release (sets latest tag automatically)
npm publish

# Pre-release (must use --tag to avoid overwriting latest)
npm publish --tag next

# Verify what latest and next point to
npm dist-tag ls get-shit-done-cc