|
| 1 | +--- |
| 2 | +name: add-changeset |
| 3 | +description: "Add a changeset to the current change. Use when preparing a PR that affects published packages, when asked to 'add a changeset' or `add cs`, or when CI reports a missing changeset. Detects monorepos and selects affected packages automatically." |
| 4 | +--- |
| 5 | + |
| 6 | +# Add Changeset |
| 7 | + |
| 8 | +A changeset declares which packages are affected by a change, the semver bump type, and a user-facing summary. It lives as a markdown file in `.changeset/` and is consumed automatically by CI to version and publish packages. |
| 9 | + |
| 10 | +## When to Add One |
| 11 | + |
| 12 | +**Add a changeset when the change:** |
| 13 | +- Fixes a bug in a published package (`patch`) |
| 14 | +- Adds a new feature or public API (`minor`) |
| 15 | +- Breaks an existing API or removes something (`major`) |
| 16 | +- Updates a dependency in a way users need to know about (`patch`) |
| 17 | + |
| 18 | +**Do nothing when:** |
| 19 | +- The change is `ci:`, `chore:`, `test:`, or an internal refactor with no API/behavior change |
| 20 | +- The only changed files are in `examples/`, `docs/`, or non-published packages (check `private: true` and `"ignore"` in `.changeset/config.json`) |
| 21 | +- The only changed files are tests or Storybook stories |
| 22 | +- The change is build-process, CI/CD, or development tooling only |
| 23 | +- The only dependency changes are `devDependencies` |
| 24 | + |
| 25 | +Tell the user no changeset is needed and why. |
| 26 | + |
| 27 | +## Steps |
| 28 | + |
| 29 | +### 1. Detect the setup |
| 30 | + |
| 31 | +```bash |
| 32 | +# Confirm changesets is initialized |
| 33 | +ls .changeset/config.json |
| 34 | +``` |
| 35 | + |
| 36 | +Read `.changeset/config.json` to find: |
| 37 | +- `"fixed"` — packages that share the exact same version; bumping one bumps all |
| 38 | +- `"linked"` — packages that share the highest bump type but keep independent versions |
| 39 | +- `"ignore"` — packages excluded from versioning |
| 40 | +- `"access"` — `"public"` means scoped packages publish publicly |
| 41 | + |
| 42 | +### 2. Identify affected packages |
| 43 | + |
| 44 | +First, determine which changes to look at: |
| 45 | + |
| 46 | +```bash |
| 47 | +# Check for staged changes |
| 48 | +git diff --cached --name-only |
| 49 | + |
| 50 | +# Check for unstaged changes |
| 51 | +git diff --name-only |
| 52 | +``` |
| 53 | + |
| 54 | +**Scope selection rules (in priority order):** |
| 55 | + |
| 56 | +1. **Staged changes exist** → use `git diff --cached --name-only` |
| 57 | +2. **Only unstaged changes exist** → use `git diff --name-only` |
| 58 | +3. **No local changes** → compare HEAD to base branch: `git diff --name-only origin/main...HEAD` |
| 59 | + |
| 60 | +In a monorepo (has `pnpm-workspace.yaml`, `workspaces` in root `package.json`, or `bun.workspace.ts`), map changed files to their owning package (find nearest `package.json` above each changed file). Apply `fixed` group rules: if any package in a fixed group is affected, all are. |
| 61 | + |
| 62 | +In a single-package repo, the root package is always the affected package. |
| 63 | + |
| 64 | +### 2a. Extract context from commit messages |
| 65 | + |
| 66 | +When scope is **no local changes** (case 3), also read recent commits for context: |
| 67 | + |
| 68 | +```bash |
| 69 | +# Commits on this branch not yet on base |
| 70 | +git log origin/main..HEAD --oneline |
| 71 | +``` |
| 72 | + |
| 73 | +Parse conventional commit prefixes to inform bump type and summary: |
| 74 | + |
| 75 | +| Prefix | Implication | |
| 76 | +|---|---| |
| 77 | +| `feat:` / `feat(scope):` | at least `minor` | |
| 78 | +| `fix:` / `fix(scope):` | at least `patch` | |
| 79 | +| `BREAKING CHANGE:` footer or `!` after type | `major` | |
| 80 | +| `chore:`, `ci:`, `test:`, `docs:` | no changeset needed | |
| 81 | + |
| 82 | +Use the commit message body / subject as a starting point for the changeset summary, rewritten to be user-facing (imperative mood, no implementation details). |
| 83 | + |
| 84 | +### 3. Determine bump type |
| 85 | + |
| 86 | +| Change type | Bump | |
| 87 | +|---|---| |
| 88 | +| Removes or renames public API, breaks existing usage | `major` | |
| 89 | +| Adds new exported function, class, option, or command | `minor` | |
| 90 | +| Bug fix, internal refactor, dependency update | `patch` | |
| 91 | + |
| 92 | +> **Pre-1.0 rule:** For packages on `0.x`, use `minor` for breaking changes — this is standard semver for pre-release packages. Only assign `major` to packages at `1.0.0` or higher. |
| 93 | +
|
| 94 | +When unsure between minor and patch, ask the user. |
| 95 | + |
| 96 | +### 4. Write the changeset file |
| 97 | + |
| 98 | +Choose a descriptive kebab-case filename that reflects the change (e.g. `fix-button-accessibility.md`, `add-retry-option.md`). Fall back to a random two-word slug (adjective + animal, e.g. `fuzzy-wolves`) when no obvious name fits or to avoid a conflict. Do not use the `changeset` CLI — write the file directly. |
| 99 | + |
| 100 | +```markdown |
| 101 | +--- |
| 102 | +"package-name": patch |
| 103 | +--- |
| 104 | + |
| 105 | +Add `retry` option to fetch client. |
| 106 | +``` |
| 107 | + |
| 108 | +- Filename: `.changeset/<name>.md` |
| 109 | +- Each affected package gets one line in the frontmatter: `"<name>": <major|minor|patch>` |
| 110 | +- For packages in a `fixed` group, list every package in the group with the same bump type |
| 111 | +- The body is the user-facing summary (see summary rules below) |
| 112 | + |
| 113 | +**Summary rules** — the body appears verbatim in `CHANGELOG.md`: |
| 114 | +- Imperative mood: "Add support for X" not "Added support for X" |
| 115 | +- User-facing: describe the effect, not the implementation |
| 116 | +- End with a period (`.`) |
| 117 | +- Wrap code identifiers (component names, prop names, function names) in backticks |
| 118 | +- One line is enough; add bullet points only for breaking changes that need migration steps |
| 119 | +- No references to internal file names or commit SHAs |
| 120 | + |
| 121 | +Good: `Add \`retry\` option to fetch client.` |
| 122 | +Bad: `Updated fetchClient.ts to handle retries in the error handler` |
| 123 | + |
| 124 | +**Breaking change example** — include migration steps in the body: |
| 125 | + |
| 126 | +```markdown |
| 127 | +--- |
| 128 | +"package-name": major |
| 129 | +--- |
| 130 | + |
| 131 | +Remove deprecated `oldOption` config key. Use `newOption` instead. |
| 132 | + |
| 133 | +Migration: |
| 134 | +- Replace `oldOption: true` with `newOption: true` |
| 135 | +``` |
| 136 | + |
| 137 | +### 5. Commit the changeset |
| 138 | + |
| 139 | +Only commit the changeset automatically when there were **no local changes** at the start (scope case 3 — branch diff). In that case: |
| 140 | + |
| 141 | +```bash |
| 142 | +git add .changeset/ |
| 143 | +git commit -m "docs: add changeset" |
| 144 | +``` |
| 145 | + |
| 146 | +If staged or unstaged changes existed (scope cases 1 or 2), tell the user the changeset file has been created and let them include it in their own commit. |
| 147 | + |
| 148 | +## What Happens Next (don't intervene) |
| 149 | + |
| 150 | +Once the changeset is merged to the base branch, the CI release workflow (`changesets/action`) will automatically: |
| 151 | +1. Open or update a **"Version Packages"** PR that bumps `package.json` versions and updates `CHANGELOG.md` |
| 152 | +2. When that PR is merged, publish to npm and create GitHub releases |
| 153 | + |
| 154 | +**Never manually edit `CHANGELOG.md`** — it is fully generated by `changeset version`. **Never add changesets to a "Version Packages" PR** — it will be overwritten. |
| 155 | + |
| 156 | +## Verification |
| 157 | + |
| 158 | +- [ ] File exists in `.changeset/` with a descriptive or slug filename |
| 159 | +- [ ] Frontmatter lists all affected packages with the correct bump type |
| 160 | +- [ ] All packages in any `fixed` group are included together |
| 161 | +- [ ] Summary is consumer-focused — no internal file names or commit SHAs |
| 162 | +- [ ] Code identifiers are wrapped in backticks |
| 163 | +- [ ] Summary ends with a period |
| 164 | +- [ ] Breaking changes include migration steps |
0 commit comments