feat: keep a list live, and hand a running job to gh run watch #34

Merged
barrettruth merged 6 commits from feat/live-checks into main 2026-07-28 05:43:44 +00:00
Owner

Checklist

  • I have read CONTRIBUTING.md.
  • No AI was used to generate, edit, or review any part of this contribution.

Problem

A list went stale the moment it was drawn, and <CR> on a running check gave
an empty buffer and no log: job is in_progress.

Measured on rust-lang/rust while a job ran: 27 of 35 steps complete and the
log endpoint still returned 215 bytes of BlobNotFound
, while the same job's
page streamed those steps' output in a browser. GitHub publishes live text only
over its own socket; the stored log arrives when the job ends. gh has tracked
this since 2021 — cli/cli#3484.

Solution

The list polls itself. Every ten seconds, while any check is running or
pending, it re-runs the reload that R already performs — so the view is
restored, a failed poll leaves the previous content, and busy and the
generation guard work unchanged. It stops when the checks settle, when no
window shows the buffer, or on wipe.

<CR> on a running check opens gh run watch in a terminal for that
check's workflow. TermClose fires when the run ends, which is exactly when
the log becomes fetchable, so the terminal is replaced by the real log buffer.
- works there too, since #23 made the parent remembered rather than derived.

Cost

ci.Check.run_id comes back, reverting three characters of #24 — the
discriminator regex already captured it.

Polling is one GraphQL request per tick, on the 5000/hr GraphQL budget, and it
is the same query gh pr checks --watch runs. Doing it ourselves rather than
scraping that command's output means it works for bare commits as well as pull
requests, and gives real job ids: in a terminal gh truncates them to the
window width.

No new module. The timer lives beside the load it repeats.

## Checklist - [x] I have read [CONTRIBUTING.md](https://forge.barrettruth.com/barrettruth/ci.nvim/src/branch/main/CONTRIBUTING.md). - [ ] No AI was used to generate, edit, or review any part of this contribution. ## Problem A list went stale the moment it was drawn, and `<CR>` on a running check gave an empty buffer and `no log: job is in_progress`. Measured on `rust-lang/rust` while a job ran: **27 of 35 steps complete and the log endpoint still returned 215 bytes of `BlobNotFound`**, while the same job's page streamed those steps' output in a browser. GitHub publishes live text only over its own socket; the stored log arrives when the job ends. `gh` has tracked this since 2021 — [cli/cli#3484](https://github.com/cli/cli/issues/3484). ## Solution **The list polls itself.** Every ten seconds, while any check is running or pending, it re-runs the reload that `R` already performs — so the view is restored, a failed poll leaves the previous content, and `busy` and the generation guard work unchanged. It stops when the checks settle, when no window shows the buffer, or on wipe. **`<CR>` on a running check opens `gh run watch`** in a terminal for that check's workflow. `TermClose` fires when the run ends, which is exactly when the log becomes fetchable, so the terminal is replaced by the real log buffer. `-` works there too, since #23 made the parent remembered rather than derived. ## Cost `ci.Check.run_id` comes back, reverting three characters of #24 — the discriminator regex already captured it. Polling is one GraphQL request per tick, on the 5000/hr GraphQL budget, and it is the same query `gh pr checks --watch` runs. Doing it ourselves rather than scraping that command's output means it works for bare commits as well as pull requests, and gives real job ids: in a terminal `gh` truncates them to the window width. No new module. The timer lives beside the load it repeats.
feat: keep a list live, and hand a running job to gh run watch
Some checks failed
quality / Test (pull_request) Successful in 3s
quality / Format (pull_request) Successful in 11s
quality / Lint (pull_request) Failing after 13s
d6987c90de
Problem: A list went stale the moment it was drawn, and pressing enter on a
running check gave an empty buffer, because a job's log does not exist until
the job ends and GitHub streams live output only to its own web interface.

Solution: A list reloads itself every ten seconds until its checks settle,
reusing the path R already takes, and a running check opens gh run watch in a
terminal that is replaced by the real log when the run finishes.
fix: restore run_id on the job type as well
All checks were successful
quality / Test (pull_request) Successful in 3s
quality / Lint (pull_request) Successful in 11s
quality / Format (pull_request) Successful in 13s
5d8a63c174
docs: make known limitations a list
All checks were successful
quality / Test (pull_request) Successful in 7s
quality / Lint (pull_request) Successful in 12s
quality / Format (pull_request) Successful in 13s
d1e0d0b569
docs: terse bullets in the README, prose in the help
All checks were successful
quality / Format (pull_request) Successful in 6s
quality / Lint (pull_request) Successful in 6s
quality / Test (pull_request) Successful in 7s
9b8a1265ee
refactor: drop the terminal handoff
All checks were successful
quality / Test (pull_request) Successful in 4s
quality / Format (pull_request) Successful in 11s
quality / Lint (pull_request) Successful in 12s
51d8bbe446
Problem: A TermClose autocmd swapped the watch terminal for the log when the
run ended, which meant a buffer variable on a foreign buffer type, a window
hunt to avoid stealing whichever split you had moved to, and behaviour nobody
asked for.

Solution: The list already refreshes itself, so a finished check is green
there and "-" then enter opens its log. Two keys instead of an autocmd.
docs: reword the limitations note
All checks were successful
quality / Test (pull_request) Successful in 7s
quality / Format (pull_request) Successful in 11s
quality / Lint (pull_request) Successful in 12s
9f65adff13
barrettruth deleted branch feat/live-checks 2026-07-28 05:43:44 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
barrettruth/ci.nvim!34
No description provided.