Skip to content

Release

Release #5

Workflow file for this run

# Release workflow for the python-sdk.
#
# Triggered by tag-release.yml (workflow_dispatch at the new tag) or by a
# manually pushed `v*` tag. Builds the sdist/wheel, publishes to PyPI via a
# Trusted Publisher (OIDC - no stored API token), and creates a GitHub Release
# whose body is the matching section from CHANGELOG.md with auto-generated
# commit notes appended.
#
# ----------------------------------------------------------------------------
# Trusted Publishing setup (do this once on PyPI - no secrets in GitHub):
# https://docs.pypi.org/trusted-publishers/
#
# On https://pypi.org, add a GitHub Actions trusted publisher to the
# `chatbotkit` project (Manage -> Publishing) with these exact values:
# Owner: chatbotkit
# Repository name: python-sdk
# Workflow name: release.yml
# Environment name: pypi
#
# For the very first release (the project does not exist on PyPI yet) use a
# "pending" publisher instead: https://pypi.org/manage/account/publishing/
# with the same four values plus the project name `chatbotkit`.
#
# Also create a GitHub Environment named `pypi` on the python-sdk repo
# (Settings -> Environments) to match `environment.name` below. Configure it:
# - Deployment branches and tags -> "Selected" -> add a tag rule `v*`.
# This is what enforces "release only from a tag": a manual workflow_dispatch
# off `next`/`main` is blocked at this gate, so no OIDC token is minted and
# nothing is uploaded. Publishing can only happen from a `v*` tag ref.
# - Optionally add required reviewers for a manual approval gate before upload.
# ----------------------------------------------------------------------------
name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
# No permissions by default; each job requests only what it needs.
permissions: {}
jobs:
build:
name: Build distributions
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Build sdist and wheel
run: |
python -m pip install --upgrade pip
pip install build twine
python -m build
twine check dist/*
- name: Extract changelog section for this version
run: |
VERSION="${GITHUB_REF_NAME#v}"
if [ -f CHANGELOG.md ]; then
awk -v ver="$VERSION" '
$0 ~ ("^## \\[" ver "\\]") { capture = 1; next }
capture && /^## \[/ { exit }
capture { print }
' CHANGELOG.md > release-notes.md
fi
if [ ! -s release-notes.md ]; then
echo "Release v${VERSION}. See the full changelog in CHANGELOG.md." > release-notes.md
fi
- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
- name: Upload release notes
uses: actions/upload-artifact@v4
with:
name: release-notes
path: release-notes.md
publish-pypi:
name: Publish to PyPI
needs: build
runs-on: ubuntu-latest
# The Trusted Publisher on PyPI is scoped to this environment name.
environment:
name: pypi
url: https://pypi.org/p/chatbotkit
# OIDC: mint the short-lived token PyPI exchanges for upload rights.
# This job intentionally does nothing else (no checkout of repo code) so the
# id-token can never be exfiltrated by build/test steps.
permissions:
id-token: write
steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
github-release:
name: Create GitHub Release
needs: [build, publish-pypi]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download release notes
uses: actions/download-artifact@v4
with:
name: release-notes
path: .
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
body_path: release-notes.md
generate_release_notes: true