Skip to content

Commit ec92930

Browse files
chanceaclarkclaude
andauthored
chore: add release-catalyst-patch skill for isolated patch releases (#3000)
Document the workflow for shipping a single Catalyst package patch ahead of the normal release cadence, without bundling it with other queued changesets in the open Version Packages PR. Quarantines other changesets, runs `changeset version` for the target, hands the publish + canary push back to the user, and creates the GitHub release manually since the bot's release flow only fires when CI itself publishes. Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5b2dc08 commit ec92930

1 file changed

Lines changed: 233 additions & 0 deletions

File tree

  • .claude/skills/release-catalyst-patch
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
---
2+
name: release-catalyst-patch
3+
description: >
4+
Release a single Catalyst package patch in isolation, without bundling it with
5+
other queued changesets in the open Version Packages PR. Use when the user says
6+
"/release-catalyst-patch", "isolate a patch release", "publish only one package",
7+
or wants to ship a single package's changeset ahead of the normal release cadence.
8+
Performs the full flow locally (`changeset version`, build, `changeset publish`,
9+
push, GitHub release) so the remaining queued changesets stay untouched in the
10+
Version Packages PR.
11+
---
12+
13+
# Release Catalyst Patch (single-package isolation)
14+
15+
The Changesets GitHub Action picks one mode per push to `canary`: if any unconsumed
16+
changesets exist, it opens/refreshes the Version Packages PR and **does not** publish.
17+
That's why we publish locally — we keep the other changesets in `.changeset/` so the
18+
Version Packages PR still tracks them, but we ship just the one we want now.
19+
20+
Execute stages in order. Pause for user input where indicated. **Never execute the
21+
`changeset publish` command yourself** — provide it to the user to run.
22+
23+
## Stage 0: Confirm scope
24+
25+
Identify the changeset to release and the target package + version.
26+
27+
```bash
28+
ls .changeset/
29+
git log --oneline -10 # find the PR/commit that added the changeset
30+
cat .changeset/<changeset-file>.md # confirm the package + bump type
31+
npm view <package> version dist-tags # confirm current published state
32+
```
33+
34+
Confirm with the user:
35+
- Which `.changeset/*.md` file is being released
36+
- The target package and the resulting version (e.g., `1.0.2``1.0.3`)
37+
- That **all other** changesets in `.changeset/` should remain queued for the next regular release
38+
39+
If the package has notes in the [Package-specific notes](#package-specific-notes) section
40+
below, review them before continuing.
41+
42+
## Stage 1: Branch + quarantine
43+
44+
Work on a release branch so the workflow doesn't trigger mid-flow.
45+
46+
```bash
47+
git switch canary && git pull
48+
git switch -c release/<package>-<new-version>
49+
```
50+
51+
Move the **other** changesets **outside** the repo. A subdirectory inside `.changeset/`
52+
gets parsed as a malformed changeset by the CLI and crashes `changeset version`:
53+
54+
```bash
55+
mkdir -p /tmp/changeset-hold
56+
mv .changeset/<other-1>.md .changeset/<other-2>.md ... /tmp/changeset-hold/
57+
ls .changeset/ # should leave only config.json + the one changeset to release
58+
```
59+
60+
## Stage 2: Run `changeset version`
61+
62+
Requires `GITHUB_TOKEN` because the repo uses `@changesets/changelog-github`. The `gh`
63+
CLI token works.
64+
65+
```bash
66+
pnpm install --frozen-lockfile
67+
GITHUB_TOKEN=$(gh auth token) pnpm changeset version
68+
```
69+
70+
Restore the held changesets immediately:
71+
72+
```bash
73+
mv /tmp/changeset-hold/*.md .changeset/
74+
rmdir /tmp/changeset-hold
75+
```
76+
77+
Verify the diff:
78+
79+
```bash
80+
git status
81+
git diff packages/<package>/package.json packages/<package>/CHANGELOG.md
82+
```
83+
84+
Expect: bumped `package.json`, new CHANGELOG entry, deleted only the one changeset.
85+
The other changesets should be back in `.changeset/` and untouched.
86+
87+
## Stage 3: Build
88+
89+
Run the root build. Turborepo handles env passthrough from `.env.local` via the
90+
pipeline config, so package builds get the variables they need without manual sourcing.
91+
92+
```bash
93+
pnpm build
94+
```
95+
96+
If a package has build-time secrets that must be present, see the
97+
[Package-specific notes](#package-specific-notes) section for verification steps.
98+
99+
## Stage 4: Commit
100+
101+
```bash
102+
git add -A
103+
git commit -m "Version Packages (\`canary\`)"
104+
```
105+
106+
Match the message format the changesets bot uses, since this is a manual stand-in for it.
107+
108+
## Stage 5: Hand the publish command to the user
109+
110+
**Do not run `changeset publish` from the agent.** Publishing to npm is a destructive,
111+
externally-visible action that should be performed by the user.
112+
113+
Have the user confirm they're logged in, then run the publish themselves. The CLI will
114+
prompt them interactively for the npm OTP.
115+
116+
```bash
117+
npm whoami # expect their npm username
118+
pnpm exec changeset publish # prompts for OTP interactively
119+
```
120+
121+
`changeset publish` is per-package version-aware: it only publishes packages whose local
122+
`package.json` is ahead of npm. Since only one package was bumped, only it ships. It
123+
also creates a local git tag like `@bigcommerce/<package>@<version>`.
124+
125+
Wait for the user to confirm the publish completed before continuing.
126+
127+
## Stage 6: Verify npm state
128+
129+
```bash
130+
npm view <package> version
131+
npm view <package> dist-tags
132+
```
133+
134+
`latest` should point to the new version. If it doesn't (rare — only happens if
135+
`publishConfig.tag` is set), advise the user to fix with:
136+
137+
```bash
138+
npm dist-tag add <package>@<version> latest
139+
```
140+
141+
## Stage 7: Fast-forward canary and push
142+
143+
This requires a direct push to the protected default branch. **Pause and ask for explicit
144+
user authorization** before pushing — the user's "never push directly to main/master/production"
145+
rule guards against this even though the changesets bot does the same thing during normal
146+
releases.
147+
148+
```bash
149+
git switch canary
150+
git fetch origin canary
151+
git log --oneline origin/canary..canary # should be 1 ahead
152+
git log --oneline canary..origin/canary # should be 0 behind
153+
git merge --ff-only release/<package>-<new-version>
154+
```
155+
156+
If you're 1 ahead and 0 behind, default `git push` rejects non-fast-forward updates,
157+
which gives the same safety as `--ff-only` on the push side. Apple's git build (≤2.50.x)
158+
does not accept `--ff-only` as a push flag — `git push origin canary` is correct here.
159+
160+
If a hook blocks the agent push, hand these commands to the user:
161+
162+
```bash
163+
git push origin canary
164+
git push origin "@bigcommerce/<package>@<new-version>"
165+
```
166+
167+
## Stage 8: Create the GitHub release manually
168+
169+
CI runs `changeset publish` after the canary push, finds the version already on npm,
170+
and no-ops. Because the action only creates GitHub releases for packages it actually
171+
publishes, **no release is created automatically** in this flow. Make it manually.
172+
173+
Extract the new CHANGELOG section (everything after the `## <version>` heading up to
174+
the next `## ` heading) into a notes file. Then:
175+
176+
```bash
177+
gh release create "@bigcommerce/<package>@<new-version>" \
178+
--repo bigcommerce/catalyst \
179+
--title "@bigcommerce/<package>@<new-version>" \
180+
--notes-file /tmp/release-notes.md
181+
```
182+
183+
Match the body format of prior releases — just the `### Patch Changes` /
184+
`### Minor Changes` heading and the bullets, no version heading at the top. Compare
185+
against an existing release:
186+
187+
```bash
188+
gh release view "@bigcommerce/catalyst-core@<some-prior-version>" --repo bigcommerce/catalyst --json body
189+
```
190+
191+
## Stage 9: Final validation
192+
193+
```bash
194+
git fetch origin canary
195+
git log --oneline origin/canary -3 # version commit on canary
196+
git ls-remote --tags origin "@bigcommerce/<package>@<new-version>" # tag on origin
197+
gh release view "@bigcommerce/<package>@<new-version>" --repo bigcommerce/catalyst --json tagName,isDraft,isPrerelease
198+
gh run list --workflow=changesets-release.yml --limit 1 # CI run succeeded
199+
gh pr list --search "Version Packages (canary)" --state open --json number,headRefName,updatedAt # Version Packages PR refreshed
200+
git fetch origin changeset-release/canary
201+
git show --stat origin/changeset-release/canary | head -20 # confirm only the other changesets remain
202+
npm view <package> version dist-tags
203+
```
204+
205+
Report:
206+
- Published version + dist-tag
207+
- Canary commit SHA
208+
- Tag pushed
209+
- GitHub release URL
210+
- Confirmation that the Version Packages PR now contains **only** the other changesets — the released one has been dropped from its scope.
211+
212+
## Stage 10: Cleanup
213+
214+
```bash
215+
git branch -d release/<package>-<new-version>
216+
```
217+
218+
## Package-specific notes
219+
220+
### `@bigcommerce/create-catalyst`
221+
222+
The CLI build (`tsup` via the package's `tsup.config.ts`) inlines `CLI_SEGMENT_WRITE_KEY`
223+
at build time, falling back to the placeholder `'not-a-valid-segment-write-key'` if the
224+
env var is missing. After Stage 3, verify the real key was embedded:
225+
226+
```bash
227+
grep -c "not-a-valid-segment-write-key" packages/create-catalyst/dist/index.js
228+
# expect: 0
229+
```
230+
231+
If `1`, the env var wasn't loaded. Confirm `CLI_SEGMENT_WRITE_KEY` exists in `.env.local`,
232+
and that the turbo pipeline for `build` declares it under `env` or `passThroughEnv` in
233+
`turbo.json`. Re-run `pnpm build` after fixing.

0 commit comments

Comments
 (0)