Publish Python SDK #8
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: Publish Python SDK | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| ref: | |
| description: "Git ref to publish (branch, tag, or commit SHA)" | |
| required: true | |
| type: string | |
| default: "main" | |
| release_type: | |
| description: "Release type to publish to PyPI" | |
| required: true | |
| type: choice | |
| options: | |
| - stable | |
| - prerelease | |
| default: stable | |
| dry_run: | |
| description: "Validate and build without publishing to PyPI or creating a GitHub Release" | |
| required: true | |
| type: boolean | |
| default: false | |
| jobs: | |
| validate: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| outputs: | |
| commit_sha: ${{ steps.validate.outputs.commit_sha }} | |
| dry_run: ${{ steps.validate.outputs.dry_run }} | |
| release_tag: ${{ steps.validate.outputs.release_tag }} | |
| release_type: ${{ steps.validate.outputs.release_type }} | |
| version: ${{ steps.validate.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| ref: ${{ github.event.inputs.ref }} | |
| fetch-depth: 0 | |
| - name: Set up mise | |
| uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 | |
| with: | |
| cache: true | |
| experimental: true | |
| - name: Validate release inputs | |
| id: validate | |
| run: | | |
| mise exec -- python py/scripts/validate-release.py \ | |
| "${{ github.event.inputs.release_type }}" \ | |
| --github-output "$GITHUB_OUTPUT" | |
| echo "dry_run=${{ github.event.inputs.dry_run }}" >> "$GITHUB_OUTPUT" | |
| build-and-publish: | |
| needs: validate | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: write | |
| id-token: write # Required for PyPI trusted publishing | |
| env: | |
| COMMIT_SHA: ${{ needs.validate.outputs.commit_sha }} | |
| DRY_RUN: ${{ needs.validate.outputs.dry_run }} | |
| RELEASE_TAG: ${{ needs.validate.outputs.release_tag }} | |
| RELEASE_TYPE: ${{ needs.validate.outputs.release_type }} | |
| VERSION: ${{ needs.validate.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| with: | |
| ref: ${{ env.COMMIT_SHA }} | |
| fetch-depth: 0 | |
| - name: Set up mise | |
| uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3.6.3 | |
| with: | |
| cache: true | |
| experimental: true | |
| - name: Build and verify | |
| run: | | |
| mise exec -- make -C py install-dev verify-build | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | |
| with: | |
| name: python-sdk-dist | |
| path: py/dist/ | |
| retention-days: 5 | |
| - name: Publish to PyPI | |
| if: env.DRY_RUN != 'true' | |
| uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 | |
| with: | |
| packages-dir: py/dist/ | |
| - name: Create local release tag | |
| run: git tag "$RELEASE_TAG" "$COMMIT_SHA" | |
| # Create GitHub Release | |
| - name: Generate release notes | |
| id: release_notes | |
| run: | | |
| RELEASE_NOTES=$(.github/scripts/generate-release-notes.sh "${{ env.RELEASE_TAG }}" "py/") | |
| echo "notes<<EOF" >> $GITHUB_OUTPUT | |
| echo "$RELEASE_NOTES" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| echo "release_name=Python SDK v${VERSION}" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release | |
| if: env.DRY_RUN != 'true' | |
| uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 | |
| env: | |
| RELEASE_NOTES: ${{ steps.release_notes.outputs.notes }} | |
| RELEASE_NAME: ${{ steps.release_notes.outputs.release_name }} | |
| with: | |
| script: | | |
| await github.rest.repos.createRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| tag_name: process.env.RELEASE_TAG, | |
| target_commitish: process.env.COMMIT_SHA, | |
| name: process.env.RELEASE_NAME, | |
| body: process.env.RELEASE_NOTES, | |
| draft: false, | |
| prerelease: process.env.RELEASE_TYPE === "prerelease" | |
| }); | |
| - name: Summarize dry run | |
| if: env.DRY_RUN == 'true' | |
| run: | | |
| echo "Dry run completed for $RELEASE_TAG from $COMMIT_SHA" | |
| notify-success: | |
| needs: [validate, build-and-publish] | |
| if: always() && needs.build-and-publish.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Post to Slack on success | |
| uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 | |
| with: | |
| method: chat.postMessage | |
| token: ${{ secrets.SLACK_BOT_TOKEN }} | |
| payload: | | |
| channel: C0ABHT0SWA2 | |
| text: "${{ needs.validate.outputs.dry_run == 'true' && '🧪 Python SDK dry run succeeded' || format('✅ Python SDK {0} v{1} published', needs.validate.outputs.release_type, needs.validate.outputs.version) }}" | |
| blocks: | |
| - type: "header" | |
| text: | |
| type: "plain_text" | |
| text: "${{ needs.validate.outputs.dry_run == 'true' && '🧪 Python SDK Dry Run Succeeded' || '✅ Python SDK Published' }}" | |
| - type: "section" | |
| text: | |
| type: "mrkdwn" | |
| text: "${{ needs.validate.outputs.dry_run == 'true' && format('*Mode:* dry run\n*Release type:* {0}\n*Version:* {1}\n*Ref:* {2}\n\n<{3}/{4}/actions/runs/{5}|View Run>', needs.validate.outputs.release_type, needs.validate.outputs.version, github.event.inputs.ref, github.server_url, github.repository, github.run_id) || format('*Release type:* {0}\n*Version:* {1}\n*Package:* <https://pypi.org/project/braintrust/|braintrust>\n\n<{2}/{3}/actions/runs/{4}|View Run>', needs.validate.outputs.release_type, needs.validate.outputs.version, github.server_url, github.repository, github.run_id) }}" | |
| notify-failure: | |
| needs: [validate, build-and-publish] | |
| if: always() && (needs.validate.result == 'failure' || needs.build-and-publish.result == 'failure') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Post to Slack on failure | |
| uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 | |
| with: | |
| method: chat.postMessage | |
| token: ${{ secrets.SLACK_BOT_TOKEN }} | |
| payload: | | |
| channel: C0ABHT0SWA2 | |
| text: "🚨 Python SDK release failed" | |
| blocks: | |
| - type: "header" | |
| text: | |
| type: "plain_text" | |
| text: "🚨 Python SDK Release Failed" | |
| - type: "section" | |
| text: | |
| type: "mrkdwn" | |
| text: "*Release type:* ${{ github.event.inputs.release_type }}\n*Ref:* ${{ github.event.inputs.ref }}\n*Commit:* ${{ needs.validate.outputs.commit_sha || github.sha }}\n\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>" |