name: Rust Version Bump
on:
workflow_call:
inputs:
bump_type:
description: 'Version bump type (major, minor, or patch)'
required: true
type: string
crate_name:
description: 'Crate name for changelog'
required: true
type: string
secrets:
GITHUB_TOKEN:
required: true
jobs:
bump:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Read current version
id: current_version
run: |
VERSION=$(grep '^version = ' Cargo.toml | cut -d'"' -f2)
echo "current=$VERSION" >> $GITHUB_OUTPUT
echo "Current version: $VERSION"
- name: Calculate new version
id: new_version
run: |
CURRENT="${{ steps.current_version.outputs.current }}"
BUMP_TYPE="${{ inputs.bump_type }}"
# Extract version parts (handle pre-release versions)
BASE_VERSION=$(echo "$CURRENT" | cut -d'-' -f1)
IFS='.' read -r major minor patch <<< "$BASE_VERSION"
case "$BUMP_TYPE" in
major)
major=$((major + 1))
minor=0
patch=0
;;
minor)
minor=$((minor + 1))
patch=0
;;
patch)
patch=$((patch + 1))
;;
*)
echo "❌ Invalid bump_type: $BUMP_TYPE. Must be major, minor, or patch"
exit 1
;;
esac
NEW_VERSION="${major}.${minor}.${patch}"
echo "new=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "New version: $NEW_VERSION"
- name: Update Cargo.toml
run: |
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s/^version = \".*\"/version = \"${{ steps.new_version.outputs.new }}\"/" Cargo.toml
else
sed -i "s/^version = \".*\"/version = \"${{ steps.new_version.outputs.new }}\"/" Cargo.toml
fi
# Verify update
UPDATED=$(grep '^version = ' Cargo.toml | cut -d'"' -f2)
if [ "$UPDATED" != "${{ steps.new_version.outputs.new }}" ]; then
echo "❌ Failed to update version in Cargo.toml"
exit 1
fi
echo "✅ Updated Cargo.toml to version ${{ steps.new_version.outputs.new }}"
- name: Update CHANGELOG.md
run: |
NEW_VERSION="${{ steps.new_version.outputs.new }}"
TODAY=$(date -u +"%Y-%m-%d")
# Check if CHANGELOG.md exists
if [ ! -f CHANGELOG.md ]; then
echo "⚠️ CHANGELOG.md not found, skipping update"
exit 0
fi
# Move [Unreleased] content to new version section
# This is a simple approach - moves everything under [Unreleased] to the new version
if grep -q "^## \[Unreleased\]" CHANGELOG.md; then
# Create new version section
sed -i.bak "s/^## \[Unreleased\]/## \[$NEW_VERSION\] - $TODAY\n\n## \[Unreleased\]/" CHANGELOG.md
rm -f CHANGELOG.md.bak
# Update comparison links
REPO_URL=$(grep -m1 "^\[Unreleased\]:" CHANGELOG.md | cut -d' ' -f2 | cut -d'/' -f1-5)
if [ -n "$REPO_URL" ]; then
# Update [Unreleased] link
sed -i.bak "s|^\[Unreleased\]: .*|\[Unreleased\]: $REPO_URL/compare/v$NEW_VERSION...HEAD|" CHANGELOG.md
# Add new version link if it doesn't exist
if ! grep -q "^\[$NEW_VERSION\]:" CHANGELOG.md; then
PREV_VERSION=$(grep "^## \[" CHANGELOG.md | head -2 | tail -1 | sed 's/## \[\(.*\)\].*/\1/')
VERSION_LINK="[$NEW_VERSION]: $REPO_URL/compare/v$PREV_VERSION...v$NEW_VERSION"
if [ -n "$PREV_VERSION" ] && [ "$PREV_VERSION" != "Unreleased" ]; then
# Insert link after version header
awk -v version="$NEW_VERSION" -v link="$VERSION_LINK" \
'/^## \[' version '\]/ {print; print ""; print link; next}1' CHANGELOG.md > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
else
VERSION_LINK="[$NEW_VERSION]: $REPO_URL/releases/tag/v$NEW_VERSION"
awk -v version="$NEW_VERSION" -v link="$VERSION_LINK" \
'/^## \[' version '\]/ {print; print ""; print link; next}1' CHANGELOG.md > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
fi
fi
rm -f CHANGELOG.md.bak
fi
echo "✅ Updated CHANGELOG.md"
else
echo "⚠️ No [Unreleased] section found in CHANGELOG.md"
fi
- name: Commit and tag
run: |
git add Cargo.toml CHANGELOG.md
# Check if there are changes to commit
if git diff --staged --quiet; then
echo "⚠️ No changes to commit"
exit 0
fi
git commit -m "chore: bump version to ${{ steps.new_version.outputs.new }}"
git tag "v${{ steps.new_version.outputs.new }}" -m "Release ${{ steps.new_version.outputs.new }}"
echo "✅ Created commit and tag v${{ steps.new_version.outputs.new }}"
- name: Push changes
run: |
# Detect default branch
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')
if [ -z "$DEFAULT_BRANCH" ]; then
DEFAULT_BRANCH="main"
fi
git push origin HEAD:$DEFAULT_BRANCH
git push origin "v${{ steps.new_version.outputs.new }}"
echo "✅ Pushed commit and tag to GitHub"
echo "🚀 Publish workflow will automatically trigger on tag push"