Skip to content

TestPyPI Publishing

TestPyPI Publishing #7

Workflow file for this run

name: PyPI Publishing
# SECURITY NOTE: This workflow uses PyPI Trusted Publishing (OIDC)
# No API tokens required - authentication is handled automatically via GitHub's OIDC token
#
# Prerequisites:
# 1. Configure trusted publisher on PyPI: https://pypi.org/manage/account/publishing/
# 2. Configure trusted publisher on TestPyPI: https://test.pypi.org/manage/account/publishing/
# 3. 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:
environment:
description: 'Environment to publish to'
required: true
default: 'testpypi'
type: choice
options:
- testpypi
- pypi
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 }}
is-release: ${{ steps.config.outputs.is-release }}
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: ${{ needs.get-config.outputs.is-release == 'true' && 'pypi' || github.event.inputs.environment || 'testpypi' }}
url: ${{ needs.get-config.outputs.is-release == 'true' && 'https://pypi.org/p/open-resource-broker' || 'https://test.pypi.org/p/open-resource-broker' }}
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: |
if [[ "${{ needs.get-config.outputs.is-release }}" == "true" ]]; then
{
echo "VERSION=${{ needs.get-config.outputs.package-version }}"
echo "TARGET=pypi"
echo "IS_RELEASE=true"
} >> "$GITHUB_ENV"
else
# Dev version for TestPyPI - use centralized version
{
echo "VERSION=${{ needs.get-config.outputs.package-version }}"
echo "TARGET=testpypi"
} >> "$GITHUB_ENV"
fi
echo "Publishing to: $TARGET 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: Publish to PyPI
if: github.event_name == 'release'
uses: pypa/gh-action-pypi-publish@release/v1
with:
verbose: true
skip-existing: true
- name: Create deployment summary
run: |
{
echo "## Package Published Successfully"
echo ""
if [ "$TARGET" = "pypi" ]; then
echo "**Environment:** Production PyPI"
echo "**Installation:** \`pip install open-resource-broker\`"
else
echo "**Environment:** Test PyPI"
echo "**Installation:** \`pip install --index-url https://test.pypi.org/simple/ open-resource-broker\`"
fi
echo ""
echo "**Version:** $VERSION"
echo "**Commands:**"
echo "- \`orb --help\`"
echo "- \`open-resource-broker --help\`"
} >> "$GITHUB_STEP_SUMMARY"
generate-sbom:
name: Generate SBOM
runs-on: ubuntu-latest
needs: [get-config, publish]
if: github.event_name == 'release' || github.event.inputs.environment == 'pypi'
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