| 1 | # Release Checklist |
| 2 | |
| 3 | A pre-tag checklist that the v0.8.21/v0.8.22 CHANGELOG gap proved we needed. |
| 4 | Step through this in order from a clean worktree on the final release source. |
| 5 | Treat any unchecked box as a release blocker. |
| 6 | |
| 7 | For deeper context on the underlying tools (preflight scripts, npm smoke, |
| 8 | publish-crates), see [`RELEASE_RUNBOOK.md`](RELEASE_RUNBOOK.md). |
| 9 | For larger milestone releases, add any version-specific acceptance matrix to |
| 10 | the release branch before tagging; use it for provider routes, feature gates, |
| 11 | GUI/runtime smoke, remote-workbench decisions, and credit hygiene that the |
| 12 | generic checklist does not enumerate. |
| 13 | |
| 14 | ## 0. Release source is frozen |
| 15 | |
| 16 | - [ ] The live milestone and PR queue no longer contain work intended for this |
| 17 | version: |
| 18 | ``` |
| 19 | gh issue list --repo Hmbown/CodeWhale --milestone "vX.Y.Z" --state open |
| 20 | gh pr list --repo Hmbown/CodeWhale --state open --limit 100 |
| 21 | ``` |
| 22 | - [ ] Any remaining same-theme work is explicitly retargeted to a later |
| 23 | version or called out as a known issue. Do not bump/tag while still |
| 24 | planning to merge more same-version fixes. |
| 25 | - [ ] The release tag does not already point at an older source SHA, or the |
| 26 | maintainer has deliberately chosen to publish exactly that older SHA: |
| 27 | ``` |
| 28 | git ls-remote origin refs/heads/main refs/tags/vX.Y.Z |
| 29 | gh release view vX.Y.Z --repo Hmbown/CodeWhale |
| 30 | ./scripts/release/check-published.sh X.Y.Z |
| 31 | ``` |
| 32 | - [ ] If `vX.Y.Z` exists with no GitHub Release/packages and `main` has moved |
| 33 | on, stop. Choose one of: publish the existing tag as-is, bump the later |
| 34 | work to the next patch version, or explicitly approve deleting/recreating |
| 35 | the unpublished tag. Do not silently move tags during PR cleanup. |
| 36 | |
| 37 | ## 1. CHANGELOG entry exists for the version |
| 38 | |
| 39 | - [ ] `CHANGELOG.md` has a `## [X.Y.Z] - YYYY-MM-DD` heading at the top |
| 40 | - [ ] The entry credits every external contributor, harvested PR author, |
| 41 | linked issue reporter, reproduction/log provider, reviewer, and |
| 42 | verification helper whose work materially shaped this version. Get the |
| 43 | commit list with: |
| 44 | ``` |
| 45 | git log vPREV..HEAD --no-merges --format="%h %an <%ae> %s" \ |
| 46 | | grep -v '<your-email@…>' |
| 47 | ``` |
| 48 | For each contributor, link both their display name and (when known) |
| 49 | `@github-handle`. Then inspect linked issues and harvested PRs so |
| 50 | reporters/helpers are not lost just because they did not author commits. |
| 51 | - [ ] The entry uses the Keep a Changelog headers — `Added`, `Changed`, |
| 52 | `Fixed`, `Security`, `Removed`, `Deprecated`. Add `Known issues` only |
| 53 | if there is something material the user must work around. |
| 54 | - [ ] The entry mentions all referenced issue/PR numbers as `#NNNN` so the |
| 55 | auto-linker on GitHub picks them up. |
| 56 | - [ ] Run `scripts/sync-changelog.sh` to regenerate `crates/tui/CHANGELOG.md` |
| 57 | (the recent-releases slice embedded in the binary for `/change`). Do |
| 58 | not edit that file by hand, and do not copy the full root changelog |
| 59 | into it — older entries live in `docs/CHANGELOG_ARCHIVE.md`. |
| 60 | |
| 61 | ## 2. Version pins are in sync |
| 62 | |
| 63 | - [ ] Run `./scripts/release/prepare-release.sh X.Y.Z` — it bumps the |
| 64 | workspace version, every per-crate dependency pin, |
| 65 | `npm/codewhale/package.json` (`version` + `codewhaleBinaryVersion`), |
| 66 | the README install-tag examples, refreshes `Cargo.lock`, regenerates |
| 67 | `crates/tui/CHANGELOG.md` and `web/lib/facts.generated.ts`, and ends |
| 68 | by running the version and OHOS gates. Write the CHANGELOG entry |
| 69 | **before** running it. The helper is safe to rerun at the requested |
| 70 | workspace version; it skips replacements but refreshes both generated |
| 71 | files and reruns the gates. |
| 72 | - [ ] `npm/deepseek-tui/package.json` remains private/compatibility-only and |
| 73 | is **not** bumped or published. |
| 74 | - [ ] `./scripts/release/check-versions.sh` reports |
| 75 | `Version state OK: workspace=X.Y.Z, npm=X.Y.Z, lockfile in sync.` |
| 76 | - [ ] `./scripts/release/check-ohos-deps.sh` reports that the OpenHarmony |
| 77 | Windows linker keeps the target/sysroot flags, the target enables the |
| 78 | `rquickjs-sys` bindgen edge, and its graph does not pull the unsupported |
| 79 | `nix` 0.28/0.29, `portable-pty`, `starlark`, `arboard`, or `keyring` |
| 80 | crates. |
| 81 | |
| 82 | ## 3. Preflight gates |
| 83 | |
| 84 | Run, in order, from the repo root: |
| 85 | |
| 86 | - [ ] `cargo fmt --all -- --check` |
| 87 | - [ ] `cargo check --workspace --all-targets --locked` |
| 88 | - [ ] `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` |
| 89 | - [ ] `cargo test --workspace --all-features --locked` |
| 90 | (Re-run any single failure in isolation with |
| 91 | `cargo test -p PKG --bin BIN -- TEST_NAME` before declaring it a flake. |
| 92 | Tests that mutate process-wide state — `HOME`, `cwd`, `RUST_LOG` — |
| 93 | can race in parallel. Document confirmed flakes in `Known issues`.) |
| 94 | - [ ] `./scripts/release/publish-crates.sh dry-run` |
| 95 | |
| 96 | ## 4. npm wrapper smoke |
| 97 | |
| 98 | - [ ] `cargo build --release --locked -p codewhale-cli -p codewhale-tui` |
| 99 | - [ ] `node scripts/release/npm-wrapper-smoke.js` |
| 100 | (Set `DEEPSEEK_TUI_KEEP_SMOKE_DIR=1` if you need to inspect the temp |
| 101 | install afterwards.) |
| 102 | |
| 103 | ## 5. Branch and PR |
| 104 | |
| 105 | - [ ] Branch is pushed: `git push -u origin work/vX.Y.Z-...` |
| 106 | - [ ] PR opened with `gh pr create --base main --title "chore(release): prepare vX.Y.Z"` |
| 107 | - [ ] The PR targets `main` and will be merged before any `vX.Y.Z` tag is |
| 108 | pushed. Do not tag a release-only branch; GitHub will not process |
| 109 | `Closes #N` keywords until those commits reach the default branch. |
| 110 | - [ ] PR body includes: |
| 111 | - one-paragraph summary of the release theme |
| 112 | - a punch list of the new commits since the last release |
| 113 | - explicit call-out of any **Security** items so reviewers see them |
| 114 | - the contributor thank-you list |
| 115 | - the `Known issues` block from the CHANGELOG, if any |
| 116 | - [ ] PR title is **neutral** — do not put CVE-style language or specific |
| 117 | attack details in the title. Save those for the GitHub release notes |
| 118 | after the tag is pushed. |
| 119 | |
| 120 | ## 5b. Branch hygiene (post-merge) |
| 121 | |
| 122 | After the release/integration merge lands, make it obvious where the release |
| 123 | tip lives and clean up stale branches **safely**. A working checkout left on a |
| 124 | scratch/renovate branch (even when `HEAD` already matches the tag) creates |
| 125 | release anxiety: contributors cannot tell whether their work merged. |
| 126 | |
| 127 | - [ ] Run the dry-run report first (read-only, deletes nothing): |
| 128 | |
| 129 | ```sh |
| 130 | ./scripts/release/branch-hygiene.sh --release-branch codex/vX.Y.Z |
| 131 | ``` |
| 132 | |
| 133 | It prints: the current checkout branch, the local + remote release tips, |
| 134 | and the main ref; the branches that are **safe to delete** (tip already |
| 135 | contained in the configured main ref or the release branch); and a |
| 136 | **keep / needs review** list naming each branch, its unique commit count, |
| 137 | the author(s), and the keep reason. The summary line reports how many are |
| 138 | safe-deletes, how many were kept for contributor work, and how many need a |
| 139 | human decision. A diverged local/remote release tip exits non-zero. Use |
| 140 | `--remote upstream` when the canonical release refs live on `upstream` |
| 141 | instead of `origin`. |
| 142 | - [ ] If the working checkout is parked on a stale branch, switch to the |
| 143 | release branch and fast-forward it: |
| 144 | |
| 145 | ```sh |
| 146 | git switch codex/vX.Y.Z |
| 147 | git fetch origin && git merge --ff-only origin/codex/vX.Y.Z # if behind |
| 148 | ``` |
| 149 | - [ ] Only after reviewing the dry-run, delete the **safe** branches. Local |
| 150 | first; add `--prune-remote` to also delete remote safe-deletes: |
| 151 | |
| 152 | ```sh |
| 153 | ./scripts/release/branch-hygiene.sh --release-branch codex/vX.Y.Z --prune --yes |
| 154 | ``` |
| 155 | |
| 156 | The script **never** auto-deletes a branch with unique commits from a |
| 157 | contributor other than Hunter unless that work is already merged. Those |
| 158 | land in the keep/review list with author and reason; review, merge, |
| 159 | harvest with credit, or explicitly preserve them before removing the |
| 160 | branch. When in doubt, leave the branch and record the decision. |
| 161 | |
| 162 | ## 6. CI green and review |
| 163 | |
| 164 | - [ ] All required CI jobs are green. The `versions` job should mirror the |
| 165 | preflight `check-versions.sh` and is your last line of defense. |
| 166 | - [ ] After the final source reaches `main`, dispatch exact-head full CI and the |
| 167 | non-publishing release-candidate build with the same 40-character SHA: |
| 168 | ```bash |
| 169 | candidate_sha="$(git rev-parse origin/main)" |
| 170 | gh workflow run ci.yml --ref main -f expected_sha="${candidate_sha}" |
| 171 | gh workflow run release-candidate.yml --ref main -f expected_sha="${candidate_sha}" |
| 172 | ``` |
| 173 | Both runs must resolve to that SHA. The candidate must report all seven |
| 174 | targets and the complete 34-file asset inventory, including Android |
| 175 | arm64, Windows arm64, `codew`, the NSIS installer, archives, and checksum |
| 176 | manifests. These are Actions artifacts only and are not a release. |
| 177 | - [ ] PR has been reviewed. |
| 178 | |
| 179 | ## 7. Tag and release (after review) |
| 180 | |
| 181 | - [ ] Release PR is merged into `main`, then local `main` is fast-forwarded: |
| 182 | `git switch main && git fetch origin main && git merge --ff-only origin/main` |
| 183 | - [ ] The release source is reachable from `main`: |
| 184 | `./scripts/release/ensure-release-on-main.sh HEAD` |
| 185 | - [ ] Create `vX.Y.Z` from the final `main` SHA using the **Create release tag** |
| 186 | workflow, or create and push a signed local tag: |
| 187 | `git tag -s vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z` |
| 188 | - [ ] The `release.yml` workflow has built and uploaded artifacts to the |
| 189 | GitHub release for this tag. |
| 190 | - [ ] The public GitHub Release assets are proven to match the tag commit |
| 191 | before publishing Cargo or npm: |
| 192 | ``` |
| 193 | ./scripts/release/verify-release-assets.sh X.Y.Z |
| 194 | ``` |
| 195 | This checks the local tag, remote tag, successful Release workflow SHA, |
| 196 | full binary/archive/installer asset set, and both checksum manifests. If |
| 197 | it fails, rerun or repair the GitHub Release workflow before touching any |
| 198 | registry. |
| 199 | - [ ] The live GitHub Release body has its own `## Contributors` or |
| 200 | `## Credits` section; do not rely on "see CHANGELOG" alone. Verify with: |
| 201 | ``` |
| 202 | gh release view vX.Y.Z --repo Hmbown/CodeWhale --json body \ |
| 203 | --jq '.body | test("## (Contributors|Credits)")' |
| 204 | ``` |
| 205 | - [ ] `npm view codewhale@X.Y.Z version codewhaleBinaryVersion --json` |
| 206 | reports the new version on the npm registry. |
| 207 | - [ ] `npm view deepseek-tui deprecated` is non-empty. The legacy npm package |
| 208 | is deprecated and must not receive an `X.Y.Z` publish. |
| 209 | - [ ] Distribution channels are canonical-first: the website install page |
| 210 | (codewhale.net/install) shows Codewhale-native commands first (`npm install -g |
| 211 | codewhale`, `curl .../install.sh | sh`); Homebrew is labeled as legacy |
| 212 | compatibility; the shell installer uses codewhale-native names as documented |
| 213 | in `docs/REBRAND.md#homebrew`. |
| 214 | - [ ] `crates.io` has the new version (or the `publish-crates.sh` job has |
| 215 | pushed it). |
| 216 | - [ ] `ghcr.io/hmbown/codewhale:vX.Y.Z` and `:latest` are updated. |
| 217 | - [ ] The final registry verification passes: |
| 218 | ``` |
| 219 | ./scripts/release/check-published.sh X.Y.Z |
| 220 | ``` |
| 221 | |
| 222 | ## 8. Post-tag |
| 223 | |
| 224 | - [ ] Edit the GitHub release notes to expand any CVE-style or attack |
| 225 | details that were intentionally omitted from the PR title/body. |
| 226 | - [ ] Re-run the GitHub Release body check after any release-workflow rerun; |
| 227 | workflows can overwrite notes and accidentally remove contributor credit. |
| 228 | - [ ] Note any deferred items in the next release's tracking issue. |
| 229 | - [ ] Close any issues that this release fixed. |
| 230 | |
| 231 | --- |
| 232 | |
| 233 | If a step fails, **fix the underlying cause** rather than skipping it. Pre-commit |
| 234 | hooks, signing, and CI are all here to catch real problems. `--no-verify`, |
| 235 | `--no-gpg-sign`, and force-pushing a release branch over reviewers should |
| 236 | remain hard-disabled by convention. |
| 237 |