name: E2E (post-deploy)

# Reusable post-deploy Playwright stage (M24-9), shared by the E2E (dev) and E2E (staging)
# callers so the two lanes cannot drift. Runs the full browser suite (apps/web/e2e) against a
# DEPLOYED environment origin, authenticating through the password-gated test-login path
# (apps/web/e2e/README.md), then hands the verdict to the promote/auto-rollback handler
# (scripts/deploy/e2e-promote-rollback.sh, E2E-7 - decision matrix unit-tested offline).
#
# The target origin must (a) serve /api same-origin and (b) run the API with
# BLOOM_ENABLE_TEST_LOGIN=true + BLOOM_TEST_LOGIN_PASSWORD - both delivered at runtime as
# per-environment Actions secrets, never committed (activation runbook: docs/deployment.md).

on:
  workflow_call:
    inputs:
      environment:
        description: GitHub environment to run against (dev | staging) - its secrets supply
          BLOOM_TEST_LOGIN_PASSWORD and the DEPLOY_* promote/rollback credentials.
        required: true
        type: string
      base-url:
        description: The deployed dashboard origin the suite targets. Callers gate on their
          env's repo variable being set; an empty value skips here too (dormant state).
        required: true
        type: string

permissions:
  contents: read

jobs:
  e2e:
    # Defense in depth - callers already gate on the base-URL variable being configured.
    if: ${{ inputs.base-url != '' }}
    runs-on: bloom-arc
    environment: ${{ inputs.environment }}
    permissions:
      contents: read
      packages: read
    defaults:
      run:
        working-directory: apps/web
    steps:
      # The suite version must match the deployed code, which always comes from main (the
      # milestone flow deploys only on merges to main; a staging deploy pins a main SHA too).
      - uses: actions/checkout@v4
        with:
          ref: main

      - uses: pnpm/action-setup@v4
        with:
          version: 10.6.3

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm
          cache-dependency-path: pnpm-lock.yaml

      # Workspace-root install (single lockfile, #481) - overrides the job's apps/web default cwd.
      - name: Install web dependencies
        working-directory: ${{ github.workspace }}
        run: pnpm install --frozen-lockfile

      - name: Install Playwright browser
        # ARC ephemeral runners are a minimal image lacking browser system libs; they run as root, so --with-deps installs them per job. (Static-VM runner had libs pre-provisioned + no sudo; that runner is decommissioned by this PR.)
        run: pnpm exec playwright install --with-deps chromium

      - name: Run Playwright E2E suite
        env:
          # The deployed dashboard origin (serves /api same-origin, test-login enabled on its API).
          E2E_BASE_URL: ${{ inputs.base-url }}
          # Unlocks the env's password-gated test surface (test-login + /api/testing/*); the
          # fixtures send it as the X-Bloom-Test-Login-Password header. Empty until the operator
          # arms the environment - harmless while the suite is dormant.
          BLOOM_TEST_LOGIN_PASSWORD: ${{ secrets.BLOOM_TEST_LOGIN_PASSWORD }}
        run: pnpm run test:e2e

      # Known-flaky specs tagged @quarantine run in their own lane and can never red the stage
      # (continue-on-error). Fix and untag them, don't ignore them (see apps/web/e2e/README.md).
      - name: Run quarantined specs (non-blocking)
        if: ${{ !cancelled() }}
        continue-on-error: true
        env:
          E2E_BASE_URL: ${{ inputs.base-url }}
          BLOOM_TEST_LOGIN_PASSWORD: ${{ secrets.BLOOM_TEST_LOGIN_PASSWORD }}
          PLAYWRIGHT_HTML_REPORT: playwright-report-quarantine
        run: pnpm run test:e2e:quarantine

      - name: Upload Playwright report and traces
        if: ${{ !cancelled() }}
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report-${{ inputs.environment }}
          path: |
            apps/web/playwright-report
            apps/web/playwright-report-quarantine
            apps/web/test-results
          retention-days: 7
          if-no-files-found: ignore

      # --- E2E-7: promote on pass, auto-rollback on failure ---
      # The branch matrix (which deploys roll back, which verdicts no-op, staging deferral)
      # lives in scripts/deploy/e2e-promote-rollback.sh and is asserted offline by
      # scripts/deploy/tests/test_e2e_promote_rollback.sh. An unarmed environment (no
      # DEPLOY_HOST secret) is a clean no-op.

      # e2e passed -> mark the currently-running image as the last e2e-green (rollback target).
      # continue-on-error: a promotion hiccup must never turn a green suite red.
      - name: Promote image to last e2e-green
        if: ${{ success() }}
        continue-on-error: true
        working-directory: ${{ github.workspace }}
        env:
          E2E_OUTCOME: pass
          E2E_ENV: ${{ inputs.environment }}
          E2E_TRIGGER: ${{ github.event.workflow_run.name }}
          DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
          DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
        run: bash scripts/deploy/e2e-promote-rollback.sh

      # e2e failed after an API deploy -> roll back (compose: last e2e-green image; k3s helm:
      # previous revision) and note it in the run summary (the red run + summary is the
      # notification). The handler skips triggers an API rollback would not fix.
      - name: Auto-rollback on e2e failure
        if: ${{ failure() }}
        working-directory: ${{ github.workspace }}
        env:
          E2E_OUTCOME: fail
          E2E_ENV: ${{ inputs.environment }}
          E2E_TRIGGER: ${{ github.event.workflow_run.name }}
          DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
          DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
          REGISTRY_USER: ${{ github.actor }}
          REGISTRY_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: bash scripts/deploy/e2e-promote-rollback.sh
