Skip to content

Commit 387a8a9

Browse files
committed
cherry-pick(#3252): devops: publish to PyPI from GitHub Actions with trusted publishing
1 parent 71d2a17 commit 387a8a9

3 files changed

Lines changed: 87 additions & 117 deletions

File tree

‎.azure-pipelines/publish.yml‎

Lines changed: 0 additions & 116 deletions
This file was deleted.

‎.claude/skills/playwright-release/SKILL.md‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,7 @@ gh release list --repo microsoft/playwright-python --limit 3 # v1.xx.0 shows a
154154

155155
Give the user the URL of the draft. Your work ends here. Do not publish the
156156
release: never run `gh release create` without `--draft`, and never run
157-
`gh release edit --draft=false`. Publishing creates the tag.
157+
`gh release edit --draft=false`. Publishing creates the tag and starts
158+
`.github/workflows/publish.yml`, which builds the wheels and uploads them to PyPI
159+
after a reviewer approves the `pypi` environment. Never run that workflow, and
160+
never approve the environment.

‎.github/workflows/publish.yml‎

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: Publish
2+
3+
# Builds the wheels of a release tag and uploads them to PyPI. Uses PyPI trusted
4+
# publishing: PyPI trusts this workflow file in the "pypi" environment, so no
5+
# PyPI token is stored. Runs when a release is published. To publish an existing
6+
# tag, run it by hand with the tag name.
7+
on:
8+
release:
9+
types: [published]
10+
workflow_dispatch:
11+
inputs:
12+
tag:
13+
description: "Release tag to publish, for example v1.64.0"
14+
required: true
15+
16+
permissions:
17+
contents: read
18+
19+
jobs:
20+
build:
21+
name: Build wheels
22+
runs-on: ubuntu-latest
23+
env:
24+
TAG: ${{ inputs.tag || github.event.release.tag_name }}
25+
steps:
26+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27+
with:
28+
ref: refs/tags/${{ env.TAG }}
29+
# setuptools-scm reads the version from the tag.
30+
fetch-depth: 0
31+
- name: Check the tag
32+
run: |
33+
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
34+
echo "Can only publish a release tag (vX.Y.Z), got: $TAG"
35+
exit 1
36+
fi
37+
- name: Set up Python
38+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
39+
with:
40+
python-version: "3.10"
41+
- name: Set up Node.js
42+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
43+
with:
44+
node-version: '24'
45+
- name: Install dependencies
46+
run: python -m pip install "$(grep '^build==' local-requirements.txt)"
47+
- name: Build wheels
48+
run: |
49+
for wheel in $(python setup.py --list-wheels); do
50+
PLAYWRIGHT_TARGET_WHEEL=$wheel python -m build --wheel --outdir dist
51+
done
52+
- name: Check the wheels
53+
run: |
54+
ls -l dist
55+
test "$(ls dist/*.whl | wc -l)" -eq "$(python setup.py --list-wheels | wc -l)"
56+
for file in dist/*; do
57+
if [[ "$(basename "$file")" != "playwright-${TAG#v}-"*.whl ]]; then
58+
echo "Unexpected file for $TAG: $file"
59+
exit 1
60+
fi
61+
done
62+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
63+
with:
64+
name: wheels
65+
path: dist/
66+
if-no-files-found: error
67+
68+
publish:
69+
name: Upload to PyPI
70+
needs: build
71+
runs-on: ubuntu-latest
72+
environment:
73+
name: pypi
74+
url: https://pypi.org/project/playwright/
75+
permissions:
76+
# Lets the job get the GitHub OIDC token that PyPI trusted publishing needs.
77+
id-token: write
78+
steps:
79+
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
80+
with:
81+
name: wheels
82+
path: dist/
83+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2

0 commit comments

Comments
 (0)