-
Notifications
You must be signed in to change notification settings - Fork 3
84 lines (78 loc) · 3.45 KB
/
Copy pathpython-publish.yml
File metadata and controls
84 lines (78 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
name: Publish Python Package
# Break-glass only. The normal path is sync-upstream-release.yml, which
# publishes the exact wheel its gate tested. Leaving `release: published`
# here would race that upload for the same version.
#
# Use this when the sync workflow cut a release and tagged it, but the PyPI
# upload alone failed. Give it that release's tag: it downloads the .whl and
# .tar.gz attached to the release -- the exact bytes the three-platform gate
# ran against -- and uploads those files unchanged.
#
# It deliberately does NOT build. A rebuild from master would upload bytes no
# gate ever saw, under a version number that already has a tested artifact
# attached to its GitHub release, which is precisely what the tested-wheel
# design exists to prevent.
on:
workflow_dispatch:
inputs:
tag:
description: 'stepss release tag whose attached distributions to upload, e.g. v3.60'
required: true
type: string
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-24.04
timeout-minutes: 15
environment: pypi
permissions:
contents: read
id-token: write
steps:
# No checkout: nothing in the working tree is used or trusted. The
# release assets are the whole input.
- name: Download the release's distributions
env:
TAG: ${{ inputs.tag }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# Same shape the sync workflow enforces on upstream tags, hyphen
# excluded so a prerelease tag cannot be published by hand either.
if ! printf '%s' "$TAG" | grep -qzE '^v[0-9][0-9A-Za-z.+]*$'; then
echo "FAIL: refusing tag: it must match ^v[0-9][0-9A-Za-z.+]*\$ as a single line, with no hyphen"
exit 1
fi
mkdir -p dist
gh release download "$TAG" --repo "$GITHUB_REPOSITORY" \
--pattern '*.whl' --pattern '*.tar.gz' --dir dist
ls -l dist
# A release with no wheel, or with more than one, is not the state
# this workflow is for; uploading blind would be a guess.
# `find`, not `ls dist/*.whl`: an unmatched glob makes `ls` exit
# non-zero, which under `set -o pipefail` would abort the step before
# this clearer message is ever printed.
WHEELS="$(find dist -maxdepth 1 -name '*.whl' | wc -l)"
if [ "$WHEELS" -ne 1 ]; then
echo "FAIL: expected exactly one .whl attached to $TAG, found $WHEELS"
exit 1
fi
# The tag and the wheel must describe the same version, or the
# release's assets were not produced by the sync workflow.
VERSION="${TAG#v}"
WHEEL="$(find dist -maxdepth 1 -name '*.whl')"
case "$(basename "$WHEEL")" in
stepss-"$VERSION"-*) echo "OK: $WHEEL matches $TAG" ;;
*) echo "FAIL: $WHEEL does not match tag $TAG (expected stepss-$VERSION-*)"; exit 1 ;;
esac
# The same action the sync workflow uses, on bytes that were gated on
# Linux, Windows and macOS before the release was cut. Authenticated by
# OIDC trusted publishing, like the sync workflow: no secret is read
# here, and the token GitHub mints names this repository and this
# workflow file, both of which the publisher on PyPI is registered
# against.
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/