Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions .claude/skills/release/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,55 @@
---
name: release
description: Prepare a codegraph release — bump versions, update CHANGELOG, ROADMAP, BACKLOG, README, create PR
argument-hint: <version e.g. 3.1.1>
argument-hint: "[version e.g. 3.1.1] (optional — auto-detects from commits)"
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent
---

# Release v$ARGUMENTS
# Release

You are preparing a release for `@optave/codegraph` version **$ARGUMENTS**.
You are preparing a release for `@optave/codegraph`.

**Version argument:** `$ARGUMENTS`
- If a version was provided (e.g. `3.1.1`), use it as the target version.
- If no version was provided (empty or blank `$ARGUMENTS`), you will auto-detect it in Step 1b.

---

## Step 1: Gather context
## Step 1a: Gather context

Run these in parallel:
1. `git log --oneline v<previous-tag>..HEAD` — all commits since the last release tag
1. `git log --oneline v<previous-tag>..HEAD` — all commits since the last release tag (use `git describe --tags --match "v*" --abbrev=0` to find the previous tag)
2. Read `CHANGELOG.md` (first 80 lines) — understand the format
3. Read `package.json` — current version
4. `git describe --tags --match "v*" --abbrev=0` — find the previous stable release tag

## Step 1b: Determine version (if not provided)

If `$ARGUMENTS` is empty or blank, determine the semver bump from the commits gathered in Step 1a.

Scan **every commit message** between the last tag and HEAD. Apply these rules in priority order:

| Condition | Bump |
|-----------|------|
| Any commit has a `BREAKING CHANGE:` or `BREAKING-CHANGE:` footer, **or** uses the `!` suffix (e.g. `feat!:`, `fix!:`, `refactor!:`) | **major** |
| Any commit uses `feat:` or `feat(scope):` | **minor** |
| Everything else (`fix:`, `refactor:`, `perf:`, `chore:`, `docs:`, `test:`, `ci:`, etc.) | **patch** |

Given the current version `MAJOR.MINOR.PATCH` from `package.json`, compute the new version:
- **major** → `(MAJOR+1).0.0`
- **minor** → `MAJOR.(MINOR+1).0`
- **patch** → `MAJOR.MINOR.(PATCH+1)`

Print the detected bump reason and the resolved version, e.g.:
> Detected **minor** bump (found `feat:` commits). Version: 3.1.0 → **3.2.0**

Use the resolved version as `VERSION` for all subsequent steps.

If `$ARGUMENTS` was provided, use it directly as `VERSION`.

## Step 2: Bump version in package.json

Edit `package.json` to set `"version": "$ARGUMENTS"`.
Edit `package.json` to set `"version": "VERSION"`.

**Do NOT bump:**
- `crates/codegraph-core/Cargo.toml` — synced automatically by `scripts/sync-native-versions.js` during the publish workflow
Expand Down Expand Up @@ -104,16 +132,16 @@ Run `grep` to confirm the new version appears in `package-lock.json` and that al

## Step 8: Create branch, commit, push, PR

1. Create branch: `git checkout -b release/$ARGUMENTS`
1. Create branch: `git checkout -b release/VERSION`
2. Stage only the files you changed: `CHANGELOG.md`, `package.json`, `package-lock.json`, `docs/roadmap/ROADMAP.md`, `docs/roadmap/BACKLOG.md` if changed, `README.md` if changed
3. Commit: `chore: release v$ARGUMENTS`
4. Push: `git push -u origin release/$ARGUMENTS`
3. Commit: `chore: release vVERSION`
4. Push: `git push -u origin release/VERSION`
5. Create PR:

```
gh pr create --title "chore: release v$ARGUMENTS" --body "$(cat <<'EOF'
gh pr create --title "chore: release vVERSION" --body "$(cat <<'EOF'
## Summary
- Bump version to $ARGUMENTS
- Bump version to VERSION
- Add CHANGELOG entry for all commits since previous release
- Update ROADMAP progress

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
fi
if [ "$COMMITS" -eq 0 ]; then
VERSION="${MAJOR}.${MINOR}.${PATCH}"
VERSION="${MAJOR}.${MINOR}.${PATCH}-dev.0"
else
VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))-dev.${COMMITS}"
fi
Expand Down
16 changes: 11 additions & 5 deletions scripts/bench-version.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 1. `git describe --tags --match "v*" --abbrev=0` → find nearest release tag
* 2. `git rev-list <tag>..HEAD --count` → count commits since that tag
*
* - If HEAD is exactly tagged (0 commits): returns "3.1.5"
* - If HEAD is exactly tagged (0 commits): returns "3.1.5-dev.0"
* - Otherwise: returns "3.1.6-dev.12" (NEXT_PATCH-dev.COMMIT_COUNT)
* This keeps dev versions in the correct semver range between the
* current release and the next, avoiding inflated patch numbers.
Expand Down Expand Up @@ -36,8 +36,8 @@ export function getBenchmarkVersion(pkgVersion, cwd) {

const [, major, minor, patch] = m;

// Exact tag (0 commits since tag): return clean release version
if (commits === 0) return `${major}.${minor}.${patch}`;
// Exact tag (0 commits since tag): still mark as dev to avoid confusion with stable
if (commits === 0) return `${major}.${minor}.${patch}-dev.0`;

// Dev build: MAJOR.MINOR.(PATCH+1)-dev.COMMITS
const nextPatch = Number(patch) + 1;
Expand All @@ -46,11 +46,17 @@ export function getBenchmarkVersion(pkgVersion, cwd) {
/* git not available or no tags */
}

// Fallback: no git or no tags — match publish.yml's no-tags behavior (COMMITS=1)
// Fallback: no git or no tags — try to get a unique SHA so repeated runs
// don't collide in benchmark reports (which deduplicate by version)
const parts = pkgVersion.split('.');
if (parts.length === 3) {
const [major, minor, patch] = parts;
return `${major}.${minor}.${Number(patch) + 1}-dev.1`;
try {
const hash = execFileSync('git', ['rev-parse', '--short', 'HEAD'], { cwd, ...GIT_OPTS }).trim();
return `${major}.${minor}.${Number(patch) + 1}-dev.${hash}`;
} catch {
return `${major}.${minor}.${Number(patch) + 1}-dev`;
}
}
return `${pkgVersion}-dev`;
}
Loading