From 4c84063a47a4a578b1420213a9739d5fde31a2f1 Mon Sep 17 00:00:00 2001 From: Jess Sullivan Date: Fri, 28 Aug 2026 15:15:10 -0400 Subject: [PATCH 1/2] ci(e2e): keep Playwright evidence from the gates lane An e2e failure in bazel-remote-gates left nothing behind: trace mode was off and the job uploaded no artifact, so today's 1/330 timeout could only be read from ephemeral stdout. Now PLAYWRIGHT_TRACE_MODE=retain-on-failure reaches the test action (.bazelrc --test_env), the Bazel config writes Playwright's output directory into TEST_UNDECLARED_OUTPUTS_DIR so Bazel keeps it in bazel-testlogs/playwright_chromium_e2e/test.outputs/outputs.zip, and an always-run step copies that directory (dereferenced, zip expanded) into a run artifact retained for seven days. No new permissions, no secrets, no change to what is tested. --- .bazelrc | 1 + .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ playwright.bazel.config.ts | 8 ++++++++ 3 files changed, 36 insertions(+) diff --git a/.bazelrc b/.bazelrc index 1173480d..73ff43ab 100644 --- a/.bazelrc +++ b/.bazelrc @@ -22,6 +22,7 @@ test --test_timeout=120,600,1800,3600 # GF_RBE_CHROMIUM_EXECUTABLE). No hardcoded value: an absent var lets # the run-*-bazel.mjs candidate scan handle system chromium paths. test --test_env=GF_RBE_CHROMIUM_EXECUTABLE +test --test_env=PLAYWRIGHT_TRACE_MODE build:local --disk_cache=~/.cache/bazel-jesssullivan-github-io diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d20d580b..c956e214 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,6 +53,9 @@ jobs: GF_BAZEL_HOST_JVM_MAX_HEAP_MB: '2560' GF_REAPI_TOKEN_EXCHANGE_REQUEST: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'cache-write' || 'cache-read' }} GF_REAPI_TOKEN_EXCHANGE_TTL: 45m + # Keep Playwright traces for failed specs; the config routes them into + # Bazel's undeclared outputs so the evidence step below can upload them. + PLAYWRIGHT_TRACE_MODE: retain-on-failure # The GF consumer registry records this repo as shared-cache-backed. # Clear any executor endpoint inherited from the generic ARC pod. BAZEL_REMOTE_EXECUTOR: '' @@ -155,6 +158,30 @@ jobs: npm run remote:e2e:public bash scripts/bazel-cache-backed.sh shutdown + - name: Collect e2e evidence + if: always() + run: | + set -euo pipefail + mkdir -p artifacts/playwright-e2e + if [[ -d bazel-testlogs/playwright_chromium_e2e ]]; then + cp -RL bazel-testlogs/playwright_chromium_e2e/. artifacts/playwright-e2e/ + if [[ -f artifacts/playwright-e2e/test.outputs/outputs.zip ]]; then + (cd artifacts/playwright-e2e && unzip -oq test.outputs/outputs.zip -d undeclared-outputs) || true + fi + find artifacts/playwright-e2e -type f | head -50 + else + echo "no bazel-testlogs/playwright_chromium_e2e directory (e2e did not run)" | tee artifacts/playwright-e2e/NO-RUN.txt + fi + + - name: Upload e2e evidence + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: playwright-e2e-${{ github.run_id }}-${{ github.run_attempt }} + path: artifacts/playwright-e2e + if-no-files-found: warn + retention-days: 7 + build-and-test: runs-on: ubuntu-latest timeout-minutes: 45 diff --git a/playwright.bazel.config.ts b/playwright.bazel.config.ts index 85464f9b..fb50f7dd 100644 --- a/playwright.bazel.config.ts +++ b/playwright.bazel.config.ts @@ -1,3 +1,4 @@ +import { join } from 'node:path'; import { defineConfig, devices } from '@playwright/test'; type TraceMode = 'off' | 'on' | 'retain-on-failure' | 'on-first-retry'; @@ -6,6 +7,12 @@ const chromiumExecutable = process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH || process.env.GF_RBE_CHROMIUM_EXECUTABLE || process.env.CHROME_BIN; const traceMode = parseTraceMode(process.env.PLAYWRIGHT_TRACE_MODE); const e2ePort = parsePort(process.env.PLAYWRIGHT_E2E_PORT); +// Under `bazel test` the sandbox is discarded; anything worth keeping (traces, +// screenshots, error contexts) must land in TEST_UNDECLARED_OUTPUTS_DIR so Bazel +// zips it into bazel-testlogs//test.outputs/outputs.zip. +const outputDir = process.env.TEST_UNDECLARED_OUTPUTS_DIR + ? join(process.env.TEST_UNDECLARED_OUTPUTS_DIR, 'playwright') + : 'test-results'; if (!chromiumExecutable) { throw new Error( @@ -15,6 +22,7 @@ if (!chromiumExecutable) { export default defineConfig({ testDir: 'e2e', + outputDir, timeout: 30_000, fullyParallel: true, forbidOnly: true, From 803285fee08da76b33846a754b1644d0c5b89113 Mon Sep 17 00:00:00 2001 From: Jess Sullivan Date: Fri, 28 Aug 2026 15:56:37 -0400 Subject: [PATCH 2/2] build(bazel): zip undeclared test outputs Run 33203042020 kept the Playwright trace for the failing spec but Bazel then refused the test: 'output tree artifact playwright_chromium_e2e/ test.outputs was not created'. Bazel 8 materializes undeclared outputs as an unzipped tree artifact by default and the spec directory names are non-ASCII. --zip_undeclared_test_outputs makes it one outputs.zip, which the evidence step already expands. --- .bazelrc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.bazelrc b/.bazelrc index 73ff43ab..36520a06 100644 --- a/.bazelrc +++ b/.bazelrc @@ -23,6 +23,10 @@ test --test_timeout=120,600,1800,3600 # the run-*-bazel.mjs candidate scan handle system chromium paths. test --test_env=GF_RBE_CHROMIUM_EXECUTABLE test --test_env=PLAYWRIGHT_TRACE_MODE +# Undeclared test outputs (Playwright traces/screenshots) are zipped into a single +# test.outputs/outputs.zip; Bazel 8's unzipped tree-artifact default refused the +# directory (spec names carry non-ASCII) on run 33203042020. +test --zip_undeclared_test_outputs build:local --disk_cache=~/.cache/bazel-jesssullivan-github-io