Publish to PyPI #2
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
| # .github/workflows/publish.yml | |
| name: Publish to PyPI | |
| on: | |
| push: | |
| tags: | |
| - "v*" # Triggers on tags like v0.1.0, v1.2.3, etc. | |
| workflow_run: | |
| workflows: ["Release on Github"] | |
| types: | |
| - completed | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| testpypi_only: | |
| description: 'Publish to TestPyPI only (for testing)' | |
| required: false | |
| default: false | |
| type: boolean | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' || | |
| github.event_name == 'push' || | |
| github.event_name == 'workflow_dispatch' | |
| environment: pypi | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.workflow_run.head_branch || github.ref }} | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Check if new tag exists | |
| id: check_tag | |
| run: | | |
| # Fetch all tags | |
| git fetch --tags | |
| # Get the latest tag matching v* pattern | |
| LATEST_TAG=$(git tag -l "v*" --sort=-version:refname | head -n 1) | |
| if [ -z "$LATEST_TAG" ]; then | |
| echo "No tag matching v* pattern found" | |
| echo "tag_exists=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| echo "Found latest tag: $LATEST_TAG" | |
| # For workflow_run events, verify tag is associated with this workflow run | |
| if [ "${{ github.event_name }}" = "workflow_run" ]; then | |
| WORKFLOW_COMMIT="${{ github.event.workflow_run.head_sha }}" | |
| TAG_COMMIT=$(git rev-list -n 1 "$LATEST_TAG") | |
| # Check if tag commit is reachable from workflow commit (same or newer) | |
| # This handles cases where semantic-release creates a new commit or tags existing commit | |
| if git merge-base --is-ancestor "$WORKFLOW_COMMIT" "$TAG_COMMIT" 2>/dev/null || [ "$TAG_COMMIT" = "$WORKFLOW_COMMIT" ]; then | |
| echo "Tag $LATEST_TAG is associated with this workflow run" | |
| echo "tag_exists=true" >> $GITHUB_OUTPUT | |
| echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT | |
| else | |
| echo "Tag $LATEST_TAG is not associated with this workflow run (no new release created)" | |
| echo "tag_exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| # For push (on tag) or workflow_dispatch, assume tag exists | |
| echo "tag_exists=true" >> $GITHUB_OUTPUT | |
| echo "tag=$LATEST_TAG" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.10" | |
| - name: Install Poetry | |
| uses: abatilo/actions-poetry@v4 | |
| with: | |
| poetry-version: "latest" | |
| - name: Install dependencies | |
| run: poetry install --no-interaction | |
| - name: Build package | |
| if: | | |
| github.event_name == 'push' || | |
| github.event_name == 'workflow_dispatch' || | |
| steps.check_tag.outputs.tag_exists == 'true' | |
| run: poetry build | |
| - name: Publish to TestPyPI | |
| if: | | |
| (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || steps.check_tag.outputs.tag_exists == 'true') && | |
| github.event.inputs.testpypi_only == 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ | |
| - name: Publish to PyPI | |
| if: | | |
| (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || steps.check_tag.outputs.tag_exists == 'true') && | |
| github.event.inputs.testpypi_only != 'true' | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |