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
38 changes: 38 additions & 0 deletions .github/workflows/post-merge-cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Clean up next branch after merge

on:
pull_request:
types: [closed]
branches:
- master

jobs:
cleanup:
runs-on: ubuntu-latest
permissions:
contents: write
# Only run if PR was merged (not just closed) and it was from next branch
if: github.event.pull_request.merged == true && github.event.pull_request.head.ref == 'next'
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0

- name: Setup Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Reset next branch to master
run: |
git checkout -B next origin/master

- name: Push updated next branch
run: |
git push --force-with-lease origin next

- name: Summary
run: |
echo "::notice::Post-merge cleanup completed"
274 changes: 274 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
name: Prepare release PR from next branch

on:
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to prepare release for'
required: true
type: string
version_type:
description: 'Version bump type'
required: true
type: choice
options:
- patch
- minor
- major
default: patch

env:
REPO_B_TARGET: 'main'
REPO_B_NEXT: 'next'

jobs:
prepare-release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0

- name: Setup Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Checkout next branch
run: |
git checkout -B ${{ env.REPO_B_NEXT }} origin/${{ env.REPO_B_NEXT }}

- name: Verify PR exists and get info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Verifying PR #${{ github.event.inputs.pr_number }} exists..."
PR_STATE=$(gh pr view ${{ github.event.inputs.pr_number }} --json state --jq '.state' 2>/dev/null || echo "NOT_FOUND")

if [ "$PR_STATE" = "NOT_FOUND" ]; then
echo "::error::PR #${{ github.event.inputs.pr_number }} not found"
exit 1
fi

if [ "$PR_STATE" != "OPEN" ]; then
echo "::error::PR #${{ github.event.inputs.pr_number }} is $PR_STATE, expected OPEN"
exit 1
fi

echo "PR #${{ github.event.inputs.pr_number }} is open and ready for release preparation"

- name: Determine version bump
id: version
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Fetching latest release from GitHub..."
LATEST_RELEASE=$(gh release list --limit 1 --json tagName --jq '.[0].tagName' 2>/dev/null || echo "")

if [ -n "$LATEST_RELEASE" ]; then
CURRENT_VERSION="$LATEST_RELEASE"
echo "Found latest release: $CURRENT_VERSION"
else
echo "No releases found, starting from v0.0.0"
CURRENT_VERSION="v0.0.0"
fi

# Parse version components (remove 'v' prefix if present)
version_number=$(echo $CURRENT_VERSION | sed 's/^v//')
major=$(echo $version_number | cut -d. -f1)
minor=$(echo $version_number | cut -d. -f2)
patch=$(echo $version_number | cut -d. -f3)

echo "Current version components: major=$major, minor=$minor, patch=$patch"

# Calculate new version based on input
case "${{ github.event.inputs.version_type }}" in
major)
major=$((major + 1))
minor=0
patch=0
echo "Major version bump requested"
;;
minor)
minor=$((minor + 1))
patch=0
echo "Minor version bump requested"
;;
patch)
patch=$((patch + 1))
echo "Patch version bump requested"
;;
esac

NEW_VERSION="v${major}.${minor}.${patch}"
echo "Version bump: $CURRENT_VERSION → $NEW_VERSION"

echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT

- name: Generate changelog entry
run: |
echo "Generating changelog entry for ${{ steps.version.outputs.new_version }}"

# Get all commits in this PR (from target branch to current HEAD)
ALL_PR_COMMITS=$(git rev-list --reverse origin/${{ env.REPO_B_TARGET }}..HEAD)

# Create changelog entry
changelog_entry="## ${{ steps.version.outputs.new_version }} ($(date +%Y-%m-%d))

Full Changelog: [${{ steps.version.outputs.current_version }}...${{ steps.version.outputs.new_version }}](https://github.com/${{ github.repository }}/compare/${{ steps.version.outputs.current_version }}...${{ steps.version.outputs.new_version }})
"

# Add features section
has_feat_commits=false
for commit in $ALL_PR_COMMITS; do
if [ -n "$commit" ]; then
commit_msg=$(git log --format="%s" -1 "$commit")
if echo "$commit_msg" | grep -q "feat:"; then
if [ "$has_feat_commits" = false ]; then
changelog_entry="${changelog_entry}
### Features
"
has_feat_commits=true
fi
# Remove "feat: " prefix and add to changelog with commit link
feature_desc=$(echo "$commit_msg" | sed 's/feat: //')
short_sha=$(echo "$commit" | cut -c1-7)
changelog_entry="${changelog_entry}* ${feature_desc} ([${short_sha}](https://github.com/${{ github.repository }}/commit/${commit}))
"
fi
fi
done

if [ "$has_feat_commits" = true ]; then
changelog_entry="${changelog_entry}
"
fi

# Add fixes section
has_fixes=false
for commit in $ALL_PR_COMMITS; do
if [ -n "$commit" ]; then
commit_msg=$(git log --format="%s" -1 "$commit")
if echo "$commit_msg" | grep -q "fix:"; then
if [ "$has_fixes" = false ]; then
changelog_entry="${changelog_entry}
### Bug Fixes
"
has_fixes=true
fi
# Remove "fix: " prefix and add to changelog with commit link
fix_desc=$(echo "$commit_msg" | sed 's/fix: //')
short_sha=$(echo "$commit" | cut -c1-7)
changelog_entry="${changelog_entry}* ${fix_desc} ([${short_sha}](https://github.com/${{ github.repository }}/commit/${commit}))
"
fi
fi
done

if [ "$has_fixes" = true ]; then
changelog_entry="${changelog_entry}
"
fi

# Add other changes section
has_other=false
for commit in $ALL_PR_COMMITS; do
if [ -n "$commit" ]; then
commit_msg=$(git log --format="%s" -1 "$commit")
if ! echo "$commit_msg" | grep -q -E "^(feat:|fix:|Update sync state)"; then
if [ "$has_other" = false ]; then
changelog_entry="${changelog_entry}
### Other Changes
"
has_other=true
fi
short_sha=$(echo "$commit" | cut -c1-7)
changelog_entry="${changelog_entry}* ${commit_msg} ([${short_sha}](https://github.com/${{ github.repository }}/commit/${commit}))
"
fi
fi
done

# Save changelog entry to temp file
echo "$changelog_entry" > /tmp/changelog_entry.md
echo "Generated changelog entry:"
cat /tmp/changelog_entry.md

- name: Update version files
run: |
# Update pyproject.toml if it exists
if [ -f pyproject.toml ]; then
echo "Updating version in pyproject.toml"
# Remove 'v' prefix for pyproject.toml
VERSION_NUMBER=$(echo "${{ steps.version.outputs.new_version }}" | sed 's/^v//')

# Update version in pyproject.toml using sed
sed -i "s/^version = .*/version = \"$VERSION_NUMBER\"/" pyproject.toml

echo "Updated pyproject.toml version to: $VERSION_NUMBER"
git add pyproject.toml
fi

- name: Update CHANGELOG.md
run: |
echo "Updating CHANGELOG.md"
# Insert new entry at the top (after title if it exists)
if head -1 CHANGELOG.md | grep -q "^# "; then
# Has title, insert after first line
head -1 CHANGELOG.md > /tmp/changelog_new.md
echo "" >> /tmp/changelog_new.md
cat /tmp/changelog_entry.md >> /tmp/changelog_new.md
tail -n +2 CHANGELOG.md >> /tmp/changelog_new.md
else
# No title, insert at beginning
cat /tmp/changelog_entry.md > /tmp/changelog_new.md
cat CHANGELOG.md >> /tmp/changelog_new.md
fi
mv /tmp/changelog_new.md CHANGELOG.md

git add CHANGELOG.md
echo "Updated CHANGELOG.md"

- name: Create release commit
run: |
git commit -m "release: ${{ steps.version.outputs.new_version }}"

echo "Created release commit for ${{ steps.version.outputs.new_version }}"

git push origin ${{ env.REPO_B_NEXT }}

- name: Update PR with release info
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Create updated PR body
PR_BODY="## Release ${{ steps.version.outputs.new_version }}

## Changelog

$(cat /tmp/changelog_entry.md)

---
*Release commit added by prepare-release workflow.*
*This PR is now ready to be reviewed and merged.*"

# Update the PR title and body
gh pr edit ${{ github.event.inputs.pr_number }} \
--title "Release ${{ steps.version.outputs.new_version }}" \
--body "$PR_BODY"

echo "Updated PR #${{ github.event.inputs.pr_number }} with release information"


- name: Summary
run: |
echo "::notice::Release preparation completed successfully"
echo "::notice::PR #${{ github.event.inputs.pr_number }} updated with release commit for ${{ steps.version.outputs.new_version }}"
echo "::notice::Review the PR and merge when ready"
1 change: 1 addition & 0 deletions .sync_state
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1d2c8905b08c612264d01f337870cd7465ad546e