-
Notifications
You must be signed in to change notification settings - Fork 110
237 lines (207 loc) · 7.88 KB
/
publish-pypi.yml
File metadata and controls
237 lines (207 loc) · 7.88 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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# This workflow is triggered when a GitHub release is created.
# It can also be run manually to re-publish to PyPI in case it failed for some reason.
name: Publish PyPI
on:
workflow_dispatch:
inputs: {}
release:
types: [published]
jobs:
build_wheels:
name: build wheels (${{ matrix.binary_name }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
binary_name: stagehand-server-v3-linux-x64
output_path: src/stagehand/_sea/stagehand-linux-x64
wheel_platform_tag: manylinux2014_x86_64
- os: macos-latest
binary_name: stagehand-server-v3-darwin-arm64
output_path: src/stagehand/_sea/stagehand-darwin-arm64
wheel_platform_tag: macosx_11_0_arm64
- os: macos-15-intel
binary_name: stagehand-server-v3-darwin-x64
output_path: src/stagehand/_sea/stagehand-darwin-x64
wheel_platform_tag: macosx_10_9_x86_64
- os: windows-latest
binary_name: stagehand-server-v3-win32-x64.exe
output_path: src/stagehand/_sea/stagehand-win32-x64.exe
wheel_platform_tag: win_amd64
runs-on: ${{ matrix.os }}
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.9.13"
- name: Resolve latest stagehand/server-v3 release
id: stagehand-server-release
uses: actions/github-script@v6
with:
github-token: ${{ secrets.STAGEHAND_SOURCE_TOKEN || github.token }}
script: |
const { data } = await github.rest.repos.listReleases({
owner: 'browserbase',
repo: 'stagehand',
per_page: 100,
});
const parseStableTag = (tag) => {
if (typeof tag !== 'string') return null;
const match = /^stagehand-server-v3\/v(\d+)\.(\d+)\.(\d+)$/.exec(tag);
if (!match) return null;
return match.slice(1).map(Number);
};
let best = null;
for (const release of data) {
if (release.draft || release.prerelease) continue;
const version = parseStableTag(release.tag_name);
if (!version) continue;
if (!best) {
best = { release, version };
continue;
}
const isGreater =
version[0] > best.version[0] ||
(version[0] === best.version[0] && version[1] > best.version[1]) ||
(version[0] === best.version[0] && version[1] === best.version[1] && version[2] > best.version[2]);
if (isGreater) {
best = { release, version };
}
}
if (!best) {
core.setFailed('No stable stagehand-server-v3/vX.Y.Z release found in browserbase/stagehand');
return;
}
core.info(`Using stagehand/server-v3 release tag: ${best.release.tag_name}`);
core.setOutput('tag', best.release.tag_name);
core.setOutput('id', String(best.release.id));
- name: Download stagehand/server SEA binary (from GitHub Release assets)
env:
GH_TOKEN: ${{ secrets.STAGEHAND_SOURCE_TOKEN || github.token }}
RELEASE_TAG: ${{ steps.stagehand-server-release.outputs.tag }}
RELEASE_ID: ${{ steps.stagehand-server-release.outputs.id }}
ASSET_NAME: ${{ matrix.binary_name }}
OUTPUT_PATH: ${{ matrix.output_path }}
shell: bash
run: |
set -euo pipefail
# Ensure we only ship the binary for this runner's OS/arch.
python - <<'PY'
from pathlib import Path
sea_dir = Path("src/stagehand/_sea")
sea_dir.mkdir(parents=True, exist_ok=True)
for p in sea_dir.glob("stagehand-*"):
p.unlink(missing_ok=True)
for p in sea_dir.glob("*.exe"):
p.unlink(missing_ok=True)
PY
echo "Downloading ${ASSET_NAME} from browserbase/stagehand@${RELEASE_TAG}"
url="$(
curl -fsSL \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/browserbase/stagehand/releases/${RELEASE_ID}" \
| python -c 'import json,sys; d=json.load(sys.stdin); a=next((x for x in d.get("assets",[]) if x.get("name")==sys.argv[1]), None); print(a.get("url","") if a else "")' \
"${ASSET_NAME}"
)"
if [ -z "${url}" ]; then
echo "Release asset not found: ${ASSET_NAME} (tag=${RELEASE_TAG})" >&2
exit 1
fi
mkdir -p "$(dirname "${OUTPUT_PATH}")"
curl -fsSL \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/octet-stream" \
"${url}" \
-o "${OUTPUT_PATH}"
chmod +x "${OUTPUT_PATH}" 2>/dev/null || true
rm -f src/stagehand/_sea/.keep || true
- name: Build wheel
env:
STAGEHAND_WHEEL_TAG: py3-none-${{ matrix.wheel_platform_tag }}
run: uv build --wheel
- name: Log SEA contents
shell: bash
run: |
echo "Contents of src/stagehand/_sea/"
ls -al src/stagehand/_sea || true
python - <<'PY'
import pathlib, zipfile, collections, sys
had_error = False
for wheel in sorted(pathlib.Path("dist").glob("*.whl")):
print(f"Contents of {wheel.name} entries matching stagehand/_sea")
with zipfile.ZipFile(wheel, "r") as zf:
names = [info.filename for info in zf.infolist()]
counts = collections.Counter(names)
dups = sorted([name for name, n in counts.items() if n > 1])
for info in zf.infolist():
if "stagehand/_sea/" in info.filename:
print(info.filename)
if dups:
had_error = True
print("ERROR: duplicate zip entries detected:")
for name in dups:
print(f" {counts[name]}x {name}")
if had_error:
sys.exit(1)
PY
- name: Upload wheel artifact
uses: actions/upload-artifact@v4
with:
name: wheel-${{ matrix.binary_name }}
path: dist/*.whl
retention-days: 7
build_sdist:
name: build sdist
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.9.13"
- name: Build sdist
run: uv build --sdist
- name: Upload sdist artifact
uses: actions/upload-artifact@v4
with:
name: sdist
path: dist/*.tar.gz
retention-days: 7
publish:
name: publish
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "0.9.13"
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: dist
- name: Flatten dist directory
shell: bash
run: |
set -euo pipefail
mkdir -p dist_out
find dist -type f \( -name "*.whl" -o -name "*.tar.gz" \) -print0 | while IFS= read -r -d '' f; do
cp -f "$f" dist_out/
done
ls -la dist_out
- name: Publish to PyPI
env:
PYPI_TOKEN: ${{ secrets.STAGEHAND_PYPI_TOKEN || secrets.PYPI_TOKEN }}
run: |
set -euo pipefail
uv publish --token="$PYPI_TOKEN" dist_out/*