Files
openobserve/.github/workflows/ent-e2e-gate.yml
T
Shrinath RaoandClaude Opus 4.8 cf3681c5f0 ci: rename ENT e2e gate → Playwright E2E Crosscheck (#13411)
Gives the cross-repo enterprise-e2e gate a real name: **Playwright E2E
Crosscheck**.

Branding only — no behaviour change. Renames the workflow, the **check
name** (what shows on the PR), every sticky-comment header, and the
hidden comment marker. Filenames unchanged. The check isn't required
yet, so nothing in branch protection references the old name.

Note: the marker change means the *next* run on a PR that already has an
old `ent-e2e-gate` sticky comment will post a fresh one (the old one is
orphaned) — only affects a couple of in-flight test PRs. Companion:
o2-enterprise `ci/crosscheck-rename`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 11:35:38 +00:00

277 lines
14 KiB
YAML

name: Playwright E2E Crosscheck
# Pre-merge GUARD (runs in openobserve) that stops an OSS PR from silently breaking the
# enterprise-only e2e specs. web/tests live in OSS; the ENT e2e *triggers* live in o2-enterprise,
# so today an OSS frontend/test change only surfaces as an ENT breakage in some later ENT PR.
#
# This job IS the required status check. Make `Playwright E2E Crosscheck` a required check on main in OSS
# branch protection to actually block merges (one-time admin toggle).
#
# Behaviour (A+A+C design):
# - PR does NOT touch web/** or tests/ui-testing/** → pass instantly (never blocks).
# - Touches them + `skip-ent-e2e` label → pass (explicit, auditable opt-out).
# - Touches them + NO `e2e` label → FAIL "add the e2e label" (blocks; no silent miss).
# - Touches them + `e2e` label:
# · open sister ENT PR (same-named branch) → DEFER to that PR's checks (link it, don't build here)
# · sister ENT branch only (no PR) → build the enterprise binary against that branch
# · no ENT counterpart → build against ENT main
# then POLL and mirror pass/fail.
#
# A single STICKY comment per PR (found by a hidden marker) reports running → passed / failed, lists the
# failing specs (or an enterprise build failure), and links the sister ENT PR/branch + the ENT run.
#
# Pure CI — no AI/LLM. Deterministic dispatch + poll of o2-enterprise/oss-pr-ent-gate.yml.
#
# Secrets/vars:
# secrets.ORG_ADMIN_TOKEN — PAT: o2-enterprise Actions R/W (dispatch+poll) + openobserve PRs R/W (comment as human).
# vars.ENT_GATE_REF — o2-enterprise ref that carries oss-pr-ent-gate.yml (default 'main';
# only override to test the engine itself from a branch).
# vars.ENT_E2E_GATE_DISABLED — 'true' kill switch: gate passes without dispatching.
on:
pull_request:
# labeled/unlabeled so adding `e2e`/`skip-ent-e2e` re-fires and re-evaluates the gate.
types: [opened, reopened, synchronize, labeled, unlabeled]
# PR-scoped: a new push/label supersedes the previous gate attempt for the same PR.
concurrency:
group: playwright-e2e-crosscheck-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
jobs:
playwright-e2e-crosscheck:
name: Playwright E2E Crosscheck
runs-on: ubuntu-latest
# ~5 min to find the ENT run + up to ~75 min to poll. Generous on purpose: normal is ~20 min,
# but a cold Rust cache can push the ENT build+run toward its own timeouts — don't false-fail
# the gate ("timed out") while ENT is still legitimately running.
timeout-minutes: 90
steps:
- name: Triage — relevant paths? which label?
id: triage
env:
GH_TOKEN: ${{ github.token }} # OSS is same-repo/public → default token can read PR files
PR: ${{ github.event.pull_request.number }}
HAS_E2E: ${{ contains(github.event.pull_request.labels.*.name, 'e2e') }}
HAS_SKIP: ${{ contains(github.event.pull_request.labels.*.name, 'skip-ent-e2e') }}
DISABLED: ${{ vars.ENT_E2E_GATE_DISABLED }}
IS_FORK: ${{ github.event.pull_request.head.repo.fork }}
run: |
set -euo pipefail
if [ "$DISABLED" = "true" ]; then
echo "::notice::ENT_E2E_GATE_DISABLED=true — passing without dispatch."
echo "mode=pass" >> "$GITHUB_OUTPUT"; exit 0
fi
# Fork PRs: head branch isn't in openobserve/openobserve and the PAT isn't available to
# forked-PR runs, so the ENT engine can't check it out. Pass with a notice; a maintainer
# re-runs from an internal branch if enterprise validation is needed.
if [ "$IS_FORK" = "true" ]; then
echo "::notice::Fork PR — Playwright E2E Crosscheck can't run (no PAT / branch not in main repo). Passing."
echo "mode=pass" >> "$GITHUB_OUTPUT"; exit 0
fi
# Relevant = any changed file under web/ or tests/ui-testing/
FILES=$(gh api "repos/${{ github.repository }}/pulls/$PR/files" --paginate -q '.[].filename')
if printf '%s\n' "$FILES" | grep -qE '^(web/|tests/ui-testing/)'; then
RELEVANT=true
else
RELEVANT=false
fi
echo "::notice::Relevant (web/** or tests/ui-testing/**) changes: $RELEVANT"
if [ "$RELEVANT" != "true" ]; then
echo "mode=pass" >> "$GITHUB_OUTPUT"
elif [ "$HAS_SKIP" = "true" ]; then
echo "::warning::PR carries 'skip-ent-e2e' — enterprise gate explicitly opted out (auditable)."
echo "mode=skip" >> "$GITHUB_OUTPUT"
elif [ "$HAS_E2E" != "true" ]; then
echo "mode=need-label" >> "$GITHUB_OUTPUT"
else
echo "mode=run" >> "$GITHUB_OUTPUT"
fi
- name: Pass — no enterprise-relevant changes (or opted out / disabled)
if: steps.triage.outputs.mode == 'pass' || steps.triage.outputs.mode == 'skip'
run: echo "✅ Playwright E2E Crosscheck not required for this PR."
- name: Block — enterprise-relevant change without the e2e label
if: steps.triage.outputs.mode == 'need-label'
run: |
echo "::error::This PR changes web/** or tests/ui-testing/**, which can break enterprise-only e2e specs."
echo "::error::Add the 'e2e' label to run the enterprise gate (or 'skip-ent-e2e' to explicitly opt out)."
exit 1
- name: Run — dispatch ENT engine, poll, mirror result
if: steps.triage.outputs.mode == 'run'
env:
GH_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} # PAT: dispatch+poll o2-enterprise, comment as human
PR: ${{ github.event.pull_request.number }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
ENT_REF: ${{ vars.ENT_GATE_REF || 'main' }}
run: |
set -euo pipefail
REPO="openobserve/o2-enterprise"; WF="oss-pr-ent-gate.yml"
MARKER="<!-- playwright-e2e-crosscheck -->"
# Upsert ONE sticky gate comment per PR (located by the hidden marker) so status updates in
# place — pass AND fail — instead of spamming a fresh comment each run.
sticky() {
local body="$1" cid
cid=$(gh api "repos/openobserve/openobserve/issues/$PR/comments" --paginate \
-q "[.[] | select(.body|contains(\"$MARKER\")) | .id][0]" 2>/dev/null || echo "")
if [ -n "$cid" ] && [ "$cid" != "null" ]; then
gh api -X PATCH "repos/openobserve/openobserve/issues/comments/$cid" -f body="$body" >/dev/null 2>&1 || true
else
gh api -X POST "repos/openobserve/openobserve/issues/$PR/comments" -f body="$body" >/dev/null 2>&1 || true
fi
}
# Sister ENT resolution. An OPEN same-named ENT PR is the live counterpart — let ITS checks
# own enterprise validation; we DEFER (don't build here), just link. Only a branch (no PR) →
# build against that branch. Neither → build against main.
SISTER_PR=$(gh pr list --repo "$REPO" --head "$HEAD_REF" --state open --json number -q '.[0].number' 2>/dev/null || echo "")
if [ -n "$SISTER_PR" ] && [ "$SISTER_PR" != "null" ]; then
sticky "### ⏭️ Playwright E2E Crosscheck — handled by the sister ENT PR
$MARKER
This OSS PR has a matching enterprise PR on branch \`$HEAD_REF\`: **openobserve/o2-enterprise#$SISTER_PR**. The enterprise-only e2e specs run there, so this gate defers to that PR's checks and does not build here."
echo "::notice::Sister ENT PR #$SISTER_PR is open — deferring, not dispatching."
exit 0
fi
if gh api "repos/$REPO/branches/$HEAD_REF" >/dev/null 2>&1; then
ENT_CODE_REF="$HEAD_REF"
SISTER_NOTE="Built against the matching ENT branch \`$HEAD_REF\` (no ENT PR yet)."
echo "::notice::ENT branch '$HEAD_REF' exists (no PR) — building against it."
else
ENT_CODE_REF=main
SISTER_NOTE="No ENT counterpart — built against ENT \`main\`."
echo "::notice::No ENT counterpart for '$HEAD_REF' — building against main."
fi
# Stamp the time BEFORE dispatch so correlation can reject stale prior runs for this PR.
DISPATCH_TS=$(date -u +%s)
echo "::notice::Dispatching ENT engine ($REPO@$ENT_REF, code=$ENT_CODE_REF) for OSS PR #$PR ($HEAD_REF)…"
gh workflow run "$WF" --repo "$REPO" --ref "$ENT_REF" \
-f oss_branch="$HEAD_REF" \
-f oss_pr="$PR" \
-f oss_sha="$HEAD_SHA" \
-f enterprise_ref="$ENT_CODE_REF"
# Correlate by PR-scoped run-name ("Playwright E2E Crosscheck — OSS PR #<PR> ("; the "(" boundary keeps
# #12 from matching #123) AND createdAt >= dispatch time (minus 60s clock-skew), so a stale
# prior run for this PR is never picked. Take the NEWEST qualifying run.
MATCH="OSS PR #$PR ("
MIN_TS=$((DISPATCH_TS - 60))
RUN_ID=""
sleep 8 # let the dispatched run register before the first lookup
for i in $(seq 1 30); do # ~5 min to appear
RUN_ID=$(gh run list --repo "$REPO" --workflow "$WF" -L 40 \
--json databaseId,displayTitle,createdAt \
-q "[.[] | select(.displayTitle | contains(\"$MATCH\")) | select((.createdAt|fromdateiso8601) >= $MIN_TS)] | sort_by(.createdAt) | last | .databaseId" 2>/dev/null || echo "")
if [ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ]; then break; fi
sleep 10
done
if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then
sticky "### 🚫 Playwright E2E Crosscheck — could not start
$MARKER
Dispatching the enterprise e2e engine failed or the run never appeared (check \`ORG_ADMIN_TOKEN\` / \`ENT_GATE_REF=$ENT_REF\`). The gate stays red until it runs — re-push or re-label to retry.
$SISTER_NOTE"
echo "::error::Could not locate the dispatched ENT run within 5 min — failing the gate (unverified)."
exit 1
fi
RUN_URL="https://github.com/$REPO/actions/runs/$RUN_ID"
echo "::notice::Tracking ENT run: $RUN_URL"
sticky "### 🔄 Playwright E2E Crosscheck — running
$MARKER
Building the enterprise binary and running the enterprise-only e2e specs against this PR.
$SISTER_NOTE
[ENT run]($RUN_URL)"
# Poll to completion (~75 min budget — covers a cold-cache ENT build+run worst case).
STATUS=""; CONCL=""
for i in $(seq 1 300); do # 300 * 15s = 75 min
read -r STATUS CONCL < <(gh run view "$RUN_ID" --repo "$REPO" \
--json status,conclusion -q '.status + " " + (.conclusion // "")' 2>/dev/null || echo "unknown ")
if [ "$STATUS" = "completed" ]; then break; fi
sleep 15
done
if [ "$STATUS" != "completed" ]; then
sticky "### ⏳ Playwright E2E Crosscheck — timed out
$MARKER
The [enterprise e2e run]($RUN_URL) didn't finish within the poll window. The gate stays red — re-push to retry.
$SISTER_NOTE"
echo "::error::ENT run did not finish within the poll window."
exit 1
fi
if [ "$CONCL" = "success" ]; then
sticky "### ✅ Playwright E2E Crosscheck — passed
$MARKER
The enterprise-only e2e specs passed against this PR. $SISTER_NOTE
[ENT run]($RUN_URL)"
echo "::notice::✅ Enterprise e2e specs passed against this PR."
exit 0
fi
# cancelled/skipped/empty ≈ a newer push superseded this run (engine cancel-in-progress).
# NOT a failure — the newer run is authoritative and updates the sticky itself. Defer.
if [ "$CONCL" = "cancelled" ] || [ "$CONCL" = "skipped" ] || [ -z "$CONCL" ]; then
echo "::notice::ENT run concluded '$CONCL' (likely superseded by a newer push) — deferring, not failing."
exit 0
fi
# Genuine failure — distinguish an enterprise BUILD failure (compile) from SPEC failures,
# and for specs list the failing files from the engine's failed-specs artifact.
BUILD_CONCL=$(gh run view "$RUN_ID" --repo "$REPO" --json jobs -q '.jobs[]|select(.name=="build_binary")|.conclusion' 2>/dev/null || echo "")
TEST_CONCL=$(gh run view "$RUN_ID" --repo "$REPO" --json jobs -q '.jobs[]|select(.name=="ent_gate_tests")|.conclusion' 2>/dev/null || echo "")
if [ "$TEST_CONCL" = "failure" ]; then
rm -rf /tmp/fs; SPEC_LIST=""
if gh run download "$RUN_ID" --repo "$REPO" -n failed-specs -D /tmp/fs >/dev/null 2>&1 && [ -f /tmp/fs/failed-specs.txt ]; then
SPEC_LIST=$(sed '/^[[:space:]]*$/d; s/^/- `/; s/$/`/' /tmp/fs/failed-specs.txt)
fi
[ -n "$SPEC_LIST" ] || SPEC_LIST="_(couldn't read the failed-spec list — open the run for details)_"
sticky "### 🚫 Playwright E2E Crosscheck — Needs Review
$MARKER
The **enterprise-only** e2e spec(s) below failed against this PR. They run only against the enterprise binary, so this breakage wouldn't show up in OSS CI:
$SPEC_LIST
$SISTER_NOTE · [ENT run]($RUN_URL)
Fix and re-push, or add \`skip-ent-e2e\` if this is a known-safe change."
elif [ "$BUILD_CONCL" = "failure" ]; then
sticky "### 🚫 Playwright E2E Crosscheck — enterprise build failed
$MARKER
The enterprise binary didn't compile against this PR, so the specs never ran. This usually means the OSS code references enterprise code not present on the ref it was built against.
$SISTER_NOTE · [ENT run]($RUN_URL)"
else
sticky "### 🚫 Playwright E2E Crosscheck — failed
$MARKER
The [enterprise e2e run]($RUN_URL) failed (conclusion: \`$CONCL\`).
$SISTER_NOTE"
fi
echo "::error::Enterprise gate failed (conclusion=$CONCL build=$BUILD_CONCL test=$TEST_CONCL)."
exit 1