|
| 1 | +# Release Candidate Process |
| 2 | + |
| 3 | +This document defines the release candidate (RC) checklist for morph releases, including documentation review, migration notes, and rollback procedures. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Table of Contents |
| 8 | + |
| 9 | +- [Overview](#overview) |
| 10 | +- [RC Lifecycle](#rc-lifecycle) |
| 11 | +- [RC1 Checklist](#rc1-checklist) |
| 12 | +- [RC2 Checklist](#rc2-checklist) |
| 13 | +- [Sign-Off Criteria](#sign-off-criteria) |
| 14 | +- [Release Procedure](#release-procedure) |
| 15 | +- [Rollback Plan](#rollback-plan) |
| 16 | +- [Post-Release](#post-release) |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Overview |
| 21 | + |
| 22 | +morph follows [Semantic Versioning](https://semver.org/). Each minor release goes through at least one Release Candidate (RC) cycle before the final release. The RC process ensures quality, compatibility, and documentation are production-ready. |
| 23 | + |
| 24 | +### Versioning Scheme |
| 25 | + |
| 26 | +- **RC tags:** `v0.X.0-rc.1`, `v0.X.0-rc.2`, … |
| 27 | +- **Final release:** `v0.X.0` |
| 28 | +- RCs are published as GitHub pre-releases (not promoted to `latest`). |
| 29 | + |
| 30 | +--- |
| 31 | + |
| 32 | +## RC Lifecycle |
| 33 | + |
| 34 | +``` |
| 35 | +main ──► RC1 tag ──► testing/feedback ──► RC2 tag (if needed) ──► final tag |
| 36 | + │ │ |
| 37 | + └── fix on main, cherry-pick ─────┘ |
| 38 | +``` |
| 39 | + |
| 40 | +1. **Feature freeze** — all planned features merged to `main`. |
| 41 | +2. **RC1** — first candidate tagged; testing begins. |
| 42 | +3. **Feedback window** — minimum 3 days for RC1, 2 days for subsequent RCs. |
| 43 | +4. **RC2+** — only if blocking issues found in previous RC. |
| 44 | +5. **Final release** — when an RC passes all sign-off criteria. |
| 45 | + |
| 46 | +--- |
| 47 | + |
| 48 | +## RC1 Checklist |
| 49 | + |
| 50 | +### Code Quality |
| 51 | + |
| 52 | +- [ ] All CI checks pass on `main` (stable + nightly, all OS targets) |
| 53 | +- [ ] No open issues labeled `blocker` or `critical` |
| 54 | +- [ ] `cargo clippy --all-targets --all-features -- -D warnings` clean |
| 55 | +- [ ] `cargo fmt --all -- --check` clean |
| 56 | +- [ ] `cargo test` — all tests pass |
| 57 | +- [ ] Golden conformance suite passes (`tests/golden_conformance.rs`) |
| 58 | + |
| 59 | +### Documentation |
| 60 | + |
| 61 | +- [ ] `README.md` — feature table, install instructions, and examples are current |
| 62 | +- [ ] `docs/MAPPING_LANGUAGE.md` — all operations and functions documented |
| 63 | +- [ ] `docs/INSTALLATION.md` — all install methods verified |
| 64 | +- [ ] `docs/MIGRATION.md` — jq/yq/mlr recipes updated for any new features |
| 65 | +- [ ] `CHANGELOG.md` — unreleased section reviewed and accurate |
| 66 | +- [ ] `CONTRIBUTING.md` — project structure and guidelines current |
| 67 | +- [ ] Inline help (`morph --help`, `morph --formats`, `morph --functions`) matches docs |
| 68 | + |
| 69 | +### Migration & Compatibility |
| 70 | + |
| 71 | +- [ ] Breaking changes documented in `CHANGELOG.md` with migration steps |
| 72 | +- [ ] `docs/MIGRATION.md` covers any new operations or changed behavior |
| 73 | +- [ ] Compatibility matrix CI passes (all OS × toolchain combinations) |
| 74 | +- [ ] Minimum Supported Rust Version (MSRV) documented if changed |
| 75 | + |
| 76 | +### Performance |
| 77 | + |
| 78 | +- [ ] Benchmark suite runs without errors (`cargo bench`) |
| 79 | +- [ ] No significant regressions vs. previous release snapshot |
| 80 | +- [ ] `bench-results/` snapshot generated and committed |
| 81 | +- [ ] README performance table updated if numbers changed materially |
| 82 | + |
| 83 | +### Release Infrastructure |
| 84 | + |
| 85 | +- [ ] `Cargo.toml` version bumped to target version (e.g., `0.6.0`) |
| 86 | +- [ ] `dist-workspace.toml` configuration reviewed |
| 87 | +- [ ] `release-plz.toml` configuration reviewed |
| 88 | +- [ ] `cliff.toml` changelog configuration current |
| 89 | +- [ ] GitHub Actions workflows (`ci.yml`, `bench.yml`, `release.yml`) current |
| 90 | + |
| 91 | +### Tag & Publish RC1 |
| 92 | + |
| 93 | +```bash |
| 94 | +# Ensure main is clean and up to date |
| 95 | +git checkout main && git pull |
| 96 | + |
| 97 | +# Tag the RC |
| 98 | +git tag -a v0.X.0-rc.1 -m "v0.X.0 Release Candidate 1" |
| 99 | +git push origin v0.X.0-rc.1 |
| 100 | +``` |
| 101 | + |
| 102 | +The `release.yml` workflow will build artifacts and create a GitHub pre-release. |
| 103 | + |
| 104 | +--- |
| 105 | + |
| 106 | +## RC2 Checklist |
| 107 | + |
| 108 | +RC2 is only needed if blocking issues were found in RC1. |
| 109 | + |
| 110 | +### Fixes |
| 111 | + |
| 112 | +- [ ] All RC1 feedback issues resolved |
| 113 | +- [ ] Fixes merged to `main` with tests |
| 114 | +- [ ] No new features — only bug fixes and doc corrections |
| 115 | + |
| 116 | +### Verification |
| 117 | + |
| 118 | +- [ ] Full CI passes on `main` |
| 119 | +- [ ] Golden conformance suite passes |
| 120 | +- [ ] Benchmark suite shows no new regressions |
| 121 | +- [ ] Fixed issues verified manually |
| 122 | + |
| 123 | +### Documentation |
| 124 | + |
| 125 | +- [ ] `CHANGELOG.md` updated with RC1→RC2 fixes |
| 126 | +- [ ] Any doc corrections from RC1 feedback applied |
| 127 | + |
| 128 | +### Tag & Publish RC2 |
| 129 | + |
| 130 | +```bash |
| 131 | +git tag -a v0.X.0-rc.2 -m "v0.X.0 Release Candidate 2" |
| 132 | +git push origin v0.X.0-rc.2 |
| 133 | +``` |
| 134 | + |
| 135 | +--- |
| 136 | + |
| 137 | +## Sign-Off Criteria |
| 138 | + |
| 139 | +A release candidate is approved for final release when **all** of the following are met: |
| 140 | + |
| 141 | +| Criterion | Description | |
| 142 | +|-----------|-------------| |
| 143 | +| **CI Green** | All matrix cells pass (3 OS × 2 toolchains) | |
| 144 | +| **Zero Blockers** | No open issues labeled `blocker` or `critical` | |
| 145 | +| **Conformance** | Golden conformance suite 100% pass | |
| 146 | +| **Performance** | No regression >10% vs. previous release | |
| 147 | +| **Docs Complete** | All user-facing docs reviewed and accurate | |
| 148 | +| **Feedback Window** | Minimum soak time elapsed (3 days RC1, 2 days RC2+) | |
| 149 | +| **Breaking Changes** | All breaking changes documented with migration path | |
| 150 | +| **Changelog** | `CHANGELOG.md` reviewed and finalized | |
| 151 | + |
| 152 | +--- |
| 153 | + |
| 154 | +## Release Procedure |
| 155 | + |
| 156 | +Once an RC is signed off: |
| 157 | + |
| 158 | +### 1. Finalize Changelog |
| 159 | + |
| 160 | +```bash |
| 161 | +# Generate changelog from commits |
| 162 | +git cliff --tag v0.X.0 -o CHANGELOG.md |
| 163 | + |
| 164 | +# Review and edit if needed |
| 165 | +$EDITOR CHANGELOG.md |
| 166 | + |
| 167 | +git add CHANGELOG.md |
| 168 | +git commit -m "docs: finalize changelog for v0.X.0" |
| 169 | +git push origin main |
| 170 | +``` |
| 171 | + |
| 172 | +### 2. Tag Final Release |
| 173 | + |
| 174 | +```bash |
| 175 | +git tag -a v0.X.0 -m "v0.X.0" |
| 176 | +git push origin v0.X.0 |
| 177 | +``` |
| 178 | + |
| 179 | +### 3. Verify Release Artifacts |
| 180 | + |
| 181 | +The `release.yml` workflow will: |
| 182 | +- Build binaries for all target platforms |
| 183 | +- Create a GitHub Release with artifacts |
| 184 | +- Publish the Homebrew formula to `alvinreal/homebrew-tap` |
| 185 | +- `release-plz` will handle crates.io publishing |
| 186 | + |
| 187 | +Verify: |
| 188 | +- [ ] GitHub Release page has all platform binaries |
| 189 | +- [ ] Install script works: `curl ... | sh` |
| 190 | +- [ ] `cargo binstall morph` works (after crates.io publish) |
| 191 | +- [ ] `brew install alvinreal/tap/morph` works (after Homebrew publish) |
| 192 | + |
| 193 | +### 4. Announce |
| 194 | + |
| 195 | +- [ ] GitHub Release notes are clear and complete |
| 196 | +- [ ] Update any external links or documentation sites |
| 197 | + |
| 198 | +--- |
| 199 | + |
| 200 | +## Rollback Plan |
| 201 | + |
| 202 | +If a critical issue is discovered after a final release: |
| 203 | + |
| 204 | +### Severity Assessment |
| 205 | + |
| 206 | +| Severity | Action | Timeline | |
| 207 | +|----------|--------|----------| |
| 208 | +| **Critical** (data loss, crashes on valid input) | Yank + patch release | Immediate | |
| 209 | +| **High** (incorrect output, security issue) | Patch release | Within 24h | |
| 210 | +| **Medium** (edge case bugs, doc errors) | Next minor release | Normal cycle | |
| 211 | +| **Low** (cosmetic, minor UX) | Next minor release | Normal cycle | |
| 212 | + |
| 213 | +### Yank Procedure (Critical Only) |
| 214 | + |
| 215 | +```bash |
| 216 | +# 1. Yank the crates.io release |
| 217 | +cargo yank --version 0.X.0 |
| 218 | + |
| 219 | +# 2. Mark GitHub Release as pre-release (hides from "latest") |
| 220 | +gh release edit v0.X.0 --prerelease |
| 221 | + |
| 222 | +# 3. Add warning to release notes |
| 223 | +gh release edit v0.X.0 --notes "⚠️ This release has been yanked due to [issue]. Please use v0.X.1 instead." |
| 224 | +``` |
| 225 | + |
| 226 | +### Patch Release |
| 227 | + |
| 228 | +```bash |
| 229 | +# 1. Create a release branch from the tag |
| 230 | +git checkout -b release/v0.X.1 v0.X.0 |
| 231 | + |
| 232 | +# 2. Cherry-pick or apply the fix |
| 233 | +git cherry-pick <fix-commit> |
| 234 | + |
| 235 | +# 3. Bump version in Cargo.toml to 0.X.1 |
| 236 | +# 4. Update CHANGELOG.md |
| 237 | +# 5. Tag and push |
| 238 | +git tag -a v0.X.1 -m "v0.X.1 — hotfix for [issue]" |
| 239 | +git push origin v0.X.1 |
| 240 | + |
| 241 | +# 6. Merge fix back to main |
| 242 | +git checkout main |
| 243 | +git merge release/v0.X.1 |
| 244 | +git push origin main |
| 245 | +``` |
| 246 | + |
| 247 | +### Homebrew Rollback |
| 248 | + |
| 249 | +If the Homebrew formula needs to revert: |
| 250 | + |
| 251 | +```bash |
| 252 | +# In the homebrew-tap repo |
| 253 | +git revert HEAD # revert the formula update |
| 254 | +git push |
| 255 | +``` |
| 256 | + |
| 257 | +### Communication |
| 258 | + |
| 259 | +For critical/high severity rollbacks: |
| 260 | +1. Update GitHub Release notes with warning |
| 261 | +2. Open a GitHub Issue documenting the problem and fix |
| 262 | +3. Reference the fix in the patch release notes |
| 263 | + |
| 264 | +--- |
| 265 | + |
| 266 | +## Post-Release |
| 267 | + |
| 268 | +After a successful release: |
| 269 | + |
| 270 | +- [ ] Verify all install methods work with the new version |
| 271 | +- [ ] Archive the benchmark snapshot for this release |
| 272 | +- [ ] Update the compatibility matrix results in the repo |
| 273 | +- [ ] Bump `Cargo.toml` version to next dev version (e.g., `0.X+1.0`) |
| 274 | +- [ ] Create the next milestone's epic issue if planned |
| 275 | +- [ ] Close the current milestone/epic |
| 276 | + |
| 277 | +--- |
| 278 | + |
| 279 | +## Quick Reference |
| 280 | + |
| 281 | +| Step | Command | |
| 282 | +|------|---------| |
| 283 | +| Run tests | `cargo test` | |
| 284 | +| Run clippy | `cargo clippy --all-targets --all-features -- -D warnings` | |
| 285 | +| Check formatting | `cargo fmt --all -- --check` | |
| 286 | +| Run benchmarks | `cargo bench` | |
| 287 | +| Generate changelog | `git cliff --tag v0.X.0 -o CHANGELOG.md` | |
| 288 | +| Tag RC | `git tag -a v0.X.0-rc.1 -m "v0.X.0 RC1"` | |
| 289 | +| Tag release | `git tag -a v0.X.0 -m "v0.X.0"` | |
| 290 | +| Yank crate | `cargo yank --version 0.X.0` | |
0 commit comments