diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..02e6242 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,76 @@ +name: Release Python SDK + +on: + push: + tags: + - "release/v*" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: python-release-${{ github.ref }} + cancel-in-progress: false + +jobs: + release: + name: Build and publish to PyPI + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Install dependencies + run: | + set -euo pipefail + + python -m pip install --upgrade pip + python -m pip install build twine pytest + + if [ -f requirements.txt ]; then + python -m pip install -r requirements.txt + fi + + - name: Build package + run: | + set -euo pipefail + + rm -rf dist build *.egg-info + + python -m build + + if [ ! -d dist ] || [ -z "$(ls -A dist/)" ]; then + echo "Error: Build failed - no distributions created" + exit 1 + fi + + ls -lh dist/ + + - name: Validate package + run: | + set -euo pipefail + + python -m twine check dist/* + + - name: Validate PyPI token + env: + PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + run: | + set -euo pipefail + + if [ -z "${PYPI_API_TOKEN:-}" ]; then + echo "Error: PYPI_API_TOKEN secret not configured" + exit 1 + fi + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file