From d89a51666678a76a0da626f2650d5e7f6d55618e Mon Sep 17 00:00:00 2001 From: Abdullah Hashim Date: Tue, 13 Oct 2026 08:44:04 -0400 Subject: [PATCH] Add /prepare-release command to scaffold gem release prep Ports the release-prep command from a11y-lint and un-ignores .claude/ so the command and the existing testing rules are tracked, as in a11y-lint. --- .claude/commands/prepare-release.md | 55 +++++++++++++++++++++++++++++ .claude/rules/testing.md | 8 +++++ .gitignore | 3 ++ 3 files changed, 66 insertions(+) create mode 100644 .claude/commands/prepare-release.md create mode 100644 .claude/rules/testing.md diff --git a/.claude/commands/prepare-release.md b/.claude/commands/prepare-release.md new file mode 100644 index 0000000..31061c8 --- /dev/null +++ b/.claude/commands/prepare-release.md @@ -0,0 +1,55 @@ +--- +description: Scaffold gem release prep — preflight, bump, verify, then push a release branch and open a PR +argument-hint: [patch|minor|major|X.Y.Z] +allowed-tools: Bash(git status:*), Bash(git fetch:*), Bash(git log:*), Bash(git diff:*), Bash(git tag:*), Bash(git rev-parse:*), Bash(git rev-list:*), Bash(git branch:*), Bash(git switch:*), Bash(git restore:*), Bash(git add:*), Bash(git commit:*), Bash(git push:*), Bash(gh pr create:*), Bash(gh pr view:*), Bash(bundle install:*), Bash(bundle exec:*), Bash(grep:*), Bash(rg:*), Bash(ls:*), Bash(date:*), Read, Edit, Write, Glob, Grep +--- + +Prepare a gem release. Bump kind: **$ARGUMENTS** (empty = infer from commits since last tag). + +End state: a `release-X.Y.Z` branch pushed to origin with an open PR titled `Release X.Y.Z` and body `🎉`. The PR diff is the review surface — the CHANGELOG is the release notes. + +The user runs the irreversible steps after the PR merges. **Never** run `bundle exec rake release`, `gem push pkg/minitest-attributes-X.Y.Z.gem`, or `git tag vX.Y.Z && git push origin vX.Y.Z`. + +## Preflight + +Bail loudly on any failure — don't try to fix state silently. + +- On `main`, working tree clean, not behind `origin/main` (`git fetch origin main` then `git rev-list --count HEAD..origin/main` → `0`). +- `lib/minitest/attributes/version.rb` `VERSION`, `Gemfile.lock`'s `minitest-attributes (X.Y.Z)` line under `PATH → specs:`, and the latest `git tag --sort=-v:refname | head -1` (stripped of leading `v`) all agree. A mismatch usually means a prior release was half-finished — surface it and stop. + +## Bump + +If `$ARGUMENTS` is empty, infer from `git log ..HEAD`: + +- Any commit subject containing `Breaking`, or starting with `Add ` or `Change ` → **minor** +- Otherwise → **patch** + +This gem is pre-1.0; breaking changes still bump the minor (no major path). Print the inferred bump and the resulting `X.Y.Z`, then proceed without confirming. + +If `$ARGUMENTS` is `patch`/`minor`/`major`, bump that segment. If it's `X.Y.Z`, use literally. Anything else → bail. + +## Apply + +1. Edit `lib/minitest/attributes/version.rb` — replace the `VERSION = "..."` literal. +2. Edit `CHANGELOG.md` — insert `## [X.Y.Z] - YYYY-MM-DD` (today, absolute via `date +%Y-%m-%d`) directly below `## [Unreleased]` with blank lines around it. The Unreleased entries shift down to attribute the new release; the new Unreleased block stays empty. +3. `bundle install` — should change only `Gemfile.lock`'s `minitest-attributes (X.Y.Z)` line. Surface anything else. + +## Verify + +`bundle exec rake` — tests + RuboCop. Bail on red. + +## Shape check + +`git diff --stat` should touch only `lib/minitest/attributes/version.rb`, `CHANGELOG.md`, `Gemfile.lock`. Anything else is a red flag — stop and ask before pushing. + +## Branch + PR + +``` +git switch -c release-X.Y.Z +git add lib/minitest/attributes/version.rb CHANGELOG.md Gemfile.lock +git commit -m "Release X.Y.Z" +git push -u origin release-X.Y.Z +gh pr create --title "Release X.Y.Z" --body "🎉" +``` + +Print the PR URL. diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md new file mode 100644 index 0000000..5cdac76 --- /dev/null +++ b/.claude/rules/testing.md @@ -0,0 +1,8 @@ +--- +description: Rules for writing tests +globs: test/**/*.rb +--- + +- Do not use `setup` methods. Create the necessary objects inline within each test method. +- Use plain `Struct`s or small classes as records; the gem must not depend on ActiveRecord or ActiveSupport to be tested. +- Every branch of `assert_attributes` (plain, nil, Time, rich text) needs both a passing case and a failing case that checks the failure message. diff --git a/.gitignore b/.gitignore index 9106b2a..aee2e0d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ /pkg/ /spec/reports/ /tmp/ + +!.claude/ +.claude/settings.local.json