chore: release v0.39.0 #237
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: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version_bump: | |
| description: 'Version bump type' | |
| required: true | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| default: 'patch' | |
| pull_request: | |
| types: [closed] | |
| branches: [main] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| id-token: write | |
| jobs: | |
| # Job 1: Create version bump PR (triggered manually) | |
| create-release-pr: | |
| if: github.event_name == 'workflow_dispatch' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| version: "latest" | |
| - name: Configure git | |
| run: | | |
| git config user.name "${GITHUB_ACTOR}" | |
| git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" | |
| - name: Bump version | |
| id: bump | |
| run: | | |
| # Get current version | |
| CURRENT_VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/') | |
| echo "Current version: $CURRENT_VERSION" | |
| # Parse version components | |
| IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION" | |
| # Bump based on input | |
| case "${{ inputs.version_bump }}" in | |
| minor) | |
| MINOR=$((MINOR + 1)) | |
| PATCH=0 | |
| ;; | |
| patch) | |
| PATCH=$((PATCH + 1)) | |
| ;; | |
| esac | |
| NEW_VERSION="${MAJOR}.${MINOR}.${PATCH}" | |
| echo "New version: $NEW_VERSION" | |
| # Update pyproject.toml | |
| sed -i "s/^version = \".*\"/version = \"$NEW_VERSION\"/" pyproject.toml | |
| echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT | |
| - name: Update lock file | |
| run: uv lock | |
| - name: Create release branch and PR | |
| id: create_pr | |
| env: | |
| GH_TOKEN: ${{ secrets.RELEASE_PAT }} | |
| STEPS_BUMP_OUTPUTS_NEW_VERSION: ${{ steps.bump.outputs.new_version }} | |
| run: | | |
| BRANCH="release/v${STEPS_BUMP_OUTPUTS_NEW_VERSION}" | |
| # Delete existing branch if it exists | |
| git push origin --delete "$BRANCH" 2>/dev/null || true | |
| git checkout -b "$BRANCH" | |
| git add pyproject.toml uv.lock | |
| git commit -m "chore: bump version to ${STEPS_BUMP_OUTPUTS_NEW_VERSION}" | |
| git push -u origin "$BRANCH" | |
| # Create PR using PAT (author is the PAT owner, CLA will pass) | |
| PR_URL=$(gh pr create \ | |
| --title "chore: release v${STEPS_BUMP_OUTPUTS_NEW_VERSION}" \ | |
| --body "## Release v${STEPS_BUMP_OUTPUTS_NEW_VERSION} | |
| This PR was automatically created by the release workflow. | |
| ### Checklist | |
| - [ ] Tests pass | |
| - [ ] Ready to publish to PyPI | |
| Once merged, the release will be published after manual approval." \ | |
| --label "release" \ | |
| --head "$BRANCH") | |
| echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT | |
| - name: Approve PR | |
| env: | |
| GH_TOKEN: ${{ secrets.APPROVER_PAT }} | |
| STEPS_CREATE_PR_OUTPUTS_PR_URL: ${{ steps.create_pr.outputs.pr_url }} | |
| run: | | |
| # Approve with second account's PAT (different user than PR author) | |
| gh pr review "${STEPS_CREATE_PR_OUTPUTS_PR_URL}" --approve | |
| - name: Wait for all checks to pass | |
| env: | |
| GH_TOKEN: ${{ secrets.RELEASE_PAT }} | |
| STEPS_CREATE_PR_OUTPUTS_PR_URL: ${{ steps.create_pr.outputs.pr_url }} | |
| run: | | |
| echo "Waiting for all status checks to complete..." | |
| sleep 10 | |
| gh pr checks "${STEPS_CREATE_PR_OUTPUTS_PR_URL}" --watch --fail-fast | |
| - name: Enable auto-merge | |
| env: | |
| GH_TOKEN: ${{ secrets.RELEASE_PAT }} | |
| STEPS_CREATE_PR_OUTPUTS_PR_URL: ${{ steps.create_pr.outputs.pr_url }} | |
| run: | | |
| # Use PAT for auto-merge so the merge event triggers the publish workflow | |
| gh pr merge "${STEPS_CREATE_PR_OUTPUTS_PR_URL}" --auto --squash | |
| # Job 2: Publish release (triggered when release PR is merged) | |
| publish: | |
| if: github.event_name == 'pull_request' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/') | |
| runs-on: ubuntu-latest | |
| environment: release # Requires manual approval | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| with: | |
| version: "latest" | |
| - name: Set up Python | |
| run: uv python install 3.11 | |
| - name: Get version from branch name | |
| id: version | |
| run: | | |
| # Extract version from branch name (release/v1.2.3 -> 1.2.3) | |
| VERSION="${GITHUB_EVENT_PULL_REQUEST_HEAD_REF}" | |
| VERSION="${VERSION#release/v}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "tag=v$VERSION" >> $GITHUB_OUTPUT | |
| env: | |
| GITHUB_EVENT_PULL_REQUEST_HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| - name: Build package | |
| run: uv build | |
| - name: Publish to PyPI | |
| run: uv publish | |
| env: | |
| UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} | |
| - name: Configure git | |
| run: | | |
| git config user.name "${GITHUB_ACTOR}" | |
| git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" | |
| - name: Create and push tag | |
| run: | | |
| git tag ${STEPS_VERSION_OUTPUTS_TAG} | |
| git push origin ${STEPS_VERSION_OUTPUTS_TAG} | |
| env: | |
| STEPS_VERSION_OUTPUTS_TAG: ${{ steps.version.outputs.tag }} | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.version.outputs.tag }} | |
| name: ${{ steps.version.outputs.tag }} | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |