Restore completed Core E2E verdicts: shard CI, drop release tag from test image

Every main push since the v6 branch flip was cancelled at the 45-minute
job timeout with no verdict. The flip brought the full 94-spec suite onto
main (the last green run, 2026-06-29, ran only 2 specs on the v5 main),
and it runs sequentially against a release-tagged image whose mock-fixture
gate returns 403 without a demo entitlement. Dozens of specs fail, retry
twice each, and burn the budget: of the 31 minutes of suite time in run
28907574469, 18.8 minutes were failing attempts.

- Add GO_BUILD_TAGS build arg (default release) and build the pulse:test
  e2e image with it empty, matching the dev harness the suite is green
  under. Shipped images keep the release tag; release-gate behavior keeps
  its dedicated -tags release Go tests.
- Shard Playwright 4 ways across a CI matrix (214/202/205/203 tests per
  shard) with per-shard report artifacts and an aggregate verdict job.
- Cap CI at 20 failures so an env-broken run reports red in minutes
  instead of grinding into a no-verdict cancellation.
This commit is contained in:
rcourtman 2026-07-08 08:00:34 +01:00
parent 61350eeaab
commit c728539f07
5 changed files with 43 additions and 9 deletions

View file

@ -29,9 +29,13 @@ permissions:
jobs:
e2e:
name: Playwright Core E2E
name: Playwright Core E2E (shard ${{ matrix.shard }}/4)
runs-on: ubuntu-24.04
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- name: Checkout code
@ -51,8 +55,10 @@ jobs:
npx playwright install --with-deps chromium
- name: Build Docker images for test environment
# GO_BUILD_TAGS="" drops the release build tag so the suite can enable
# mock fixtures; release-tag gating has its own -tags release Go tests.
run: |
docker build -t pulse:test --target runtime .
docker build -t pulse:test --target runtime --build-arg GO_BUILD_TAGS="" .
docker build -t pulse-mock-github:test ./tests/integration/mock-github-server
env:
PULSE_LICENSE_PUBLIC_KEY: ${{ secrets.PULSE_LICENSE_PUBLIC_KEY }}
@ -72,7 +78,7 @@ jobs:
PULSE_E2E_SKIP_DOCKER: "true"
PULSE_E2E_SKIP_PLAYWRIGHT_INSTALL: "true"
PULSE_E2E_PERF: "1"
run: npm test
run: npm test -- --shard=${{ matrix.shard }}/4
- name: Collect container logs
if: always()
@ -89,7 +95,7 @@ jobs:
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: playwright-report
name: playwright-report-shard-${{ matrix.shard }}
path: tests/integration/playwright-report/
retention-days: 30
@ -97,6 +103,20 @@ jobs:
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-failures
name: test-failures-shard-${{ matrix.shard }}
path: tests/integration/test-results/
retention-days: 7
e2e-verdict:
name: E2E verdict
runs-on: ubuntu-24.04
needs: e2e
if: always()
steps:
- name: Check shard results
run: |
if [ "${{ needs.e2e.result }}" != "success" ]; then
echo "E2E shards did not all pass (result: ${{ needs.e2e.result }})"
exit 1
fi
echo "All E2E shards passed"

View file

@ -31,6 +31,11 @@ ARG BUILD_AGENT
ARG VERSION
ARG PULSE_LICENSE_PUBLIC_KEY_SHA256
ARG PULSE_UPDATE_SIGNING_PUBLIC_KEY
# Go build tags for the server binary. Shipped images use "release", which
# fail-closes mock fixtures, admin bypass, and licensing env overrides. The
# E2E test image builds with GO_BUILD_TAGS="" so the suite can drive mock
# fixtures the same way the local dev harness does.
ARG GO_BUILD_TAGS=release
WORKDIR /app
# Install build dependencies
@ -84,13 +89,13 @@ RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
if [ -n "${PULSE_UPDATE_SIGNING_PUBLIC_KEY:-}" ] && [ "${UPDATE_PUBLIC_KEYS}" != "${PULSE_UPDATE_SIGNING_PUBLIC_KEY}" ]; then echo "Error: mounted update signing key does not match PULSE_UPDATE_SIGNING_PUBLIC_KEY." >&2; echo "Expected public key: ${PULSE_UPDATE_SIGNING_PUBLIC_KEY}" >&2; echo "Actual public key: ${UPDATE_PUBLIC_KEYS}" >&2; exit 1; fi && \
SERVER_LDFLAGS="$(./scripts/release_ldflags.sh server --version "${VERSION}" --build-time "${BUILD_TIME}" --git-commit "${GIT_COMMIT}" $(if [ -n "${LICENSE_PUBLIC_KEY}" ]; then printf '%s %s' --license-public-key "${LICENSE_PUBLIC_KEY}"; fi) $(if [ -n "${UPDATE_PUBLIC_KEYS}" ]; then printf '%s %s' --update-public-keys "${UPDATE_PUBLIC_KEYS}"; fi))" && \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
-tags release \
-tags "${GO_BUILD_TAGS}" \
-ldflags="${SERVER_LDFLAGS}" \
-buildvcs=false \
-trimpath \
-o pulse-linux-amd64 ./cmd/pulse && \
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build \
-tags release \
-tags "${GO_BUILD_TAGS}" \
-ldflags="${SERVER_LDFLAGS}" \
-buildvcs=false \
-trimpath \

View file

@ -17,6 +17,11 @@ export default defineConfig({
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* On CI, a broken test environment fails most of the suite; abort early so
the run produces a red completed verdict with a report instead of
grinding until the job timeout cancels it with no verdict at all. */
maxFailures: process.env.CI ? 20 : 0,
/* Opt out of parallel tests on CI */
workers: 1, // Update tests modify global state

View file

@ -44,7 +44,9 @@ ensure_test_images() {
if ! docker image inspect pulse:test >/dev/null 2>&1; then
echo "Building missing image: pulse:test"
docker build -t pulse:test -f "$REPO_ROOT/Dockerfile" "$REPO_ROOT"
# Test image drops the release build tag so the suite can enable mock
# fixtures without a demo entitlement.
docker build -t pulse:test --build-arg GO_BUILD_TAGS="" -f "$REPO_ROOT/Dockerfile" "$REPO_ROOT"
fi
}

View file

@ -86,7 +86,9 @@ echo "✅ Mock GitHub server image built"
# Build Pulse test image (from root of repo)
cd "$TEST_ROOT/../.."
if [ -f "Dockerfile" ]; then
docker build -t pulse:test -f Dockerfile .
# Test image drops the release build tag so the suite can enable mock
# fixtures without a demo entitlement.
docker build -t pulse:test --build-arg GO_BUILD_TAGS="" -f Dockerfile .
echo "✅ Pulse test image built"
else
echo "⚠️ Pulse Dockerfile not found. Using published image instead."