Prepare release PR from next branch #2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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: 'master' | |
| 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" |