|
1 | 1 | # Release workflow for the python-sdk. |
2 | 2 | # |
3 | 3 | # Triggered by tag-release.yml (workflow_dispatch at the new tag) or by a |
4 | | -# manually pushed `v*` tag. Builds the sdist/wheel, publishes to PyPI (only if |
5 | | -# a PYPI_API_TOKEN secret is configured), and creates a GitHub Release whose |
6 | | -# body is the matching section from CHANGELOG.md with auto-generated commit |
7 | | -# notes appended. |
| 4 | +# manually pushed `v*` tag. Builds the sdist/wheel, publishes to PyPI via a |
| 5 | +# Trusted Publisher (OIDC - no stored API token), and creates a GitHub Release |
| 6 | +# whose body is the matching section from CHANGELOG.md with auto-generated |
| 7 | +# commit notes appended. |
8 | 8 | # |
9 | | -# To enable PyPI publishing, add a `PYPI_API_TOKEN` secret (a PyPI API token) |
10 | | -# to this repository. Without it, the build still runs and the GitHub Release is |
11 | | -# still created; only the upload step is skipped. |
| 9 | +# ---------------------------------------------------------------------------- |
| 10 | +# Trusted Publishing setup (do this once on PyPI - no secrets in GitHub): |
| 11 | +# https://docs.pypi.org/trusted-publishers/ |
| 12 | +# |
| 13 | +# On https://pypi.org, add a GitHub Actions trusted publisher to the |
| 14 | +# `chatbotkit` project (Manage -> Publishing) with these exact values: |
| 15 | +# Owner: chatbotkit |
| 16 | +# Repository name: python-sdk |
| 17 | +# Workflow name: release.yml |
| 18 | +# Environment name: pypi |
| 19 | +# |
| 20 | +# For the very first release (the project does not exist on PyPI yet) use a |
| 21 | +# "pending" publisher instead: https://pypi.org/manage/account/publishing/ |
| 22 | +# with the same four values plus the project name `chatbotkit`. |
| 23 | +# |
| 24 | +# Also create a GitHub Environment named `pypi` on the python-sdk repo |
| 25 | +# (Settings -> Environments) to match `environment.name` below. Add required |
| 26 | +# reviewers there if you want a manual approval gate before every upload. |
| 27 | +# ---------------------------------------------------------------------------- |
12 | 28 | name: Release |
13 | 29 |
|
14 | 30 | on: |
|
17 | 33 | - 'v*' |
18 | 34 | workflow_dispatch: |
19 | 35 |
|
20 | | -permissions: |
21 | | - contents: write |
| 36 | +# No permissions by default; each job requests only what it needs. |
| 37 | +permissions: {} |
22 | 38 |
|
23 | 39 | jobs: |
24 | | - release: |
| 40 | + build: |
| 41 | + name: Build distributions |
25 | 42 | runs-on: ubuntu-latest |
| 43 | + permissions: |
| 44 | + contents: read |
26 | 45 | steps: |
27 | 46 | - name: Checkout |
28 | 47 | uses: actions/checkout@v4 |
|
41 | 60 | python -m build |
42 | 61 | twine check dist/* |
43 | 62 |
|
44 | | - - name: Detect PyPI token |
45 | | - id: token |
46 | | - env: |
47 | | - PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} |
48 | | - run: | |
49 | | - if [ -n "$PYPI_API_TOKEN" ]; then |
50 | | - echo "present=true" >> "$GITHUB_OUTPUT" |
51 | | - else |
52 | | - echo "present=false" >> "$GITHUB_OUTPUT" |
53 | | - echo "PYPI_API_TOKEN not set - skipping PyPI upload." >&2 |
54 | | - fi |
55 | | -
|
56 | | - - name: Publish to PyPI |
57 | | - if: steps.token.outputs.present == 'true' |
58 | | - env: |
59 | | - TWINE_USERNAME: __token__ |
60 | | - TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} |
61 | | - run: twine upload --non-interactive dist/* |
62 | | - |
63 | 63 | - name: Extract changelog section for this version |
64 | | - id: changelog |
65 | 64 | run: | |
66 | 65 | VERSION="${GITHUB_REF_NAME#v}" |
67 | 66 | if [ -f CHANGELOG.md ]; then |
|
75 | 74 | echo "Release v${VERSION}. See the full changelog in CHANGELOG.md." > release-notes.md |
76 | 75 | fi |
77 | 76 |
|
| 77 | + - name: Upload distributions |
| 78 | + uses: actions/upload-artifact@v4 |
| 79 | + with: |
| 80 | + name: dist |
| 81 | + path: dist/ |
| 82 | + |
| 83 | + - name: Upload release notes |
| 84 | + uses: actions/upload-artifact@v4 |
| 85 | + with: |
| 86 | + name: release-notes |
| 87 | + path: release-notes.md |
| 88 | + |
| 89 | + publish-pypi: |
| 90 | + name: Publish to PyPI |
| 91 | + needs: build |
| 92 | + runs-on: ubuntu-latest |
| 93 | + # The Trusted Publisher on PyPI is scoped to this environment name. |
| 94 | + environment: |
| 95 | + name: pypi |
| 96 | + url: https://pypi.org/p/chatbotkit |
| 97 | + # OIDC: mint the short-lived token PyPI exchanges for upload rights. |
| 98 | + # This job intentionally does nothing else (no checkout of repo code) so the |
| 99 | + # id-token can never be exfiltrated by build/test steps. |
| 100 | + permissions: |
| 101 | + id-token: write |
| 102 | + steps: |
| 103 | + - name: Download distributions |
| 104 | + uses: actions/download-artifact@v4 |
| 105 | + with: |
| 106 | + name: dist |
| 107 | + path: dist/ |
| 108 | + |
| 109 | + - name: Publish to PyPI |
| 110 | + uses: pypa/gh-action-pypi-publish@release/v1 |
| 111 | + |
| 112 | + github-release: |
| 113 | + name: Create GitHub Release |
| 114 | + needs: [build, publish-pypi] |
| 115 | + runs-on: ubuntu-latest |
| 116 | + permissions: |
| 117 | + contents: write |
| 118 | + steps: |
| 119 | + - name: Download release notes |
| 120 | + uses: actions/download-artifact@v4 |
| 121 | + with: |
| 122 | + name: release-notes |
| 123 | + path: . |
| 124 | + |
78 | 125 | - name: Create GitHub Release |
79 | 126 | uses: softprops/action-gh-release@v2 |
80 | 127 | with: |
|
0 commit comments