I recently came across a pretty nice pattern for using GitHub Workflows to automatically publish packages to PyPI when new tags are created. This lets you generate a new release via the GitHub Draft a New Release
UI. (e.g. here’s the page for the pydata sphinx theme). Writing it down here in case it’s useful for others and for me to re-discover in the future!
This will allow anybody who can create a repository tag to also create a release! That could either be a good or bad thing depending on your aversion to risk!
Here are the quick steps:
-
Generate a release secret via PyPI for your account.
-
Create a new secret for your repository via
settings
→secrets
→actions
→New repository secret
: -
Paste in the PyPI token that you just created, e.g.
-
You can now use this secret to authenticate PyPI in your GitHub Workflows
-
In your tests workflow, add a
workflow_call
trigger, which will allow other workflows to call it on their own. E.g. you might have something like this in atests.yml
workflow:name: continuous-integration on: push: branches: - main pull_request: workflow_call: ...your tests steps here
-
Create a
publish.yml
workflow to publish your package. Make it call, and need success for your tests workflow. Then make it publish your package upon success. Use a template like below (note the${{ secrets.PYPI_KEY }}
, which re-uses the secret you stored above).# Build the package and publish it to PyPI after tests pass. name: Publish to PyPI on: push: tags: - "*" jobs: tests: uses: ./.github/workflows/tests.yml publish: name: publish needs: [tests] # require tests to pass before deploy runs runs-on: ubuntu-latest steps: - name: Checkout source uses: actions/checkout@v3 - name: Set up Python 3.9 uses: actions/setup-python@v4 with: python-version: 3.9 - name: Build package run: | python -m pip install -U pip build python -m build - name: Publish uses: pypa/gh-action-pypi-publish@v1.5.0 with: user: __token__ password: ${{ secrets.PYPI_KEY }}
And that should be it! Now to create a release you should simply do so via the GitHub repository UI, and when this happens it will trigger the publish.yml
workflow, which will call tests.yml
and wait for it to pass, and if so then it will publish to PyPI.
I hope this is useful!