Skip to content

TestPyPI Publishing #21

TestPyPI Publishing

TestPyPI Publishing #21

Workflow file for this run

name: TestPyPI Publishing
# SECURITY NOTE: This workflow uses PyPI Trusted Publishing (OIDC)
# No API tokens required - authentication is handled automatically via GitHub's OIDC token
#
# This workflow publishes to TestPyPI ONLY for development testing.
# Production releases to PyPI are handled by prod-release.yml
#
# Prerequisites:
# 1. Configure trusted publisher on TestPyPI: https://test.pypi.org/manage/account/publishing/
# 2. See docs/deployment/pypi-setup.md for detailed setup instructions
env:
# Comment trigger words for package publishing
PUBLISH_TRIGGERS: "/package"
on:
push:
branches: [main]
paths:
- 'src/**'
- 'pyproject.toml'
- 'requirements*.txt'
- 'uv.lock'
workflow_run:
workflows: ["Quality Checks", "Unit Tests"]
types: [completed]
branches: [main]
workflow_dispatch:
inputs:
force:
description: 'Force publish even if version exists'
required: false
default: false
type: boolean
concurrency:
group: "pypi-publishing"
cancel-in-progress: false
jobs:
get-config:
name: Get Configuration
runs-on: ubuntu-latest
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
outputs:
default-python-version: ${{ steps.config.outputs.default-python-version }}
package-version: ${{ steps.config.outputs.package-version }}
pypi-name: ${{ steps.config.outputs.pypi-name }}
steps:
- name: Checkout code
uses: actions/checkout@v6.0.1
- name: Get project configuration
id: config
uses: ./.github/actions/get-config
publish:
name: Build and Publish Package
runs-on: ubuntu-latest
needs: [get-config]
environment:
name: testpypi
url: https://test.pypi.org/p/${{ needs.get-config.outputs.pypi-name }}
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
contents: read # needed to checkout code
steps:
- name: Checkout code
uses: actions/checkout@v6.0.1
with:
ref: ${{ github.sha }}
- name: Determine version and target
run: |
{
echo "VERSION=${{ needs.get-config.outputs.package-version }}"
echo "TARGET=testpypi"
} >> "$GITHUB_ENV"
echo "Publishing to: TestPyPI with version: $VERSION"
- name: Setup Python and UV
uses: ./.github/actions/setup-uv-cached
with:
cache-key: deps-${{ needs.get-config.outputs.default-python-version }}-${{ hashFiles('.project.yml', 'pyproject.toml', 'requirements*.txt') }}
fail-on-cache-miss: false
- name: Build package
run: |
make build
- name: Check package
run: |
make test-install
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
verbose: true
skip-existing: true
- name: Create deployment summary
run: |
{
echo "## Package Published Successfully"
echo ""
echo "**Environment:** Test PyPI"
echo "**Installation:** \`pip install --index-url https://test.pypi.org/simple/ ${{ needs.get-config.outputs.pypi-name }}\`"
echo ""
echo "**Version:** $VERSION"
echo "**Commands:**"
echo "- \`orb --help\`"
} >> "$GITHUB_STEP_SUMMARY"
generate-sbom:
name: Generate SBOM
runs-on: ubuntu-latest
needs: [get-config, publish]
permissions:
contents: read
actions: write
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v6.0.1
- name: Setup Python and UV
uses: ./.github/actions/setup-uv-cached
with:
cache-key: deps-${{ needs.get-config.outputs.default-python-version }}-${{ hashFiles('.project.yml', 'pyproject.toml', 'requirements*.txt') }}
fail-on-cache-miss: false
- name: Generate SBOM files
run: |
make ci-build-sbom
- name: Upload SBOM artifacts
uses: actions/upload-artifact@v4
with:
name: reports-sbom-${{ needs.get-config.outputs.package-version }}
path: |
python-sbom-cyclonedx.json
python-sbom-spdx.json
retention-days: 180
- name: Upload SBOM to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always()
with:
sarif_file: python-sbom-cyclonedx.json
continue-on-error: true