Merge pull request #6 from alirezarezvani/dependabot/pip/dev/setuptoo… #9
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: Auto-Create PR to Main | ||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| release_type: | ||
| description: 'Release type' | ||
| required: true | ||
| type: choice | ||
| options: | ||
| - patch | ||
| - minor | ||
| - major | ||
| # Optionally trigger automatically after successful merge to dev | ||
| # pull_request: | ||
| # types: [closed] | ||
| # branches: [dev] | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| jobs: | ||
| create-release-pr: | ||
| name: Create Release PR (dev → main) | ||
| runs-on: ubuntu-latest | ||
| # Only run on workflow_dispatch or when PR to dev is merged | ||
| if: | | ||
| github.event_name == 'workflow_dispatch' || | ||
| (github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev') | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| ref: dev | ||
| - name: Check for changes since last release | ||
| id: check-changes | ||
| run: | | ||
| # Get last release tag | ||
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") | ||
| echo "Last release: $LAST_TAG" | ||
| # Check if there are commits since last tag | ||
| COMMITS_SINCE=$(git rev-list ${LAST_TAG}..HEAD --count 2>/dev/null || git rev-list HEAD --count) | ||
| echo "Commits since last release: $COMMITS_SINCE" | ||
| if [ "$COMMITS_SINCE" -eq 0 ]; then | ||
| echo "No changes since last release" | ||
| echo "has_changes=false" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| echo "commits_count=$COMMITS_SINCE" >> $GITHUB_OUTPUT | ||
| echo "last_tag=$LAST_TAG" >> $GITHUB_OUTPUT | ||
| fi | ||
| - name: Check if PR already exists | ||
| id: check-pr | ||
| if: steps.check-changes.outputs.has_changes == 'true' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const { data: pulls } = await github.rest.pulls.list({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| head: `${context.repo.owner}:dev`, | ||
| base: 'main', | ||
| state: 'open', | ||
| }); | ||
| if (pulls.length > 0) { | ||
| console.log(`Release PR already exists: #${pulls[0].number}`); | ||
| core.setOutput('pr_exists', 'true'); | ||
| core.setOutput('pr_number', pulls[0].number); | ||
| } else { | ||
| console.log('No existing release PR found'); | ||
| core.setOutput('pr_exists', 'false'); | ||
| } | ||
| - name: Extract CHANGELOG unreleased | ||
| id: extract-changelog | ||
| if: steps.check-changes.outputs.has_changes == 'true' && steps.check-pr.outputs.pr_exists == 'false' | ||
| run: | | ||
| # Extract unreleased section from CHANGELOG.md | ||
| if [ -f "CHANGELOG.md" ]; then | ||
| # Get content between [Unreleased] and next version | ||
| UNRELEASED=$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | sed '1d;$d') | ||
| if [ -n "$UNRELEASED" ]; then | ||
| echo "Found unreleased changes in CHANGELOG.md" | ||
| echo "$UNRELEASED" > /tmp/changelog-unreleased.txt | ||
| echo "has_changelog=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "No unreleased section in CHANGELOG.md" | ||
| echo "has_changelog=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| else | ||
| echo "CHANGELOG.md not found" | ||
| echo "has_changelog=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| - name: Get commit log since last release | ||
| id: get-commits | ||
| if: steps.check-changes.outputs.has_changes == 'true' && steps.check-pr.outputs.pr_exists == 'false' | ||
| run: | | ||
| LAST_TAG="${{ steps.check-changes.outputs.last_tag }}" | ||
| # Get commits since last tag | ||
| git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" > /tmp/commits.txt | ||
| echo "Commits since $LAST_TAG:" | ||
| cat /tmp/commits.txt | ||
| - name: Create PR body | ||
| id: create-body | ||
| if: steps.check-changes.outputs.has_changes == 'true' && steps.check-pr.outputs.pr_exists == 'false' | ||
| run: | | ||
| COMMITS_COUNT="${{ steps.check-changes.outputs.commits_count }}" | ||
| LAST_TAG="${{ steps.check-changes.outputs.last_tag }}" | ||
| # Build PR body | ||
| cat > /tmp/pr-body.txt << 'EOFBODY' | ||
| ## Release PR: dev → main | ||
| This PR includes **COMMITS_COUNT** commits ready for release. | ||
| EOFBODY | ||
| # Replace placeholder | ||
| sed -i "s/COMMITS_COUNT/$COMMITS_COUNT/g" /tmp/pr-body.txt | ||
| # Add changelog if available | ||
| if [ "${{ steps.extract-changelog.outputs.has_changelog }}" == "true" ]; then | ||
| cat >> /tmp/pr-body.txt << 'EOFCHANGELOG' | ||
| ## Changes | ||
| EOFCHANGELOG | ||
| cat /tmp/changelog-unreleased.txt >> /tmp/pr-body.txt | ||
| else | ||
| # Use commit log | ||
| cat >> /tmp/pr-body.txt << 'EOFCOMMITS' | ||
| ## Commits Since LAST_TAG | ||
| EOFCOMMITS | ||
| sed -i "s/LAST_TAG/$LAST_TAG/g" /tmp/pr-body.txt | ||
| cat /tmp/commits.txt >> /tmp/pr-body.txt | ||
| fi | ||
| # Add pre-merge checklist | ||
| cat >> /tmp/pr-body.txt << 'EOFCHECKLIST' | ||
| ## Pre-Release Checklist | ||
| - [ ] CHANGELOG.md updated with version number | ||
| - [ ] Version bumped in pyproject.toml (if exists) | ||
| - [ ] All quality checks passed on dev | ||
| - [ ] README.md reflects latest changes | ||
| - [ ] Breaking changes documented | ||
| - [ ] Migration guide provided (if breaking changes) | ||
| ## Post-Merge Actions | ||
| After merging this PR: | ||
| - GitHub Release will be created automatically | ||
| - Wiki will be updated automatically | ||
| - Distribution package will be rebuilt | ||
| --- | ||
| **⚠️ This PR will be reviewed by Claude agent for final validation.** | ||
| EOFCHECKLIST | ||
| echo "PR body created" | ||
| - name: Determine next version | ||
| id: next-version | ||
| if: steps.check-changes.outputs.has_changes == 'true' && steps.check-pr.outputs.pr_exists == 'false' | ||
| run: | | ||
| LAST_TAG="${{ steps.check-changes.outputs.last_tag }}" | ||
| RELEASE_TYPE="${{ github.event.inputs.release_type || 'patch' }}" | ||
| # Remove 'v' prefix if present | ||
| LAST_VERSION="${LAST_TAG#v}" | ||
| # Parse version | ||
| IFS='.' read -r MAJOR MINOR PATCH <<< "$LAST_VERSION" | ||
| # Increment based on release type | ||
| case $RELEASE_TYPE in | ||
| major) | ||
| MAJOR=$((MAJOR + 1)) | ||
| MINOR=0 | ||
| PATCH=0 | ||
| ;; | ||
| minor) | ||
| MINOR=$((MINOR + 1)) | ||
| PATCH=0 | ||
| ;; | ||
| patch) | ||
| PATCH=$((PATCH + 1)) | ||
| ;; | ||
| esac | ||
| NEXT_VERSION="v${MAJOR}.${MINOR}.${PATCH}" | ||
| echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT | ||
| echo "Next version: $NEXT_VERSION" | ||
| - name: Create pull request | ||
| if: steps.check-changes.outputs.has_changes == 'true' && steps.check-pr.outputs.pr_exists == 'false' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const fs = require('fs'); | ||
| const nextVersion = '${{ steps.next-version.outputs.next_version }}'; | ||
| const body = fs.readFileSync('/tmp/pr-body.txt', 'utf8'); | ||
| const { data: pr } = await github.rest.pulls.create({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| title: `Release ${nextVersion}`, | ||
| body: body, | ||
| head: 'dev', | ||
| base: 'main', | ||
| }); | ||
| console.log(`Created release PR #${pr.number}: ${pr.html_url}`); | ||
| // Add release label | ||
| await github.rest.issues.addLabels({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: pr.number, | ||
| labels: ['release'], | ||
| }); | ||
| core.setOutput('pr_number', pr.number); | ||
| core.setOutput('pr_url', pr.html_url); | ||
| - name: No changes to release | ||
| if: steps.check-changes.outputs.has_changes == 'false' | ||
| run: | | ||
| echo "ℹ️ No changes to release since last tag" | ||
| echo "dev branch is up-to-date with last release" | ||