TestPyPI Publishing #5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |