Skip to main content
Version: Next

PyPI Publish Workflow

View Source

Publish Python packages to PyPI (Python Package Index) or TestPyPI.

Overviewโ€‹

This workflow publishes built Python packages to PyPI or TestPyPI using either OIDC (OpenID Connect) trusted publishing or API token authentication.

When to Useโ€‹

  • โœ… You need to publish packages to PyPI
  • โœ… You want to deploy to TestPyPI for testing
  • โœ… You're automating package releases
  • โœ… You need secure, automated publishing

Workflow Architectureโ€‹

Inputsโ€‹

Required Inputsโ€‹

None - uses artifacts from previous jobs

Optional Inputsโ€‹

InputTypeDefaultDescription
repositorystring'pypi'Target repository (pypi, testpypi)
auth_methodstring'oidc'Authentication method (oidc, token)
package_pathstring'dist/'Path to package files
skip_existingbooleanfalseSkip if version already exists
verify_metadatabooleantrueVerify package metadata before upload

Secretsโ€‹

For OIDC Authenticationโ€‹

No secrets required - uses GitHub OIDC tokens

For Token Authenticationโ€‹

SecretDescription
pypi_tokenPyPI API token
test_pypi_tokenTestPyPI API token (if using TestPyPI)

Outputsโ€‹

OutputDescription
package_urlURL to published package on PyPI
package_versionPublished package version
publication_statusSuccess or failure status

Usage Examplesโ€‹

name: Publish

on:
release:
types: [published]

permissions:
id-token: write # Required for OIDC
contents: read

jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master

publish:
needs: build
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_push_pypi.yaml@master
with:
repository: pypi
auth_method: oidc

Using API Tokenโ€‹

jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master

publish:
needs: build
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_push_pypi.yaml@master
secrets:
pypi_token: ${{ secrets.PYPI_API_TOKEN }}
with:
repository: pypi
auth_method: token

Publish to TestPyPIโ€‹

jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master

test-publish:
needs: build
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_push_pypi.yaml@master
secrets:
pypi_token: ${{ secrets.TEST_PYPI_API_TOKEN }}
with:
repository: testpypi
auth_method: token

Complete Release Pipelineโ€‹

name: Release

on:
push:
tags:
- 'v*'

permissions:
id-token: write
contents: write

jobs:
build:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_python_package.yaml@master
with:
python_version: '3.11'
validate_package: true

test-publish:
needs: build
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_push_pypi.yaml@master
secrets:
pypi_token: ${{ secrets.TEST_PYPI_API_TOKEN }}
with:
repository: testpypi
auth_method: token

publish:
needs: test-publish
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_push_pypi.yaml@master
with:
repository: pypi
auth_method: oidc

How It Worksโ€‹

Step 1: Download Artifactsโ€‹

Downloads package distributions from build job:

- uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/

Step 2: Verify Metadataโ€‹

Validates package before upload:

twine check dist/*

Step 3: Authenticateโ€‹

OIDC Authenticationโ€‹

Requests OIDC token from GitHub:

- uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://upload.pypi.org/legacy/

Token Authenticationโ€‹

Uses provided API token:

- uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.pypi_token }}
repository-url: https://upload.pypi.org/legacy/

Step 4: Upload Packageโ€‹

Uploads package to PyPI:

twine upload dist/*

Step 5: Verify Publicationโ€‹

Confirms package is available:

pip index versions my-package

Authentication Methodsโ€‹

Advantages:

  • โœ… No secrets to manage
  • โœ… More secure
  • โœ… Automatic token rotation
  • โœ… Scoped permissions

Setup:

  1. Configure PyPI Trusted Publisher:

    • Go to PyPI โ†’ Account Settings โ†’ Publishing
    • Add GitHub as trusted publisher
    • Specify: owner/repo, workflow name, environment (optional)
  2. Add permissions to workflow:

    permissions:
    id-token: write
    contents: read
  3. Use OIDC authentication:

    with:
    auth_method: oidc

Token Authenticationโ€‹

Advantages:

  • โœ… Works with all PyPI-compatible repositories
  • โœ… Simple setup
  • โœ… Backward compatible

Setup:

  1. Generate API token on PyPI:

    • Go to Account Settings โ†’ API tokens
    • Create token (project-scoped recommended)
  2. Add token to GitHub Secrets:

    • Repository Settings โ†’ Secrets โ†’ Actions
    • Add PYPI_API_TOKEN
  3. Use token authentication:

    secrets:
    pypi_token: ${{ secrets.PYPI_API_TOKEN }}
    with:
    auth_method: token

Repository Targetsโ€‹

PyPI (Production)โ€‹

Main Python Package Index:

repository: pypi

URL: https://pypi.org/
Upload URL: https://upload.pypi.org/legacy/

TestPyPI (Testing)โ€‹

Testing environment:

repository: testpypi

URL: https://test.pypi.org/
Upload URL: https://test.pypi.org/legacy/

Testing installation:

pip install --index-url https://test.pypi.org/simple/ my-package

Best Practicesโ€‹

1. Test Before Productionโ€‹

Always test on TestPyPI first:

jobs:
test-publish:
uses: ./.github/workflows/rw_push_pypi.yaml
with:
repository: testpypi

publish:
needs: test-publish
uses: ./.github/workflows/rw_push_pypi.yaml
with:
repository: pypi

2. Use OIDC When Possibleโ€‹

Prefer OIDC over tokens:

permissions:
id-token: write

with:
auth_method: oidc

3. Verify Metadataโ€‹

Always verify before upload:

with:
verify_metadata: true

4. Version Managementโ€‹

Ensure unique versions:

[project]
version = "1.0.0" # Increment for each release

5. Skip Existing Versionsโ€‹

Prevent re-upload errors:

with:
skip_existing: true

Troubleshootingโ€‹

OIDC Authentication Failsโ€‹

Symptoms:

  • "OIDC token validation failed"
  • Permission denied errors

Solutions:

  1. Verify PyPI trusted publisher configuration:

    • Repository name matches exactly
    • Workflow filename is correct
    • Environment name matches (if specified)
  2. Check workflow permissions:

    permissions:
    id-token: write
  3. Ensure using correct PyPI account

Token Authentication Failsโ€‹

Symptoms:

  • "Invalid credentials"
  • "Authentication failed"

Solutions:

  1. Verify token is correct:

    • Check token hasn't expired
    • Ensure token has correct scope
  2. Check secret name:

    secrets:
    pypi_token: ${{ secrets.PYPI_API_TOKEN }}
  3. Regenerate token if necessary

Version Already Existsโ€‹

Symptoms:

  • "File already exists" error
  • Upload rejected

Solutions:

  1. Increment version number:

    version = "1.0.1"  # Bump version
  2. Use skip_existing:

    with:
    skip_existing: true
  3. Delete old version from PyPI (not recommended)

Package Upload Failsโ€‹

Symptoms:

  • Upload times out
  • Network errors

Solutions:

  1. Check package size (PyPI has limits)
  2. Verify network connectivity
  3. Retry upload
  4. Check PyPI status page

Package Verificationโ€‹

After Publicationโ€‹

Verify package is available:

# Check package exists
pip index versions my-package

# Install and test
pip install my-package
python -c "import my_package; print(my_package.__version__)"

Metadata Verificationโ€‹

Check package page on PyPI:

  • Description renders correctly
  • Links work
  • Classifiers are correct
  • Version is correct

Security Considerationsโ€‹

1. Token Securityโ€‹

  • โœ… Use project-scoped tokens
  • โœ… Rotate tokens regularly
  • โœ… Never commit tokens to repository
  • โœ… Use GitHub Secrets for storage

2. OIDC Securityโ€‹

  • โœ… Configure trusted publishers correctly
  • โœ… Use environment protection rules
  • โœ… Limit workflow permissions
  • โœ… Review OIDC claims

3. Package Securityโ€‹

  • โœ… Sign packages (optional)
  • โœ… Use HTTPS for uploads
  • โœ… Verify package integrity
  • โœ… Enable 2FA on PyPI account

Additional Resourcesโ€‹