ci: keep browser e2e out of normal pr path
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Waiting to run
CI / Detect changes (pull_request) Successful in 12s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 13s
sop-tier-check / tier-check (pull_request) Successful in 4s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 10s
E2E API Smoke Test / detect-changes (pull_request) Successful in 12s
E2E Chat / detect-changes (pull_request) Successful in 9s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 10s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 7s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 7s
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 7s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
lint-continue-on-error-tracking / lint-continue-on-error-tracking (pull_request) Successful in 1m16s
lint-required-workflows-docker-host-pinned / Lint docker-host pin on docker-touching workflows (pull_request) Successful in 3s
Lint pre-flip continue-on-error / Verify continue-on-error flips have run-log proof (pull_request) Successful in 1m4s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 10s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 4s
gate-check-v3 / gate-check (pull_request) Successful in 5s
qa-review / approved (pull_request) Failing after 5s
sop-checklist / na-declarations (pull_request) N/A: (none)
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 34s
security-review / approved (pull_request) Failing after 6s
sop-checklist / all-items-acked (pull_request) Successful in 5s
sop-checklist / review-refire (pull_request) Has been skipped
lint-required-context-exists-in-bp / lint-required-context-exists-in-bp (pull_request) Successful in 1m24s
CI / Platform (Go) (pull_request) Successful in 3m6s
Lint workflow YAML (Gitea-1.22.6-hostile shapes) / Lint workflow YAML for Gitea-1.22.6-hostile shapes (pull_request) Successful in 1m22s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 5s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 3s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 12s
E2E Chat / E2E Chat (pull_request) Successful in 8s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 6s
CI / Canvas (Next.js) (pull_request) Successful in 5m14s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Python Lint & Test (pull_request) Successful in 6m40s
CI / all-required (pull_request) Successful in 6m43s
audit-force-merge / audit (pull_request) Successful in 7s

This commit is contained in:
core-fe
2026-05-20 21:02:33 -07:00
parent c58ffd2828
commit 16b203fff1
3 changed files with 91 additions and 11 deletions
+34 -3
View File
@@ -1,8 +1,10 @@
name: E2E Chat
# Comprehensive Playwright E2E for the unified chat stack (desktop
# ChatTab + mobile MobileChat). Runs on every PR that touches canvas,
# workspace-server, or this workflow file.
# ChatTab + mobile MobileChat). Heavy browser execution is intentionally
# outside the normal required PR path: PRs run it only after entering the
# `merge-queue`, while push/main, nightly, and manual dispatch preserve
# coverage without making every PR pay the full runtime/browser cost.
#
# Architecture:
# 1. Ephemeral Postgres + Redis (docker, unique container names)
@@ -22,6 +24,11 @@ on:
branches: [main, staging]
pull_request:
branches: [main, staging]
schedule:
# Nightly at 09:00 UTC. Keeps coverage for the currently non-required
# heavy browser lane without spending runner time on every PR.
- cron: '0 9 * * *'
workflow_dispatch:
concurrency:
group: e2e-chat-${{ github.event.pull_request.head.sha || github.sha }}
@@ -50,7 +57,14 @@ jobs:
with:
fetch-depth: 0
- id: decide
env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
QUEUE_LABEL: merge-queue
run: |
if [ "${{ github.event_name }}" = "schedule" ] || [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "chat=true" >> "$GITHUB_OUTPUT"
exit 0
fi
BASE="${GITHUB_BASE_REF:-${{ github.event.before }}}"
if [ "${{ github.event_name }}" = "pull_request" ] && [ -n "${{ github.event.pull_request.base.sha }}" ]; then
BASE="${{ github.event.pull_request.base.sha }}"
@@ -67,9 +81,26 @@ jobs:
exit 0
fi
CHANGED=$(git diff --name-only "$BASE" HEAD)
if echo "$CHANGED" | grep -qE '^(canvas/|workspace-server/|\.gitea/workflows/e2e-chat\.yml$)'; then
if ! echo "$CHANGED" | grep -qE '^(canvas/|workspace-server/|\.gitea/workflows/e2e-chat\.yml$)'; then
echo "chat=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "chat=true" >> "$GITHUB_OUTPUT"
exit 0
fi
authfile=$(mktemp)
chmod 600 "$authfile"
printf 'header = "Authorization: token %s"\n' "$GITEA_TOKEN" > "$authfile"
labels=$(curl -fsS -K "$authfile" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" \
| python3 -c 'import json,sys; print("\n".join(label.get("name","") for label in json.load(sys.stdin)))')
rm -f "$authfile"
if printf '%s\n' "$labels" | grep -qx "$QUEUE_LABEL"; then
echo "chat=true" >> "$GITHUB_OUTPUT"
else
echo "PR is not in merge-queue; skipping heavy E2E Chat for normal PR path."
echo "chat=false" >> "$GITHUB_OUTPUT"
fi
+29 -8
View File
@@ -16,9 +16,9 @@ name: E2E Staging Canvas (Playwright)
# e2e-staging-saas.yml (which tests the API shape) by exercising the
# actual browser + canvas bundle against live staging.
#
# Triggers: push to main/staging or PR touching canvas sources + this workflow,
# manual dispatch, and weekly cron to catch browser/runtime drift even
# when canvas is quiet.
# Triggers: push to main, PR touching canvas sources + this workflow only
# after the PR enters `merge-queue`, manual dispatch, and scheduled cron to
# catch browser/runtime drift even when canvas is quiet.
# Added staging to push/pull_request branches so the auto-promote gate
# check (--event push --branch staging) can see a completed run for this
# workflow — mirrors what PR #1891 does for e2e-api.yml.
@@ -37,9 +37,10 @@ on:
pull_request:
branches: [main]
schedule:
# Weekly on Sunday 08:00 UTC — catches Chrome / Playwright / Next.js
# Nightly at 08:00 UTC — catches Chrome / Playwright / Next.js
# release-note-shaped regressions that don't ride in with a PR.
- cron: '0 8 * * 0'
- cron: '0 8 * * *'
workflow_dispatch:
concurrency:
# Per-SHA grouping (changed 2026-04-28 from a single global group). The
@@ -79,10 +80,13 @@ jobs:
with:
fetch-depth: 0
- id: decide
env:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
QUEUE_LABEL: merge-queue
# Inline replacement for dorny/paths-filter — see e2e-api.yml.
# Cron triggers always run real work (no diff context).
# Cron and manual triggers always run real work (no diff context).
run: |
if [ "${{ github.event_name }}" = "schedule" ]; then
if [ "${{ github.event_name }}" = "schedule" ] || [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "canvas=true" >> "$GITHUB_OUTPUT"
exit 0
fi
@@ -102,9 +106,26 @@ jobs:
exit 0
fi
CHANGED=$(git diff --name-only "$BASE" HEAD)
if echo "$CHANGED" | grep -qE '^(canvas/|\.gitea/workflows/e2e-staging-canvas\.yml$)'; then
if ! echo "$CHANGED" | grep -qE '^(canvas/|\.gitea/workflows/e2e-staging-canvas\.yml$)'; then
echo "canvas=false" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "canvas=true" >> "$GITHUB_OUTPUT"
exit 0
fi
authfile=$(mktemp)
chmod 600 "$authfile"
printf 'header = "Authorization: token %s"\n' "$GITEA_TOKEN" > "$authfile"
labels=$(curl -fsS -K "$authfile" \
"${{ github.server_url }}/api/v1/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/labels" \
| python3 -c 'import json,sys; print("\n".join(label.get("name","") for label in json.load(sys.stdin)))')
rm -f "$authfile"
if printf '%s\n' "$labels" | grep -qx "$QUEUE_LABEL"; then
echo "canvas=true" >> "$GITHUB_OUTPUT"
else
echo "PR is not in merge-queue; skipping heavy E2E Staging Canvas for normal PR path."
echo "canvas=false" >> "$GITHUB_OUTPUT"
fi
+28
View File
@@ -0,0 +1,28 @@
from pathlib import Path
import yaml
ROOT = Path(__file__).resolve().parents[1]
def workflow_on(path: Path):
doc = yaml.safe_load(path.read_text())
return doc.get("on") or doc.get(True)
def test_browser_e2e_workflows_are_not_unconditional_pr_heavy_lanes():
workflows = [
ROOT / ".gitea/workflows/e2e-chat.yml",
ROOT / ".gitea/workflows/e2e-staging-canvas.yml",
]
for path in workflows:
text = path.read_text()
events = workflow_on(path)
assert "workflow_dispatch" in events
assert "schedule" in events
assert "merge-queue" in text
assert "/issues/${{ github.event.pull_request.number }}/labels" in text
assert "PR is not in merge-queue" in text