From ed4e374fce854a054d2836723b962cd6baeb6473 Mon Sep 17 00:00:00 2001 From: janithjay Date: Tue, 18 Aug 2026 16:04:30 +0530 Subject: [PATCH] Run E2E on every PR and gate releases on it Signed-off-by: janithjay --- .github/actions/run-e2e-suite/action.yml | 11 ++++++----- .github/workflows/e2e-nightly.yml | 3 +-- .github/workflows/pr-builder.yml | 12 +----------- .github/workflows/release.yml | 21 +++++++++++++++++++++ tests/e2e/run-e2e.sh | 10 +++++----- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/.github/actions/run-e2e-suite/action.yml b/.github/actions/run-e2e-suite/action.yml index f4ee47c4..4286041e 100644 --- a/.github/actions/run-e2e-suite/action.yml +++ b/.github/actions/run-e2e-suite/action.yml @@ -58,10 +58,11 @@ runs: # the THUNDERID_ADMIN_* env vars. It always finishes by trying to attach its interactive # REPL, which needs a real TTY this runner doesn't have, so it fails; that's expected, and # by then the release is already downloaded and fully set up on disk, so the exit code is - # ignored. We start it ourselves afterward with `start.sh`, since npx thunderid's own - # (REPL-attached) background process doesn't outlive the npx invocation. This is the first - # thing on this fresh runner to touch the ThunderID CLI's state, so there is no risk of it - # picking up a stale "active version" the way a long-lived dev machine could. + # ignored. npx thunderid already health-checked the server it started before that point, so + # we only start it ourselves with `start.sh` if it isn't actually reachable (e.g. the REPL + # failure tore it down) instead of racing a second instance onto the same port. This is the + # first thing on this fresh runner to touch the ThunderID CLI's state, so there is no risk + # of it picking up a stale "active version" the way a long-lived dev machine could. run: | # setsid detaches into a new session with no controlling terminal, so npx thunderid's # REPL (which opens /dev/tty directly, bypassing stdin redirection) fails to attach @@ -78,7 +79,7 @@ runs: echo "dist_home=$DIST_HOME" >> "$GITHUB_OUTPUT" chmod +x "$DIST_HOME/start.sh" - (cd "$DIST_HOME" && setsid ./start.sh &) + curl -skf https://localhost:8090/health/liveness > /dev/null || (cd "$DIST_HOME" && setsid ./start.sh &) for i in $(seq 1 60); do curl -skf https://localhost:8090/health/liveness && exit 0 sleep 2 diff --git a/.github/workflows/e2e-nightly.yml b/.github/workflows/e2e-nightly.yml index 816f6499..837b6e41 100644 --- a/.github/workflows/e2e-nightly.yml +++ b/.github/workflows/e2e-nightly.yml @@ -2,8 +2,7 @@ name: 🌙 E2E Nightly (latest ThunderID) # Runs the same E2E suite as pr-builder.yml's `e2e` job, against the same always-latest ThunderID # release. The two differ only in trigger: this one runs on a schedule regardless of PR activity, -# so a ThunderID release that breaks something surfaces even on a day with no relevant PR open — -# the per-PR job (see pr-builder.yml) is label-gated and opt-in, not scheduled. +# so a ThunderID release that breaks something surfaces even on a day with no open PR to catch it. on: schedule: diff --git a/.github/workflows/pr-builder.yml b/.github/workflows/pr-builder.yml index 61d64656..6c0d05a2 100644 --- a/.github/workflows/pr-builder.yml +++ b/.github/workflows/pr-builder.yml @@ -2,7 +2,7 @@ name: 👷🛠️ PR Builder on: pull_request: - types: [opened, synchronize, reopened, labeled] + types: [opened, synchronize, reopened] merge_group: workflow_dispatch: @@ -101,12 +101,6 @@ jobs: e2e: name: 🎭 E2E (sample apps) - # Label-gated, mirroring thunderid's own pr-builder.yml `trigger-pr-builder` pattern — a real - # backend + six sample apps is expensive enough that it shouldn't run on every push by - # default. Always runs on merge_group/workflow_dispatch. - if: >- - github.event_name != 'pull_request' || - contains(github.event.pull_request.labels.*.name, 'trigger-e2e') runs-on: ubuntu-latest timeout-minutes: 40 # Least privilege: this job never pushes, comments, or writes to the repo — only the default @@ -117,10 +111,6 @@ jobs: - name: 📥 Checkout Code uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: - # Matches thunder-id/thunderid's own checkout steps: the checked-out repo never needs - # git push/fetch credentials in this job, so don't leave the token available to be - # abused by anything that runs afterward (including the third-party composite actions - # invoked later in this job). persist-credentials: false - name: 🎭 Run E2E suite diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6de95fc9..a8c1e1d1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -95,8 +95,29 @@ env: NODE_VERSION: "lts/*" jobs: + test-e2e: + name: 🎭 E2E (sample apps) + runs-on: ubuntu-latest + timeout-minutes: 40 + # Least privilege: this job never pushes, comments, or writes to the repo — only the default + # GITHUB_TOKEN's read access is needed for checkout. + permissions: + contents: read + steps: + - name: 📥 Checkout Code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: 🎭 Run E2E suite + uses: ./.github/actions/run-e2e-suite + with: + node-version: ${{ env.NODE_VERSION }} + artifact-name: playwright-report-release + validate: name: ✅ Validate Inputs + needs: [test-e2e] runs-on: ubuntu-latest steps: - name: Guard against accidental major bump diff --git a/tests/e2e/run-e2e.sh b/tests/e2e/run-e2e.sh index eea94335..0261cb2b 100755 --- a/tests/e2e/run-e2e.sh +++ b/tests/e2e/run-e2e.sh @@ -122,10 +122,10 @@ resolve_platform() { # GitHub API or thunderid.dev calls of our own and no version pinned in this repo, downloads it for # the current platform, and runs setup.sh non-interactively (admin credentials passed through via # THUNDERID_ADMIN_* env vars). It always finishes by trying to attach its interactive REPL, which -# needs a real TTY and fails in a script; that is expected, so its exit code is ignored below. By -# the time it fails, the release is already downloaded and fully set up on disk, so we start it -# ourselves with `start.sh` rather than relying on npx thunderid's own (REPL-attached) background -# process, which does not outlive the npx invocation. A scratch HOME is used for that one +# needs a real TTY and fails in a script; that is expected, so its exit code is ignored below. npx +# thunderid already health-checked the server it started before that point, so we only start it +# ourselves with `start.sh` if it isn't actually reachable (e.g. the REPL failure tore it down) +# instead of racing a second instance onto the same port. A scratch HOME is used for that one # invocation so it can't see, or reuse, a version already active from a developer's own separate # `npx thunderid` use on this machine, guaranteeing a fresh "no active version" state and therefore # the true latest release every run. @@ -183,7 +183,7 @@ download_and_start_server() { fi echo "Starting ThunderID server..." - (cd "$DIST_HOME" && ./start.sh) & + curl -sk "https://localhost:${SERVER_PORT}/health/liveness" > /dev/null 2>&1 || (cd "$DIST_HOME" && ./start.sh &) wait_for_url "https://localhost:${SERVER_PORT}/health/liveness" "ThunderID server" }