Skip to content

Commit a93c736

Browse files
committed
CI: Switch to PyPI trusted publishing
Rework release workflow to: - Separate build, publish (to PyPI), and release (to GitHub) jobs - Switch from `twine upload` to PyPI trusted publishing action - Limit permissions for each job
1 parent aa4dca2 commit a93c736

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

.github/workflows/release.yml

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ on:
1818
workflow_dispatch:
1919

2020
jobs:
21-
release:
21+
build:
2222
runs-on: ubuntu-22.04
23-
environment: release
24-
permissions:
25-
# `gh release` requires write permission on repo contents
26-
contents: write
23+
outputs:
24+
anchor: ${{ steps.version.outputs.anchor }}
25+
tag: ${{ steps.version.outputs.tag }}
26+
version: ${{ steps.version.outputs.version }}
2727
steps:
2828
- name: Get code
2929
uses: actions/checkout@v4
@@ -52,29 +52,59 @@ jobs:
5252
echo "tag=$TAG" >> $GITHUB_OUTPUT
5353
echo "anchor=${TAG//[^[:alnum:]]/-}" >> $GITHUB_OUTPUT
5454
55-
- name: Build
55+
- name: Build distribution
5656
run: |
5757
rm -rf build dist django_anymail.egg-info
5858
python -m build
59+
60+
- name: Check metadata
61+
run: |
5962
python -m twine check dist/*
6063
64+
- name: Upload build artifacts
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: dist
68+
path: dist/
69+
retention-days: 7
70+
71+
publish:
72+
needs: [build]
73+
runs-on: ubuntu-22.04
74+
environment:
75+
name: pypi
76+
url: https://pypi.org/p/django-anymail
77+
permissions:
78+
# Required for PyPI trusted publishing
79+
id-token: write
80+
steps:
81+
- name: Download build artifacts
82+
uses: actions/download-artifact@v4
83+
with:
84+
name: dist
85+
path: dist/
6186
- name: Publish to PyPI
62-
env:
63-
TWINE_USERNAME: __token__
64-
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
65-
# For test PyPI, set release var PYPI_REPOSITORY_URL=https://test.pypi.org/legacy/.
66-
# For production PyPI, leave unset (or set to empty string).
67-
TWINE_REPOSITORY_URL: ${{ vars.PYPI_REPOSITORY_URL }}
68-
run: |
69-
python -m twine upload --disable-progress-bar --non-interactive dist/*
87+
uses: pypa/gh-action-pypi-publish@release/v1
7088

89+
release:
90+
needs: [build, publish]
91+
runs-on: ubuntu-22.04
92+
permissions:
93+
# `gh release` requires write permission on repo contents
94+
contents: write
95+
steps:
96+
- name: Download build artifacts
97+
uses: actions/download-artifact@v4
98+
with:
99+
name: dist
100+
path: dist/
71101
- name: Release to GitHub
72102
env:
73103
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
74-
TAG: ${{ steps.version.outputs.tag }}
75-
TITLE: ${{ steps.version.outputs.tag }}
104+
TAG: ${{ needs.build.outputs.tag }}
105+
TITLE: ${{ needs.build.outputs.tag }}
76106
NOTES: |
77-
[Changelog](https://anymail.dev/en/stable/changelog/#${{ steps.version.outputs.anchor }})
107+
[Changelog](https://anymail.dev/en/stable/changelog/#${{ needs.build.outputs.anchor }})
78108
run: |
79109
if ! gh release edit "$TAG" --verify-tag --target "$GITHUB_SHA" --title "$TITLE" --notes "$NOTES"; then
80110
gh release create "$TAG" --verify-tag --target "$GITHUB_SHA" --title "$TITLE" --notes "$NOTES"

0 commit comments

Comments
 (0)