ci: retry npm ci in e2e workflow on transient failures #217
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: E2E | |
| on: | |
| push: | |
| branches: [main, development, nightly, 'feature/**'] | |
| pull_request: | |
| branches: [main, development, nightly] | |
| jobs: | |
| e2e: | |
| runs-on: ubuntu-latest | |
| # No step here should ever legitimately run long — a genuine hang | |
| # (e.g. total loss of runner connectivity) should fail fast instead | |
| # of tying up the runner for hours. Without this, GitHub's default | |
| # 360m job timeout is the only backstop. | |
| timeout-minutes: 20 | |
| env: | |
| # docker-compose.yml's base AUTH_SECRET is a required (`:?`) variable | |
| # interpolated from the shell environment before docker-compose.e2e.yml's | |
| # override ever merges in — so compose fails at parse time on a CI | |
| # runner with no .env file, even though the override replaces this | |
| # value with its own literal AUTH_SECRET for the actual container. | |
| # Any non-empty placeholder satisfies the base file's interpolation. | |
| AUTH_SECRET: unused-placeholder-overridden-by-docker-compose.e2e.yml | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Build and start the app (real Docker image, per docs/current_spec.md Decision 4) | |
| run: docker compose -f docker-compose.yml -f docker-compose.e2e.yml build | |
| - name: Start containers | |
| run: docker compose -f docker-compose.yml -f docker-compose.e2e.yml up -d | |
| - name: Wait for the app to become healthy | |
| run: | | |
| for i in $(seq 1 60); do | |
| if curl -sf http://127.0.0.1:8080/api/health >/dev/null; then | |
| echo "App is up" | |
| exit 0 | |
| fi | |
| sleep 2 | |
| done | |
| echo "App did not become healthy in time" >&2 | |
| docker compose -f docker-compose.yml -f docker-compose.e2e.yml logs | |
| exit 1 | |
| # Runs npm ci + the suite inside Microsoft's official Playwright | |
| # image, whose tag is derived from the resolved @playwright/test | |
| # version in frontend/package-lock.json so the pre-baked browsers | |
| # always match the npm-installed client (a hardcoded tag silently | |
| # drifts the moment a dep bump lands on one branch but not the | |
| # other). This replaces `npx playwright install --with-deps` on | |
| # the bare runner. The prior approach repeatedly hit severe | |
| # `azure.archive.ubuntu.com` mirror flakiness fetching apt's font | |
| # packages (one run saw a 107KB package take 7 minutes, then | |
| # timed out entirely on the next one) — a real, recurring | |
| # infrastructure flake, not something a longer timeout reliably | |
| # fixes. This image ships every browser + system dependency | |
| # pre-baked, so no apt install happens at all. `--network host` | |
| # lets the container reach the app/Mailpit via the host ports | |
| # docker-compose.e2e.yml already publishes, exactly like running | |
| # Playwright natively on the runner would. | |
| - name: Run e2e suite (official Playwright image — pre-baked browsers/deps) | |
| timeout-minutes: 10 | |
| run: | | |
| PW_VERSION=$(jq -r '.packages["node_modules/@playwright/test"].version' frontend/package-lock.json) | |
| echo "Using Playwright image mcr.microsoft.com/playwright:v${PW_VERSION}-noble" | |
| docker run --rm --network host \ | |
| -v "$PWD/frontend:/work" -w /work \ | |
| -e PLAYWRIGHT_BASE_URL \ | |
| "mcr.microsoft.com/playwright:v${PW_VERSION}-noble" \ | |
| bash -c ' | |
| for i in 1 2 3; do | |
| npm ci && exit_code=0 && break || exit_code=$? | |
| echo "npm ci failed (attempt $i/3), retrying..." >&2 | |
| sleep 5 | |
| done | |
| [ "$exit_code" = 0 ] || exit "$exit_code" | |
| npx playwright test | |
| ' | |
| - name: Upload Playwright report | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 | |
| with: | |
| name: playwright-report | |
| path: frontend/playwright-report/ | |
| retention-days: 7 | |
| - name: Tear down containers | |
| if: always() | |
| run: docker compose -f docker-compose.yml -f docker-compose.e2e.yml down -v |