Skip to content

Commit 180a1c8

Browse files
committed
Moved server binary build into release.yaml
1 parent 51e0170 commit 180a1c8

File tree

2 files changed

+258
-257
lines changed

2 files changed

+258
-257
lines changed

.github/workflows/release.yml

Lines changed: 258 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ jobs:
1616
release:
1717
name: Release
1818
runs-on: ubuntu-latest
19+
outputs:
20+
server_published: ${{ steps.server_meta.outputs.server_published }}
21+
server_version: ${{ steps.server_meta.outputs.server_version }}
22+
server_tag: ${{ steps.server_meta.outputs.server_tag }}
1923
steps:
2024
- name: Checkout Repo
2125
uses: actions/checkout@v4
@@ -49,24 +53,35 @@ jobs:
4953
env:
5054
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5155

52-
- name: Tag stagehand/server version for GitHub Releases
53-
env:
54-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
56+
- name: Detect stagehand/server publish
57+
id: server_meta
5558
run: |
5659
set -euo pipefail
5760
5861
SERVER_VERSION="$(node -p "require('./packages/server/package.json').version")"
5962
TAG="stagehand-server/v${SERVER_VERSION}"
60-
BEFORE_SHA="${{ github.event.before }}"
61-
62-
if [ -n "${BEFORE_SHA}" ] && [ "${BEFORE_SHA}" != "0000000000000000000000000000000000000000" ]; then
63-
BEFORE_VERSION="$(git show "${BEFORE_SHA}:packages/server/package.json" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin)['version'])" 2>/dev/null || true)"
64-
if [ -n "${BEFORE_VERSION}" ] && [ "${BEFORE_VERSION}" = "${SERVER_VERSION}" ]; then
65-
echo "No @browserbasehq/stagehand-server version change (${SERVER_VERSION}); skipping tag."
66-
exit 0
67-
fi
63+
64+
SERVER_PUBLISHED="false"
65+
if [ "${{ steps.changesets.outputs.published }}" = "true" ]; then
66+
SERVER_PUBLISHED="$(node -e "const pkgs=JSON.parse(process.env.PUBLISHED_PACKAGES||'[]'); process.stdout.write(pkgs.some(p=>p.name==='@browserbasehq/stagehand-server')?'true':'false');")"
6867
fi
6968
69+
echo "server_version=${SERVER_VERSION}" >> "$GITHUB_OUTPUT"
70+
echo "server_tag=${TAG}" >> "$GITHUB_OUTPUT"
71+
echo "server_published=${SERVER_PUBLISHED}" >> "$GITHUB_OUTPUT"
72+
env:
73+
PUBLISHED_PACKAGES: ${{ steps.changesets.outputs.publishedPackages }}
74+
75+
- name: Tag stagehand/server version for GitHub Releases
76+
if: steps.server_meta.outputs.server_published == 'true'
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
run: |
80+
set -euo pipefail
81+
82+
TAG="${{ steps.server_meta.outputs.server_tag }}"
83+
SERVER_VERSION="${{ steps.server_meta.outputs.server_version }}"
84+
7085
git config user.name "github-actions[bot]"
7186
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
7287
@@ -87,3 +102,235 @@ jobs:
87102
pnpm run release-canary
88103
env:
89104
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
105+
106+
server_build_binaries:
107+
name: Build stagehand/server binaries (${{ matrix.os }})
108+
needs: release
109+
if: needs.release.outputs.server_published == 'true'
110+
strategy:
111+
fail-fast: false
112+
matrix:
113+
include:
114+
- os: ubuntu-latest
115+
platform: linux
116+
arch: x64
117+
binary_name: stagehand-server-linux-x64
118+
119+
- os: ubuntu-latest
120+
platform: linux
121+
arch: arm64
122+
binary_name: stagehand-server-linux-arm64
123+
124+
- os: macos-latest
125+
platform: darwin
126+
arch: arm64
127+
binary_name: stagehand-server-darwin-arm64
128+
129+
- os: macos-13
130+
platform: darwin
131+
arch: x64
132+
binary_name: stagehand-server-darwin-x64
133+
134+
- os: windows-latest
135+
platform: win32
136+
arch: x64
137+
binary_name: stagehand-server-win32-x64.exe
138+
139+
- os: windows-latest
140+
platform: win32
141+
arch: arm64
142+
binary_name: stagehand-server-win32-arm64.exe
143+
144+
runs-on: ${{ matrix.os }}
145+
steps:
146+
- name: Checkout repository
147+
uses: actions/checkout@v4
148+
with:
149+
fetch-depth: 0
150+
151+
- name: Setup pnpm
152+
uses: pnpm/action-setup@v4
153+
154+
- name: Setup Node.js
155+
uses: actions/setup-node@v4
156+
with:
157+
node-version: 22.x
158+
cache: pnpm
159+
160+
- name: Install dependencies
161+
env:
162+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
163+
run: pnpm install --frozen-lockfile
164+
165+
- name: Build binary (Linux/macOS x64/host arch)
166+
if: matrix.platform != 'win32' && !(matrix.platform == 'linux' && matrix.arch == 'arm64')
167+
shell: bash
168+
run: |
169+
CI=true pnpm --filter @browserbasehq/stagehand-server build:binary
170+
171+
- name: Build binary (Linux arm64)
172+
if: matrix.platform == 'linux' && matrix.arch == 'arm64'
173+
shell: bash
174+
run: |
175+
set -euo pipefail
176+
177+
# Intentionally build the core SDK package (not `@browserbasehq/stagehand-server`),
178+
# since the SEA bundle depends on the built SDK output and the server's `build`
179+
# also runs OpenAPI generation (unnecessary for binary packaging here).
180+
pnpm --filter @browserbasehq/stagehand build
181+
cd packages/server
182+
mkdir -p dist/sea
183+
184+
pnpm exec esbuild src/server.ts \
185+
--bundle \
186+
--platform=node \
187+
--format=cjs \
188+
--outfile=dist/sea/bundle.cjs \
189+
--log-level=warning
190+
191+
node --experimental-sea-config sea-config.json
192+
193+
BLOB="dist/sea/sea-prep.blob"
194+
if [ ! -f "${BLOB}" ]; then
195+
echo "Missing ${BLOB}; SEA blob generation failed." >&2
196+
exit 1
197+
fi
198+
199+
NODE_VERSION="$(node -p 'process.version')"
200+
NODE_TARBALL="node-${NODE_VERSION}-linux-arm64.tar.xz"
201+
NODE_URL="https://nodejs.org/dist/${NODE_VERSION}/${NODE_TARBALL}"
202+
203+
curl -fsSL "${NODE_URL}" -o "${NODE_TARBALL}"
204+
tar -xJf "${NODE_TARBALL}"
205+
206+
NODE_EXE="node-${NODE_VERSION}-linux-arm64/bin/node"
207+
if [ ! -f "${NODE_EXE}" ]; then
208+
echo "Missing downloaded Node binary at ${NODE_EXE}" >&2
209+
exit 1
210+
fi
211+
212+
OUT="dist/sea/${{ matrix.binary_name }}"
213+
cp "${NODE_EXE}" "${OUT}"
214+
chmod +x "${OUT}"
215+
216+
pnpm exec postject "${OUT}" NODE_SEA_BLOB "${BLOB}" \
217+
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
218+
219+
ls -lh "${OUT}"
220+
221+
- name: Build binary (Windows)
222+
if: matrix.platform == 'win32' && matrix.arch == 'x64'
223+
shell: powershell
224+
run: |
225+
# Intentionally build the core SDK package (not `@browserbasehq/stagehand-server`),
226+
# since the SEA bundle depends on the built SDK output and the server's `build`
227+
# also runs OpenAPI generation (unnecessary for binary packaging here).
228+
pnpm --filter @browserbasehq/stagehand build
229+
Set-Location packages/server
230+
node -e "require('fs').mkdirSync('dist/sea',{recursive:true})"
231+
pnpm exec esbuild src/server.ts --bundle --platform=node --format=cjs --outfile=dist/sea/bundle.cjs --log-level=warning
232+
node --experimental-sea-config sea-config.json
233+
$blob = "dist/sea/sea-prep.blob"
234+
if (!(Test-Path $blob)) { throw "Missing blob at $blob; SEA blob generation failed." }
235+
Copy-Item (Get-Command node).Source -Destination "dist/sea/${{ matrix.binary_name }}"
236+
pnpm exec postject "dist/sea/${{ matrix.binary_name }}" NODE_SEA_BLOB $blob `
237+
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
238+
239+
- name: Build binary (Windows arm64)
240+
if: matrix.platform == 'win32' && matrix.arch == 'arm64'
241+
shell: powershell
242+
run: |
243+
# Intentionally build the core SDK package (not `@browserbasehq/stagehand-server`),
244+
# since the SEA bundle depends on the built SDK output and the server's `build`
245+
# also runs OpenAPI generation (unnecessary for binary packaging here).
246+
pnpm --filter @browserbasehq/stagehand build
247+
Set-Location packages/server
248+
node -e "require('fs').mkdirSync('dist/sea',{recursive:true})"
249+
pnpm exec esbuild src/server.ts --bundle --platform=node --format=cjs --outfile=dist/sea/bundle.cjs --log-level=warning
250+
node --experimental-sea-config sea-config.json
251+
252+
$blob = "dist/sea/sea-prep.blob"
253+
if (!(Test-Path $blob)) { throw "Missing blob at $blob; SEA blob generation failed." }
254+
255+
$nodeVersion = node -p "process.version"
256+
$zipName = "node-$nodeVersion-win-arm64.zip"
257+
$url = "https://nodejs.org/dist/$nodeVersion/$zipName"
258+
259+
$tmp = Join-Path $env:RUNNER_TEMP "node-arm64"
260+
Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue
261+
New-Item -ItemType Directory -Force -Path $tmp | Out-Null
262+
263+
$zipPath = Join-Path $tmp $zipName
264+
Invoke-WebRequest -Uri $url -OutFile $zipPath
265+
Expand-Archive -Path $zipPath -DestinationPath $tmp
266+
267+
$nodeExe = Join-Path $tmp "node-$nodeVersion-win-arm64\\node.exe"
268+
if (!(Test-Path $nodeExe)) { throw "Missing downloaded Node binary at $nodeExe" }
269+
270+
Copy-Item $nodeExe -Destination "dist/sea/${{ matrix.binary_name }}"
271+
pnpm exec postject "dist/sea/${{ matrix.binary_name }}" NODE_SEA_BLOB $blob `
272+
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
273+
274+
- name: Upload artifact
275+
uses: actions/upload-artifact@v4
276+
with:
277+
name: ${{ matrix.binary_name }}
278+
path: packages/server/dist/sea/${{ matrix.binary_name }}
279+
retention-days: 7
280+
281+
server_publish_release:
282+
name: Publish stagehand/server GitHub Release
283+
needs: [release, server_build_binaries]
284+
if: needs.release.outputs.server_published == 'true'
285+
runs-on: ubuntu-latest
286+
env:
287+
OAS_PATH: packages/server/openapi.v3.yaml
288+
steps:
289+
- name: Checkout repository
290+
uses: actions/checkout@v4
291+
with:
292+
fetch-depth: 0
293+
294+
- name: Prepare release assets directory
295+
run: mkdir -p release-assets
296+
297+
- name: Prepare stagehand/server release assets
298+
run: |
299+
set -euo pipefail
300+
cp "${{ env.OAS_PATH }}" "release-assets/openapi.v3.stagehand-server-${{ needs.release.outputs.server_version }}.yaml"
301+
302+
- name: Download SEA binary artifacts
303+
uses: actions/download-artifact@v4
304+
with:
305+
pattern: stagehand-server-*
306+
path: release-assets
307+
merge-multiple: true
308+
309+
- name: Create checksums
310+
shell: bash
311+
run: |
312+
set -euo pipefail
313+
cd release-assets
314+
# Only checksum binaries (exclude openapi yaml). Avoid failing if no matches.
315+
shopt -s nullglob
316+
files=(stagehand-server-*)
317+
bins=()
318+
for f in "${files[@]}"; do
319+
[[ "$f" == *openapi* ]] && continue
320+
[[ -f "$f" ]] && bins+=("$f")
321+
done
322+
: > checksums.sha256
323+
if [ "${#bins[@]}" -gt 0 ]; then
324+
shasum -a 256 "${bins[@]}" > checksums.sha256
325+
fi
326+
327+
- name: Publish stagehand/server GitHub release
328+
uses: softprops/action-gh-release@v2
329+
with:
330+
tag_name: ${{ needs.release.outputs.server_tag }}
331+
name: stagehand/server v${{ needs.release.outputs.server_version }}
332+
generate_release_notes: true
333+
files: |
334+
release-assets/openapi.v3.stagehand-server-${{ needs.release.outputs.server_version }}.yaml
335+
release-assets/stagehand-server-*
336+
release-assets/checksums.sha256

0 commit comments

Comments
 (0)