chore: add release automation and /release skill#32
Conversation
- Auto-tag workflow: detects Cargo.toml version bump on main push, creates git tag automatically, which triggers the release workflow. - /release Claude Code skill: guided release preparation with semver determination, user confirmation, and PR creation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds repository automation and guidance to streamline releases by auto-tagging version bumps on main and documenting a /release command workflow for Claude Code.
Changes:
- Introduces a new GitHub Actions workflow to create
vX.Y.Ztags whenCargo.tomlversion changes onmain. - Adds a Claude Code
/releasecommand guide to prepare a release PR (version bump + changelog update). - Updates
CHANGELOG.mdto document the new release flow components.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| CHANGELOG.md | Documents the new auto-tag workflow and /release command under Unreleased. |
| .github/workflows/auto-tag.yml | Adds CI workflow that detects version bumps and pushes a vX.Y.Z tag. |
| .claude/commands/release.md | Adds guided release instructions for creating a release PR. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| fetch-depth: 2 | ||
| - name: Check for version bump | ||
| id: version | ||
| run: | | ||
| CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') | ||
| PREVIOUS=$(git show HEAD~1:Cargo.toml | grep '^version' | head -1 | sed 's/.*"\(.*\)"/\1/') |
There was a problem hiding this comment.
HEAD~1 only compares against the immediately previous commit. On pushes that include multiple commits (or merges), this can miss a version bump that happened earlier in the push (or compare against the wrong base). Use the push event's before SHA (e.g., ${{ github.event.before }}) or explicitly diff Cargo.toml between ${{ github.event.before }} and ${{ github.sha }} to reliably detect version changes for the whole push.
| fetch-depth: 2 | |
| - name: Check for version bump | |
| id: version | |
| run: | | |
| CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') | |
| PREVIOUS=$(git show HEAD~1:Cargo.toml | grep '^version' | head -1 | sed 's/.*"\(.*\)"/\1/') | |
| fetch-depth: 0 | |
| - name: Check for version bump | |
| id: version | |
| run: | | |
| CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') | |
| PREVIOUS=$(git show ${{ github.event.before }}:Cargo.toml | grep '^version' | head -1 | sed 's/.*"\(.*\)"/\1/') |
| if git rev-parse "$TAG" >/dev/null 2>&1; then | ||
| echo "Tag $TAG already exists, skipping" | ||
| exit 0 | ||
| fi | ||
| git tag "$TAG" | ||
| git push origin "$TAG" |
There was a problem hiding this comment.
The tag existence check uses git rev-parse "$TAG", which only checks locally fetched tags. In a shallow checkout this may not include existing remote tags, causing git push to fail when the tag already exists on origin. Prefer checking the remote (git ls-remote --tags origin "refs/tags/$TAG") or fetching tags before the check, and handle a push rejection gracefully.
| if git rev-parse "$TAG" >/dev/null 2>&1; then | |
| echo "Tag $TAG already exists, skipping" | |
| exit 0 | |
| fi | |
| git tag "$TAG" | |
| git push origin "$TAG" | |
| # Check if the tag already exists on the remote | |
| if git ls-remote --tags origin "refs/tags/$TAG" | grep -q .; then | |
| echo "Tag $TAG already exists on origin, skipping" | |
| exit 0 | |
| fi | |
| # Also check if the tag exists locally | |
| if git rev-parse "$TAG" >/dev/null 2>&1; then | |
| echo "Tag $TAG already exists locally, skipping" | |
| exit 0 | |
| fi | |
| git tag "$TAG" | |
| # Push the tag; if it fails, re-check the remote to handle concurrent creation | |
| if ! git push origin "$TAG"; then | |
| if git ls-remote --tags origin "refs/tags/$TAG" | grep -q .; then | |
| echo "Tag $TAG was created concurrently on origin, skipping" | |
| exit 0 | |
| fi | |
| echo "Failed to push tag $TAG" | |
| exit 1 | |
| fi |
|
|
||
| 1. Fetch origin and create a branch: `release/vX.Y.Z` from `origin/main`. | ||
| 2. Bump version in `Cargo.toml` (the `version = "..."` field under `[package]`). | ||
| 3. Run `cargo check` to update `Cargo.lock`. |
There was a problem hiding this comment.
This step says cargo check will update Cargo.lock, but cargo check typically won't change the lockfile unless dependency resolution changes; bumping the package version alone won't do that. If the goal is just validation, reword to reflect that; if the goal is to ensure a lockfile exists/updates, use the appropriate Cargo command (e.g., generating/updating the lockfile) instead.
| 3. Run `cargo check` to update `Cargo.lock`. | |
| 3. Run `cargo check` to ensure the project builds successfully after the version bump. |
- Use github.event.before SHA instead of HEAD~1 for reliable version diff across multi-commit pushes and merges. - Use fetch-depth: 0 to ensure full history is available. - Check remote tags via git ls-remote before creating, and handle concurrent tag creation gracefully. - Fix misleading comment about cargo check updating Cargo.lock. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
.github/workflows/auto-tag.yml): Runs on push to main whenCargo.tomlchanges. Compares the version with the previous commit — if it changed, creates and pushes avX.Y.Ztag. This triggers the existing release workflow (Docker build, crates.io publish)./releaseskill (.claude/commands/release.md): A guided release preparation command for Claude Code. Determines the next semver version from changelog + commits, presents a confirmation to the user, then creates a release PR with version bump + changelog update.New release flow
/releasein Claude CodeTest plan
/releaseskill appears in Claude Code (/?)Cargo.tomlversion is unchanged in this PR)🤖 Generated with Claude Code