From d278c8ba9cb94be18a51fb676f39fc09a5fce59a Mon Sep 17 00:00:00 2001 From: Kamil Krzywda Date: Wed, 23 Sep 2026 17:07:23 +0000 Subject: [PATCH] v0.66.0: e2e results in Gitea job summary (#141) The run page's Job summaries panel showed vitest results (vitest's built-in github-actions reporter auto-appends $GITHUB_STEP_SUMMARY in CI) but nothing about the Playwright suite. The E2E step now also runs the built-in json reporter (--reporter=list,json, output pinned to git-ignored test-results/e2e.json via PLAYWRIGHT_JSON_OUTPUT_FILE), and a new non-fatal 'E2E job summary' step (if: always()) parses it with an inline node script and appends spec-level passed/failed/skipped counts + failed spec names (file > title) to $GITHUB_STEP_SUMMARY. Guarded so a missing/malformed report can never fail or mask the e2e step's real exit code; no test behavior, timeouts, workers or retries changed. --- .gitea/workflows/ci.yml | 50 +++++++++++++++++++++++++++++++++++++++-- CHANGELOG.md | 3 +++ package.json | 2 +- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 161486f..e66aa15 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -189,10 +189,56 @@ jobs: # in-network app host out of any proxy path. NO_PROXY: app,localhost,127.0.0.1,.kkhost.pl no_proxy: app,localhost,127.0.0.1,.kkhost.pl + # Machine-readable e2e results for the job-summary step below (Playwright's built-in + # json reporter; without this env var it would dump to stdout). test-results/ is git-ignored. + PLAYWRIGHT_JSON_OUTPUT_FILE: test-results/e2e.json # Connectivity diagnostics now run post-deploy in e2e/ci-diagnostics.ts (globalSetup). # --reporter=list prints each test as it completes (name + ✓/× + duration) for progress - # visibility in the job log; failure error context/snapshots are unchanged. - run: npx playwright test --reporter=list + # visibility in the job log; failure error context/snapshots are unchanged. The json + # reporter adds a machine-readable report (PLAYWRIGHT_JSON_OUTPUT_FILE above) — no + # execution behavior changes, reporters only observe. + run: npx playwright test --reporter=list,json + + # Appends e2e results to the job-summary panel — mirrors how unit tests get there + # (vitest's built-in github-actions reporter auto-appends $GITHUB_STEP_SUMMARY in CI). + # if: always() so a FAILED suite still gets summarized; non-fatal by design — a missing + # or malformed report must never mask the real e2e exit code. The script is single-quoted + # for bash, so it contains no apostrophes. + - name: E2E job summary + if: always() + run: | + node -e ' + const fs = require("fs"); + let report; + try { + report = JSON.parse(fs.readFileSync("test-results/e2e.json", "utf8")); + } catch { + process.exit(0); // e2e never ran (earlier step failed) or no report — nothing to summarize + } + let passed = 0, skipped = 0; + const failed = []; + const walk = (suite) => { + for (const spec of suite.specs ?? []) { + if (!spec.ok) failed.push(`${suite.title} › ${spec.title}`); + else if ((spec.tests ?? []).length && spec.tests.every((t) => t.expectedStatus === "skipped")) skipped++; + else passed++; + } + for (const sub of suite.suites ?? []) walk(sub); + }; + for (const s of report.suites ?? []) walk(s); + const lines = [ + "", "## E2E results", "", + `- Passed: ${passed}`, + `- Failed: ${failed.length}`, + `- Skipped: ${skipped}`, + ]; + if (failed.length) { + lines.push("", "### Failed specs"); + for (const f of failed) lines.push(`- \`${f}\``); + } + const summaryFile = process.env.GITHUB_STEP_SUMMARY; + if (summaryFile) fs.appendFileSync(summaryFile, lines.join("\n") + "\n"); + ' || true # The daemon is shared with production — never leave our stack or network behind. # -v drops the named DB volume so every run seeds fresh (no schema drift between PRs). diff --git a/CHANGELOG.md b/CHANGELOG.md index 80787c3..b1faa1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v0.66.0 — 2026-09-23 17:06 +- **E2E results in the Gitea job summary (#141).** The run page's "Job summaries" panel showed vitest results (vitest's built-in `github-actions` reporter auto-appends `$GITHUB_STEP_SUMMARY` when `GITHUB_ACTIONS=true`) but nothing about the Playwright suite, so a failed e2e run required digging into raw logs to see which specs broke. The CI E2E step now also runs Playwright's built-in `json` reporter (`--reporter=list,json`, output pinned to git-ignored `test-results/e2e.json` via `PLAYWRIGHT_JSON_OUTPUT_FILE` — no new dependencies, no config/TS changes), and a new non-fatal "E2E job summary" step (`if: always()`) parses that report with an inline node script and appends spec-level passed/failed/skipped counts plus the file + title of every failed spec to `$GITHUB_STEP_SUMMARY` — mirroring exactly how vitest gets there. The append is guarded (`|| true`, missing/malformed report = silent no-op) so it can never fail or mask the e2e step's real exit code; test behavior, timeouts, workers and retries are untouched. + ## v0.65.0 — 2026-09-23 12:58 - **Per-airport job pools with real-time refresh.** The market was a global bag of jobs (top-up to `MARKET_TARGET_OPEN_PACKAGES = 10` + coverage spawn at uncovered grounded airports), so the board showed work you could never take and hid nothing. Now open jobs are generated PER AIRPORT where a plane can actually pick them up — the pool is the set of grounded planes' `locationIcao`, flying planes' `destIcao` and queued-leg ICAOs — queued legs count even while their plane is in the shop (the work will be waiting at its next stop); a fleet fully repairing with empty queues has no pool, and orphaned pools simply expire out. Each pool airport holds exactly `POOL_TARGET_PER_AIRPORT = 10` open jobs in a fixed weight composition (`POOL_BANDS`: 2×[500,4000) + 6×[4000,18000) + 1×[18000,48000] + 1×(48000,80000] kg), so the board always mixes jobs you can take now with heavier ones that are what you buy better planes for. `spawnPoolPackages` in `lib/sim/engine.ts` replaces both old spawners and runs on every tick (including frozen ones) like v0.64.0's top-up; seeded and spawned packages come from the same new `generatePoolPackage` helper in `lib/game/seed.ts`, so they are indistinguishable — `buildSeed` now seeds a full pool at the starter's home hub, and `PACKAGE_COUNT_MIN/MAX` + `MARKET_TARGET_OPEN_PACKAGES` are retired. - **Open jobs live on the wall clock.** New `created_real_ms INTEGER NOT NULL DEFAULT 0` column (guarded ALTER backfilled with `Date.now()` for existing rows): an open job expires `JOB_LIFETIME_MS = 1 h` after creation regardless of time scale or fleet state — checked every tick OUTSIDE the advance gate, so a paused world still refreshes its board. Loaded jobs keep their sim-clock deadline logic unchanged (delivery check, expiry floor, abandon penalty all untouched). Taken slots (loaded OR ignored) stamp `slot_free_at_real_ms` and hold their pool slot for a refill cooldown — `REFILL_DELAY_MS = 15 min`, or `SMALL_REFILL_DELAY_MS = 1 min` for the <4 t band — so the board visibly refreshes instead of instantly refilling; expired/delivered/abandoned never block. ponytail: one shared per-airport cooldown (the max stamp) rather than a per-band table, add when per-band refill timing matters. diff --git a/package.json b/package.json index b35c8c1..4bcfb7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flight-ops", - "version": "0.65.0", + "version": "0.66.0", "private": true, "scripts": { "dev": "next dev -p 3000",