-
Notifications
You must be signed in to change notification settings - Fork 0
198 lines (174 loc) · 7.04 KB
/
release.yml
File metadata and controls
198 lines (174 loc) · 7.04 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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
name: release
# Auto-publishes rpr to PyPI, npm, and the Homebrew tap whenever a merge to
# main bumps the version in pyproject.toml. The workflow is a no-op if the
# version hasn't changed (i.e. v<version> is already tagged).
#
# Required secrets (Settings → Secrets and variables → Actions):
# NPM_TOKEN — npmjs.com automation token with publish rights.
# HOMEBREW_TAP_TOKEN — fine-grained PAT with Contents: read/write on
# dedev-llc/homebrew-rpr. Used to commit the bumped
# formula to the tap repo.
#
# PyPI uses Trusted Publishing (OIDC) — no token required. One-time setup:
# 1. https://pypi.org/manage/account/publishing/
# 2. Add a "pending publisher" (or, after first publish, a real one):
# Project name: rpr
# Owner: dedev-llc
# Repository: rpr
# Workflow name: release.yml
# Environment: release
# 3. The pypi job below claims an OIDC token and PyPI verifies it matches.
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: write
concurrency:
group: release
cancel-in-progress: false
jobs:
check-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.v.outputs.version }}
should_release: ${{ steps.v.outputs.should_release }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: v
name: Read version and check if already released
run: |
set -euo pipefail
py_version=$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')
npm_version=$(node -p "require('./npm/package.json').version")
init_version=$(python3 -c 'import re,pathlib; m=re.search(r"__version__\s*=\s*\"([^\"]+)\"", pathlib.Path("src/rpr/__init__.py").read_text()); print(m.group(1) if m else "MISSING")')
if [ "$py_version" != "$npm_version" ] || [ "$py_version" != "$init_version" ]; then
echo "::error::Version mismatch — pyproject.toml=$py_version, npm/package.json=$npm_version, src/rpr/__init__.py=$init_version. Use scripts/bump.sh to bump all three."
exit 1
fi
echo "version=$py_version" >> "$GITHUB_OUTPUT"
if git rev-parse --verify "refs/tags/v$py_version" >/dev/null 2>&1; then
echo "v$py_version already tagged — nothing to release."
echo "should_release=false" >> "$GITHUB_OUTPUT"
else
echo "v$py_version is new — proceeding."
echo "should_release=true" >> "$GITHUB_OUTPUT"
fi
pypi:
needs: check-version
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
environment: release
permissions:
id-token: write # required for Trusted Publishing (OIDC)
contents: read # job-level permissions REPLACE workflow-level, so we
# must re-grant this for actions/checkout to work
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install build tooling
run: python -m pip install --upgrade build
- name: Build sdist + wheel
run: python -m build
- name: Upload to PyPI (Trusted Publishing)
uses: pypa/gh-action-pypi-publish@release/v1
npm:
needs: [check-version, pypi]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
registry-url: "https://registry.npmjs.org"
- name: Publish to npm
working-directory: npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public
homebrew:
needs: [check-version, pypi]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
environment: release
steps:
- name: Wait for PyPI to expose new version
env:
VERSION: ${{ needs.check-version.outputs.version }}
run: |
set -euo pipefail
for i in $(seq 1 30); do
if curl -sSf "https://pypi.org/pypi/rpr/${VERSION}/json" >/dev/null; then
echo "PyPI has rpr ${VERSION}"
exit 0
fi
echo "Waiting for PyPI propagation... (${i}/30)"
sleep 10
done
echo "::error::PyPI never exposed rpr ${VERSION}"
exit 1
- name: Resolve sdist URL and sha256
id: sdist
env:
VERSION: ${{ needs.check-version.outputs.version }}
run: |
set -euo pipefail
json=$(curl -sSf "https://pypi.org/pypi/rpr/${VERSION}/json")
url=$(echo "$json" | python3 -c 'import json,sys; d=json.load(sys.stdin)["urls"]; s=[x for x in d if x["packagetype"]=="sdist"][0]; print(s["url"])')
sha=$(echo "$json" | python3 -c 'import json,sys; d=json.load(sys.stdin)["urls"]; s=[x for x in d if x["packagetype"]=="sdist"][0]; print(s["digests"]["sha256"])')
echo "url=$url" >> "$GITHUB_OUTPUT"
echo "sha=$sha" >> "$GITHUB_OUTPUT"
- name: Checkout tap repo
uses: actions/checkout@v4
with:
repository: dedev-llc/homebrew-rpr
token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
path: tap
- name: Update Formula/rpr.rb
env:
VERSION: ${{ needs.check-version.outputs.version }}
URL: ${{ steps.sdist.outputs.url }}
SHA: ${{ steps.sdist.outputs.sha }}
run: |
set -euo pipefail
python3 - <<'PY'
import os, pathlib, re
formula = pathlib.Path("tap/Formula/rpr.rb")
text = formula.read_text()
text = re.sub(r'^(\s*)url\s+".*"', rf'\1url "{os.environ["URL"]}"', text, count=1, flags=re.M)
text = re.sub(r'^(\s*)sha256\s+".*"', rf'\1sha256 "{os.environ["SHA"]}"', text, count=1, flags=re.M)
formula.write_text(text)
PY
cd tap
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Formula/rpr.rb
git commit -m "rpr ${VERSION}"
git push
tag-and-release:
needs: [check-version, pypi, npm, homebrew]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Tag and create GitHub release
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.check-version.outputs.version }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag "v${VERSION}"
git push origin "v${VERSION}"
gh release create "v${VERSION}" --generate-notes --title "v${VERSION}"