Skip to content

Commit 84bf033

Browse files
HikoQiuclaude
andcommitted
chore: improve release command to generate changelog from commits
The /opencow.release command now generates CHANGELOG.md entries from actual git commits instead of leaving placeholder text. It categorizes commits by conventional commit type (feat→Added, fix→Fixed, etc.) and writes user-facing descriptions. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 73e4b07 commit 84bf033

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
allowed-tools: Bash(git:*), Bash(pnpm lint), Bash(pnpm test), Bash(pnpm typecheck), Bash(pnpm build), Bash(node *), Bash(npm version *), Read, Edit, Grep, Glob
3+
description: "Bump version, update changelog, run quality gates, commit, tag, and push a new release"
4+
---
5+
6+
You are the release manager for the OpenCow open-source project. Your job is to execute a fully automated, safe release pipeline.
7+
8+
## Input
9+
10+
The user provides a version string as the argument: `$ARGUMENTS`
11+
12+
- Accept both `vX.Y.Z` and `X.Y.Z` formats
13+
- Normalize to `X.Y.Z` for package.json and `vX.Y.Z` for git tags
14+
15+
## Context
16+
17+
- Current branch: !`git branch --show-current`
18+
- Current version in package.json: !`node -p "require('./package.json').version"`
19+
- Latest git tags: !`git tag --sort=-v:refname | head -5`
20+
- Working tree status: !`git status --short`
21+
22+
---
23+
24+
## Execution Flow
25+
26+
Execute the following steps **strictly in order**. Each step must pass before proceeding.
27+
28+
### Step 0: Pre-flight Validation
29+
30+
**Checks** (any failure β†’ **stop immediately** and explain):
31+
32+
1. **Argument present** β€” `$ARGUMENTS` must not be empty. If empty, output usage:
33+
```
34+
Usage: /opencow.release vX.Y.Z
35+
Example: /opencow.release v0.4.0
36+
```
37+
2. **Valid semver** β€” must match `(v)?MAJOR.MINOR.PATCH` (no pre-release suffixes for now).
38+
3. **Version is newer** β€” the target version must be strictly greater than the current version in `package.json`. Compare `major.minor.patch` numerically.
39+
4. **Clean working tree** β€” `git status --porcelain` must be empty. If there are uncommitted changes, tell the user to commit or stash first.
40+
5. **On `main` branch** β€” releases must be cut from `main`. If on another branch, warn the user.
41+
42+
**Output**:
43+
```
44+
[Pre-flight]
45+
βœ“ Target version: X.Y.Z
46+
βœ“ Current version: A.B.C β†’ X.Y.Z
47+
βœ“ Working tree: clean
48+
βœ“ Branch: main
49+
```
50+
51+
---
52+
53+
### Step 1: Update Version in `package.json`
54+
55+
Run:
56+
```bash
57+
npm version X.Y.Z --no-git-tag-version
58+
```
59+
60+
This updates `package.json` (and `package-lock.json` if present). The `--no-git-tag-version` flag prevents npm from creating a commit or tag β€” we handle those ourselves.
61+
62+
**Verify** by reading back the version:
63+
```bash
64+
node -p "require('./package.json').version"
65+
```
66+
67+
---
68+
69+
### Step 2: Update CHANGELOG.md
70+
71+
**Generate the changelog from actual commits** β€” never leave placeholder text.
72+
73+
1. Run `git log vA.B.C..HEAD --oneline` to list all commits since the previous release tag.
74+
2. Categorize each commit into **Added** / **Changed** / **Fixed** based on its conventional commit type:
75+
- `feat` β†’ Added
76+
- `refactor`, `perf`, `chore` β†’ Changed
77+
- `fix` β†’ Fixed
78+
- `docs`, `style`, `test` β†’ omit (or include under Changed if user-facing)
79+
3. Write concise, user-facing descriptions (not raw commit messages). Group related commits into single entries when they belong to the same feature.
80+
81+
Read the current `CHANGELOG.md`, then insert the new version section **at the top** (below the header), using today's date:
82+
83+
```markdown
84+
## [X.Y.Z] - YYYY-MM-DD
85+
86+
### Added
87+
- Feature description derived from feat() commits
88+
89+
### Changed
90+
- Change description derived from refactor()/perf() commits
91+
92+
### Fixed
93+
- Fix description derived from fix() commits
94+
```
95+
96+
Insert this **before** the previous version's `## [A.B.C]` heading. Do NOT delete or modify existing changelog entries.
97+
98+
If there is no `CHANGELOG.md`, create one with the standard "Keep a Changelog" header.
99+
100+
---
101+
102+
### Step 3: Quality Gates
103+
104+
Run **all four** checks. All must pass β€” any failure β†’ **stop** and report the error.
105+
106+
```bash
107+
pnpm lint
108+
pnpm typecheck
109+
pnpm test
110+
pnpm build
111+
```
112+
113+
**Output**:
114+
```
115+
[Quality Gates]
116+
βœ“ Lint: 0 errors
117+
βœ“ TypeCheck: 0 errors
118+
βœ“ Tests: NNN passed
119+
βœ“ Build: success
120+
```
121+
122+
---
123+
124+
### Step 4: Commit the Version Bump
125+
126+
Stage and commit with a standardized message:
127+
128+
```bash
129+
git add package.json CHANGELOG.md
130+
git commit -m "chore(release): bump version to X.Y.Z
131+
132+
Prepare release vX.Y.Z.
133+
- Update package.json version
134+
- Add CHANGELOG.md entry
135+
136+
Co-Authored-By: Claude <noreply@anthropic.com>"
137+
```
138+
139+
**Important**: Only stage `package.json` and `CHANGELOG.md`. Do NOT use `git add .`.
140+
141+
---
142+
143+
### Step 5: Create Git Tag
144+
145+
```bash
146+
git tag -a vX.Y.Z -m "Release vX.Y.Z"
147+
```
148+
149+
Verify:
150+
```bash
151+
git tag --sort=-v:refname | head -3
152+
```
153+
154+
---
155+
156+
### Step 6: Summary & Next Steps
157+
158+
**Output**:
159+
```
160+
═══════════════════════════════════════════════════
161+
βœ… Release vX.Y.Z prepared successfully!
162+
═══════════════════════════════════════════════════
163+
164+
Version bump: A.B.C β†’ X.Y.Z
165+
Commit: <short hash> chore(release): bump version to X.Y.Z
166+
Tag: vX.Y.Z
167+
168+
Next steps:
169+
1. Review: git log --oneline -3
170+
2. Push: git push origin main && git push origin vX.Y.Z
171+
3. Monitor: https://github.com/OpenCowAI/opencow/actions
172+
173+
After CI completes, the GitHub Release will be created
174+
automatically with DMG/ZIP artifacts attached.
175+
═══════════════════════════════════════════════════
176+
```
177+
178+
**Ask the user**: "Ready to push to remote? (This will trigger the release CI pipeline)"
179+
180+
If the user confirms β†’ run:
181+
```bash
182+
git push origin main && git push origin vX.Y.Z
183+
```
184+
185+
---
186+
187+
## Constraints
188+
189+
1. **Sequential**: Steps 0 β†’ 1 β†’ 2 β†’ 3 β†’ 4 β†’ 5 β†’ 6, no skipping
190+
2. **Blocking**: Stop immediately on any failure, explain clearly
191+
3. **No force push**: Never use `--force` on any git operation
192+
4. **Version source of truth**: Only `package.json` needs a manual version update; `appIdentity.ts` reads from the build-time `__APP_VERSION__` injection via `electron.vite.config.ts`
193+
5. **Tag format**: Always `vX.Y.Z` (with `v` prefix)
194+
6. **No secrets**: Never commit `.env*`, credentials, or tokens
195+
7. **Atomic**: If any quality gate fails, the version bump commit must NOT be pushed

0 commit comments

Comments
Β (0)