PyPI Publish Workflow
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โ
| Input | Type | Default | Description |
|---|---|---|---|
repository | string | 'pypi' | Target repository (pypi, testpypi) |
auth_method | string | 'oidc' | Authentication method (oidc, token) |
package_path | string | 'dist/' | Path to package files |
skip_existing | boolean | false | Skip if version already exists |
verify_metadata | boolean | true | Verify package metadata before upload |
Secretsโ
For OIDC Authenticationโ
No secrets required - uses GitHub OIDC tokens
For Token Authenticationโ
| Secret | Description |
|---|---|
pypi_token | PyPI API token |
test_pypi_token | TestPyPI API token (if using TestPyPI) |
Outputsโ
| Output | Description |
|---|---|
package_url | URL to published package on PyPI |
package_version | Published package version |
publication_status | Success or failure status |
Usage Examplesโ
Basic Usage with OIDC (Recommended)โ
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โ
OIDC (Recommended)โ
Advantages:
- โ No secrets to manage
- โ More secure
- โ Automatic token rotation
- โ Scoped permissions
Setup:
-
Configure PyPI Trusted Publisher:
- Go to PyPI โ Account Settings โ Publishing
- Add GitHub as trusted publisher
- Specify:
owner/repo, workflow name, environment (optional)
-
Add permissions to workflow:
permissions:
id-token: write
contents: read -
Use OIDC authentication:
with:
auth_method: oidc
Token Authenticationโ
Advantages:
- โ Works with all PyPI-compatible repositories
- โ Simple setup
- โ Backward compatible
Setup:
-
Generate API token on PyPI:
- Go to Account Settings โ API tokens
- Create token (project-scoped recommended)
-
Add token to GitHub Secrets:
- Repository Settings โ Secrets โ Actions
- Add
PYPI_API_TOKEN
-
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:
-
Verify PyPI trusted publisher configuration:
- Repository name matches exactly
- Workflow filename is correct
- Environment name matches (if specified)
-
Check workflow permissions:
permissions:
id-token: write -
Ensure using correct PyPI account
Token Authentication Failsโ
Symptoms:
- "Invalid credentials"
- "Authentication failed"
Solutions:
-
Verify token is correct:
- Check token hasn't expired
- Ensure token has correct scope
-
Check secret name:
secrets:
pypi_token: ${{ secrets.PYPI_API_TOKEN }} -
Regenerate token if necessary
Version Already Existsโ
Symptoms:
- "File already exists" error
- Upload rejected
Solutions:
-
Increment version number:
version = "1.0.1" # Bump version -
Use skip_existing:
with:
skip_existing: true -
Delete old version from PyPI (not recommended)
Package Upload Failsโ
Symptoms:
- Upload times out
- Network errors
Solutions:
- Check package size (PyPI has limits)
- Verify network connectivity
- Retry upload
- 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
Related Workflowsโ
- rw_python_package - Build packages
- rw_pre-building_test - Test package installation
- rw_checking_deployment_state - Check deployment state
- rw_release_complete - Complete release process