Skip to content

Commit df529c5

Browse files
committed
feat(lighthouse-ci): bundle test apps and upload to lighthouse.sentry.gg lab
Replace the in-CI Lighthouse runs with a build-bundle-upload pipeline that ships prebuilt test apps to the dedicated Sentry Lighthouse lab service (https://lighthouse.sentry.gg). The lab runs Lighthouse on stable, dedicated hardware — eliminating the measurement noise we hit on shared GitHub-hosted runners — persists results, and ships every metric to Sentry under the lighthouse.* namespace. Companion to the spec at ~/Projects/sentry-lhci/docs/sentry-javascript-handoff.md. Concretely: - Rename dev-packages/lighthouse-tests/ to dev-packages/lighthouse-bundle/. The directory's job is no longer 'tests' — it's bundle preparation. - Delete the in-CI Lighthouse infrastructure: lighthouserc.cjs (lab owns the LHCI config now), report.mjs (Job Summary moves into the new script), and lighthouse-matrix.mjs (matrix is just a hardcoded constant in the upload script — no GitHub Actions matrix expansion needed anymore). - Add bundle-and-upload.mjs: zero-deps (Node 22 builtins only — fetch, FormData, Blob, system tar). For each (app, mode) cell, copies the app to a temp dir, applies the existing ci:pnpm-overrides helper, builds with the right SENTRY_LIGHTHOUSE_MODE / NEXT_PUBLIC_SENTRY_LIGHTHOUSE_MODE / REACT_APP_SENTRY_LIGHTHOUSE_MODE env vars (every prefix set at once — each app's bundler picks up whichever it knows), and tars the result. Static cells (default-browser, react-19) bundle only their build/ dir. SSR cell (nextjs-16) strips node_modules + pnpm-lock.yaml, copies the packed SDK tgzs into ./packed/ inside the bundle, and rewrites every workspace-absolute file: path in package.json (dependencies, devDependencies, pnpm.overrides) to file:./packed/... so pnpm install can resolve them after the lab extracts the tarball. All 9 bundles are POSTed as one multipart request to /api/builds; the script then polls /api/builds/:id every 15s for up to 25 minutes and appends a markdown summary table to $GITHUB_STEP_SUMMARY with per-cell status, median score, and Lighthouse-report links. - Strip dependencies from dev-packages/lighthouse-bundle/package.json. The script only needs Node builtins. - Rewrite .github/workflows/lighthouse.yml. Two jobs: * job_build — SDK build + tarball generation (unchanged). * job_bundle_and_upload — single non-matrix job; runs the script after restoring tarballs and seeding dev-packages/e2e-tests/packed/ via yarn test:prepare. Per-cell parallelism gained nothing once Lighthouse moved off the runner. Requires two new repo secrets in getsentry/sentry-javascript: - LIGHTHOUSE_LAB_URL (https://lighthouse.sentry.gg) - LIGHTHOUSE_UPLOAD_TOKEN (mirror of the lab's Northflank UPLOAD_TOKEN) Triggers: nightly cron at 00:00 UTC plus workflow_dispatch for ad-hoc runs.
1 parent bb5ee63 commit df529c5

7 files changed

Lines changed: 374 additions & 413 deletions

File tree

.github/workflows/lighthouse.yml

Lines changed: 34 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
name: 'Nightly: Lighthouse'
22

3-
# Standalone workflow that runs Lighthouse audits across instrumented E2E test apps
4-
# on a nightly schedule (and on demand via workflow_dispatch). Intentionally NOT
5-
# wired to pull_request triggers — the per-PR comment was too noisy to keep on
6-
# every push, so the report now surfaces only as a Job Summary on each workflow
7-
# run page. Never blocks merges (not referenced by build.yml's required-jobs gate).
3+
# Builds the instrumented Sentry test apps (default-browser, react-19, nextjs-16)
4+
# in three Sentry feature modes (no-sentry, init-only, tracing-replay), tars each
5+
# of the 9 cells, and uploads them to the Sentry Lighthouse lab at
6+
# https://lighthouse.sentry.gg.
7+
#
8+
# The lab runs Lighthouse on dedicated hardware (no shared-runner flake), saves
9+
# results to its own DB + dashboard, and ships metrics to Sentry. See the wire
10+
# protocol in ~/Projects/sentry-lhci/docs/sentry-javascript-handoff.md.
11+
#
12+
# This workflow only builds + uploads — no Lighthouse runs on GitHub Actions.
13+
# Never blocks merges (not in build.yml's required-jobs gate).
814

915
on:
1016
schedule:
1117
- cron: '0 0 * * *'
1218
workflow_dispatch:
1319

14-
# Independent concurrency group from build.yml so nothing in this workflow can
15-
# cancel or queue against the main CI pipeline.
20+
# Independent of build.yml so nothing here can cancel or queue against main CI.
1621
concurrency:
1722
group: lighthouse-${{ github.run_id }}
1823
cancel-in-progress: false
@@ -29,11 +34,10 @@ env:
2934

3035
jobs:
3136
job_build:
32-
name: Build SDK + Generate Matrix
37+
name: Build SDK + Tarballs
3338
runs-on: ubuntu-24.04
3439
timeout-minutes: 20
3540
outputs:
36-
matrix: ${{ steps.matrix.outputs.matrix }}
3741
dependency_cache_key: ${{ steps.install_dependencies.outputs.cache_key }}
3842
steps:
3943
- name: Check out current commit
@@ -64,42 +68,33 @@ jobs:
6468
compression-level: 6
6569
overwrite: true
6670

67-
- name: Generate matrix
68-
id: matrix
69-
# Script prints `matrix=<JSON>` to stdout; redirect to $GITHUB_OUTPUT so the
70-
# downstream matrix job can pick it up via needs.job_build.outputs.matrix.
71-
run: node dev-packages/lighthouse-tests/lighthouse-matrix.mjs >> "$GITHUB_OUTPUT"
72-
73-
job_lighthouse:
74-
name: Lighthouse ${{ matrix.app }} (${{ matrix.mode }})
71+
job_bundle_and_upload:
72+
name: Bundle test apps and upload to Lighthouse lab
7573
needs: [job_build]
76-
runs-on: ubuntu-24.04-large-js
77-
timeout-minutes: 20
78-
# One bad cell shouldn't tank the rest of the matrix — the Report job marks
79-
# missing/empty cells in the Job Summary.
80-
continue-on-error: true
81-
strategy:
82-
fail-fast: false
83-
max-parallel: 15
84-
matrix: ${{ fromJson(needs.job_build.outputs.matrix) }}
74+
runs-on: ubuntu-24.04
75+
timeout-minutes: 30
8576
env:
86-
# Only the two prefixes the currently-matrixed apps actually consume:
87-
# - SENTRY_LIGHTHOUSE_MODE → default-browser (plain webpack)
88-
# - NEXT_PUBLIC_* → nextjs-16 (Next.js client-side env exposure)
89-
# If more frameworks are added to the matrix later, add the corresponding
90-
# prefix here. (Tracked in TODO-aeab11f0.)
77+
LIGHTHOUSE_LAB_URL: ${{ secrets.LIGHTHOUSE_LAB_URL }}
78+
LIGHTHOUSE_UPLOAD_TOKEN: ${{ secrets.LIGHTHOUSE_UPLOAD_TOKEN }}
79+
# Synthetic DSNs — the apps only need *something* parseable at build time;
80+
# nothing actually phones home (the Lighthouse run is what we care about).
9181
E2E_TEST_DSN: 'https://username@domain/123'
9282
NEXT_PUBLIC_E2E_TEST_DSN: 'https://username@domain/123'
83+
PUBLIC_E2E_TEST_DSN: 'https://username@domain/123'
84+
REACT_APP_E2E_TEST_DSN: 'https://username@domain/123'
9385
steps:
9486
- name: Check out current commit
9587
uses: actions/checkout@v6
88+
9689
- uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
9790
with:
9891
version: 9.15.9
92+
9993
- name: Set up Node
10094
uses: actions/setup-node@v6
10195
with:
102-
node-version-file: 'dev-packages/e2e-tests/test-applications/${{ matrix.app }}/package.json'
96+
node-version-file: 'package.json'
97+
10398
- name: Restore caches
10499
uses: ./.github/actions/restore-cache
105100
with:
@@ -111,92 +106,17 @@ jobs:
111106
name: lighthouse-build-tarball-output
112107
path: ${{ env.TARBALL_ARTIFACT_DOWNLOAD_PATH }}
113108

114-
- name: Prepare E2E tests
109+
- name: Prepare E2E tests (copy packed tgzs into dev-packages/e2e-tests/packed)
115110
run: yarn test:prepare
116111
working-directory: dev-packages/e2e-tests
117112

118113
- name: Validate E2E tests setup
119114
run: yarn test:validate
120115
working-directory: dev-packages/e2e-tests
121116

122-
- name: Copy app to temp
123-
run: yarn ci:copy-to-temp ./test-applications/${{ matrix.app }} ${{ runner.temp }}/test-application
124-
working-directory: dev-packages/e2e-tests
125-
126-
- name: Add pnpm overrides
127-
run:
128-
yarn ci:pnpm-overrides ${{ runner.temp }}/test-application ${{ github.workspace
129-
}}/dev-packages/e2e-tests/packed
130-
working-directory: dev-packages/e2e-tests
131-
132-
- name: Build E2E app for Lighthouse
133-
working-directory: ${{ runner.temp }}/test-application
134-
timeout-minutes: 7
135-
run: pnpm test:build
136-
env:
137-
SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }}
138-
SENTRY_LIGHTHOUSE_MODE: ${{ matrix.mode }}
139-
NEXT_PUBLIC_SENTRY_LIGHTHOUSE_MODE: ${{ matrix.mode }}
140-
141-
- name: Run Lighthouse CI
142-
id: lighthouse
143-
# Pinned to a commit SHA (rather than the floating @v12 tag) to lock down the
144-
# supply chain: this third-party action also npm-installs @lhci/cli, so an
145-
# upstream tag-repoint could otherwise change what runs on our runners.
146-
# SHA is the current tip of v12. Bump deliberately when upgrading.
147-
uses: treosh/lighthouse-ci-action@3e7e23fb74242897f95c0ba9cabad3d0227b9b18 # v12
148-
with:
149-
configPath: ${{ github.workspace }}/dev-packages/lighthouse-tests/lighthouserc.cjs
150-
# Do NOT enable uploadArtifacts here — it would upload `.lighthouseci/` under
151-
# the default name `lighthouse-reports` for every cell, causing a 409 conflict
152-
# on every matrix cell after the first one. We do our own per-cell upload
153-
# below with a unique name (lighthouse-<app>-<mode>).
154-
temporaryPublicStorage: true
155-
runs: 5
156-
env:
157-
# lighthouserc.cjs branches on these env vars at config-load time.
158-
LIGHTHOUSE_SERVE_MODE: ${{ matrix.serve }}
159-
LIGHTHOUSE_STATIC_DIR: ${{ runner.temp }}/test-application/${{ matrix.static-dir }}
160-
LIGHTHOUSE_START_CMD: cd ${{ runner.temp }}/test-application && ${{ matrix.start-cmd }}
161-
LIGHTHOUSE_READY_PATTERN: ${{ matrix.ready-pattern }}
162-
LIGHTHOUSE_URL: 'http://localhost:3000/'
163-
164-
- name: Upload Lighthouse results
165-
# `resultsPath` is the absolute path to the .lighthouseci/ output dir written by
166-
# `lhci collect`. The dir is dot-prefixed, and actions/upload-artifact@v7 excludes
167-
# hidden files / dot-prefixed dirs by default — so we must set
168-
# `include-hidden-files: true` or every cell uploads zero files.
169-
uses: actions/upload-artifact@v7
170-
if: always() && steps.lighthouse.outputs.resultsPath != ''
171-
with:
172-
name: lighthouse-${{ matrix.app }}-${{ matrix.mode }}
173-
path: ${{ steps.lighthouse.outputs.resultsPath }}
174-
include-hidden-files: true
175-
retention-days: 7
176-
# Fail loudly if the dir is empty — we already gated on resultsPath being set,
177-
# so an empty dir means lhci collect produced nothing, which is a real bug.
178-
if-no-files-found: error
179-
180-
job_lighthouse_report:
181-
name: Lighthouse Report
182-
needs: [job_build, job_lighthouse]
183-
if: always() && needs.job_build.result == 'success'
184-
runs-on: ubuntu-24.04
185-
steps:
186-
- name: Check out current commit
187-
uses: actions/checkout@v6
188-
- name: Set up Node
189-
uses: actions/setup-node@v6
190-
with:
191-
node-version-file: 'package.json'
192-
- name: Restore caches
193-
uses: ./.github/actions/restore-cache
194-
with:
195-
dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }}
196-
- name: Download all Lighthouse artifacts
197-
uses: actions/download-artifact@v7
198-
with:
199-
pattern: lighthouse-*
200-
path: lighthouse-results/
201-
- name: Generate report
202-
run: node dev-packages/lighthouse-tests/report.mjs
117+
- name: Bundle every cell and upload to the lab
118+
# bundle-and-upload.mjs handles the full 3 × 3 matrix in one process:
119+
# copies each app to a temp dir, applies pnpm overrides, builds with the
120+
# right SENTRY_LIGHTHOUSE_MODE env var, tars, POSTs all 9 bundles to the
121+
# lab, polls until terminal, writes a Job Summary.
122+
run: node dev-packages/lighthouse-bundle/bundle-and-upload.mjs

0 commit comments

Comments
 (0)