feat(ci): live CI page — fleet event stream, live test results, in-flight first #552
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
gmackie/ForgeGraph!552
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/ci-row-app-and-pr-first"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Makes
/cia live view of current work. Three parts: a layout that puts in-flight work first, a fleet-wide event channel, and live test results that actually arrive.Layout
Three zones, because the page answers three questions and only two are urgent.
over ~8:00rather than implying a completion it cannot know. A queued run gets no clock, just waiting for a runner.Identity (app + PR, or the branch when there is no PR) is one shared component across all three, so the same two fields lead everywhere and only the type scale changes.
Fleet channel
Every existing broadcast is addressed to
pipeline:<appId>. That is right for an app's Pipeline tab and unusable for/ci, which would need a socket per app across 77 of them. Queued and running Forgejo run progress now also goes toci:fleet, stamped with the app it came from so a fleet consumer can attribute it.Live test results — why they never worked
The agent already tails the build worktree's
.fg/check-events.ndjsonand posts a folded summary every couple of seconds. That already fanned out onapps/web'seventBus, whose own comment says it only works:That stopped being true when the control plane moved to Cloudflare Workers. Each request can land in a different isolate, so the isolate receiving the agent's POST is almost never the one holding a browser's SSE connection. The publish succeeded and nobody was listening.
Test progress now also goes over the hub, which is a real cross-instance broker and already carries pipeline events. The
eventBuspublish stays, becausefg watchconsumes it.Consumption
useFleetCiStreamsubscribes to the one fleet channel.LiveRefreshtreats an event as a hint to look, not as data: it re-runs the server render, so every number moves together. A partial live-patch would let the header disagree with the list, which on a status page is worse than being a second late.live/polling/pausedso the mode is never a guess.What I found and did not ship
handlers/workflow-run.tsmaps arequestedrun to a queued build and is wired and correct — and cannot fire on this install. Forgejo 15.0.7 has noworkflow_runwebhook event; a PATCH containing one returns 200 and silently drops it (I probedworkflow_run,workflow_job,action_run,actions,status). I wrote and tested a webhook-convergence fix before discovering this and reverted it, because it would have added an event Forgejo discards. That is why thebuildstable shows a near-empty queue while Forgejo has runs waiting, and it is worth its own decision rather than being buried here.Verification
packages/apiandapps/webtypecheck clean.next buildsucceeds and emits the/ciclient-reference manifest. 42 tests pass across the lib suites, including 5 new ones asserting both channels receive run progress and test progress, that the fleet copy carriesappId, that an unconfigured hub sends nothing, and that an unreachable hub never rejects the request that produced the event.oxlintreports nothing new on the changed files.Stacking
Built on
fix/runner-label-parsing(#551). Merge that first.🤖 Generated with Claude Code
The /ci list gave its loudest slot to the least useful field. Every row titled itself `forgejo:ci` -- the same string on nearly every row, which identifies nothing -- at 14px semibold, while the app name sat in 10px grey mono beside the branch, and the PR number appeared only when a branch happened to be named after one. Reordered to what actually distinguishes one row from another: before forgejo:ci PASSED streamConductor fix/dashboard-panels -- 7h ago after streamConductor #57 PASSED 2s fix/dashboard-panels · forgejo:ci · 7h ago The app name leads at 15px semibold and the PR number sits next to it as a link-toned chip. The pipeline name drops to the metadata line with the branch and timestamp. Rows with no PR put the branch in the PR's slot so they still identify themselves rather than reading as a bare app name. Getting a real PR number needed one: `builds` had no link to a pull request, and the branch field only sometimes holds one. `pull_requests` matches on (repo, head_ref), but it is unique on (repo, number), so a branch opened, closed and reopened has several rows and a left join would silently multiply the build list. Resolved in a second query instead, newest PR per branch, with a fallback that reads the number straight out of the branch for `pull_request`-triggered builds that arrive with sourceBranch already set to "#57". The matching is extracted to lib/build-pull-requests.ts and tested for both traps plus the near-misses (a branch like `release-2026` is not a PR, two repos sharing a branch name stay apart). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>bf1ea8e7fef6e9ca42d2feat(ci): lead each CI row with the app and PR, not the pipeline nameto feat(ci): give in-flight and just-landed runs the page, demote historyf6e9ca42d235940f0fc735940f0fc71189df575afeat(ci): give in-flight and just-landed runs the page, demote historyto feat(ci): live CI page — fleet event stream, live test results, in-flight first1189df575a96444cac4c96444cac4c3070c319f3