Skip to content

Prepare Release

Prepare Release #4

name: Prepare Release
on:
workflow_dispatch:
inputs:
version:
description: 'Version number (e.g., 0.6.0)'
required: true
type: string
permissions:
contents: write
pull-requests: write
jobs:
prepare:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Validate version format
run: |
if ! echo "${{ inputs.version }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Error: Version must be in format X.Y.Z (e.g., 0.6.0)"
exit 1
fi
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Create release branch
run: |
VERSION="${{ inputs.version }}"
# Delete remote branch if it exists from a previous attempt
git push origin --delete "release/${VERSION}" 2>/dev/null || true
git checkout -b "release/${VERSION}"
- name: Update CHANGELOG.md
env:
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
VERSION="${{ inputs.version }}"
DATE=$(date +%Y-%m-%d)
# Create the new Unreleased section template
UNRELEASED_TEMPLATE=$(printf '%s\n\n%s\n\n%s\n\n%s\n\n%s\n\n' \
'## [Unreleased]' \
'### Added' \
'### Changed' \
'### Fixed' \
'### Removed')
# Read the current changelog
CHANGELOG=$(cat CHANGELOG.md)
# Check if there's an existing Unreleased section
if grep -q "^## \[Unreleased\]" CHANGELOG.md; then
# Replace [Unreleased] with the new version and date
# First, extract everything after the Unreleased header until the next ## section
# Then insert the new Unreleased section at the top
# Use awk to do the replacement
awk -v version="$VERSION" -v date="$DATE" -v template="$UNRELEASED_TEMPLATE" '
/^## \[Unreleased\]/ {
print template
print "## [" version "] - " date
next
}
{ print }
' CHANGELOG.md > CHANGELOG.md.tmp
mv CHANGELOG.md.tmp CHANGELOG.md
else
# No Unreleased section exists - insert new version after the header
# Find the first ## line and insert before it
awk -v version="$VERSION" -v date="$DATE" -v template="$UNRELEASED_TEMPLATE" '
BEGIN { inserted = 0 }
/^## \[/ && !inserted {
print template
print "## [" version "] - " date
print ""
inserted = 1
}
{ print }
' CHANGELOG.md > CHANGELOG.md.tmp
mv CHANGELOG.md.tmp CHANGELOG.md
fi
# Update the version links at the bottom of the CHANGELOG
# Update the Unreleased link to compare from the new version
sed -i "s|\[Unreleased\]: https://github.com/.*/compare/.*\.\.\.HEAD|[Unreleased]: https://github.com/${GITHUB_REPOSITORY}/compare/${VERSION}...HEAD|" CHANGELOG.md
# Add the new version link if it doesn't exist (insert after Unreleased link)
if ! grep -q "^\[${VERSION}\]:" CHANGELOG.md; then
# Find the previous version from the changelog (first version after Unreleased)
PREV_VERSION=$(grep -oP '^\[[\d.]+\]:' CHANGELOG.md | head -1 | tr -d '[]:' || echo "")
if [ -n "$PREV_VERSION" ]; then
VERSION_LINK="[${VERSION}]: https://github.com/${GITHUB_REPOSITORY}/releases/tag/${VERSION}"
sed -i "/^\[Unreleased\]:/a ${VERSION_LINK}" CHANGELOG.md
fi
fi
- name: Update pyproject.toml version
run: |
VERSION="${{ inputs.version }}"
sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
# Verify the change
grep "^version = " pyproject.toml
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Update lock file
run: uv sync
- name: Commit and push
run: |
VERSION="${{ inputs.version }}"
git add CHANGELOG.md pyproject.toml uv.lock
git commit -m "Release v${VERSION}"
git push -u origin "release/${VERSION}"
- name: Create Pull Request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ inputs.version }}"
gh pr create \
--title "${VERSION}" \
--body "## Release v${VERSION}
This PR prepares the release of version ${VERSION}.
### Changes
- Updated version in pyproject.toml
- Updated CHANGELOG.md
- Updated uv.lock
### After Merge
A GitHub Release will be automatically created when this PR is merged." \
--label "release"