feat(cli): show apply provenance as a clickable source in status output - #1086
Conversation
The status list's CALLER column becomes SOURCE: webhook-driven applies show the full clickable PR URL, and CLI-driven applies keep their short caller such as cli:jdoe. The status detail box separates the two — a short Caller row (who drove it) plus a clickable Source row (the PR it came from) — instead of one raw caller string with an unclickable repo#pr tail. The database history table gets the same SOURCE treatment. pkg/caller gains PullRequest(), extracting the repo and PR number from a webhook-shaped caller, and the progress parser now carries the server's pull_request URL through to the detail box, preferring it over the caller-derived one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR improves the CLI’s “apply provenance” UX by rendering webhook-driven applies with a clickable PR URL (and separating “who” from “where” in the detail box), derived client-side from existing caller/progress data.
Changes:
- Add parsing for webhook-shaped caller strings via
pkg/caller.PullRequest()and use it to render a clickable PR URL on CLI status surfaces. - Update status list/history columns from
CALLER→SOURCE, and split the detail box intoCaller+Sourcerows when PR provenance exists. - Update preview/template outputs and add focused unit tests for the new attribution rendering helpers.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| TEMPLATES.md | Updates documented CLI output to reflect the new SOURCE column and Caller/Source rows. |
| pkg/cmd/internal/templates/progress.go | Renames list column header to SOURCE and renders provenance via applySource() / callerAndSourceBoxRows(). |
| pkg/cmd/internal/templates/progress_parse.go | Plumbs server-provided pull_request URL into ProgressData. |
| pkg/cmd/internal/templates/progress_multi.go | Uses the shared Caller/Source row rendering for multi-deployment boxes. |
| pkg/cmd/internal/templates/preview_status.go | Updates preview status-list callers to the structured forms used for source rendering. |
| pkg/cmd/internal/templates/preview_progress_multi.go | Updates preview multi-deployment progress data to use the structured GitHub caller form. |
| pkg/cmd/internal/templates/applysource.go | Introduces helper functions to render SOURCE and split Caller/Source in detail boxes. |
| pkg/cmd/internal/templates/applysource_test.go | Adds unit coverage for SOURCE rendering and detail box row behavior. |
| pkg/caller/caller.go | Adds GitHubPrefix and new PullRequest() extractor for webhook-shaped callers. |
| pkg/caller/caller_test.go | Adds tests covering PullRequest() parsing (including email-shaped users). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…rmed repos The server substitutes a bare "<owner>/<repo>#<pr>" caller when an apply carries PR provenance but no recorded caller, so PullRequest now accepts that form too instead of leaving it non-clickable. The repository must be exactly owner/name — one slash with non-empty segments — so a malformed location never yields a bogus PR link. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🤖 Review findings - created by Kiran's code review agent - for schemabot/pull/1086, 328a351. Verdict: 8 findings — 1 blocking (the detail box now drops a CLI caller's host, contradicting its own doc comment), 5 non-blocking, 2 suggestions. Blocking1. A CLI-driven apply that also carries repo/PR metadata loses its originating host from the detail box. The Caller row is short-formed whenever any source URL exists (applysource.go:30), including the server-provided one — so Non-blocking2. The one line that delivers the PR's headline behavior has no test. Deleting 3. The bare-form rejection guard survives deletion, and the test named for it exercises a different case. Removing 4. The CALLER→SOURCE sweep missed 5. The list and the detail box can render different PR URLs for the same apply. 6. General suggestions7. 8. Two presentation gaps. The history and per-deployment preview fixtures were never given PR-shaped callers, so the regenerated TEMPLATES.md documents The one thing that could have broken, verifiedThe obvious risk was the hardcoded Verified correct
This review was generated by Claude Code (claude-opus-5). |
The detail box now splits Caller/Source only when the caller's own trailing location is the repo#pr; any other caller keeps its full attribution even when the server supplies a PR URL, and a server-substituted bare repo#pr renders only the Source row. PR locations are validated segment-by-segment (repository-shaped characters, plain positive decimal PR number) so a malformed caller never yields a bogus link, failure listings render the clickable source, and status previews use wire-format callers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🤖 Thanks for the thorough review — all fixable findings are addressed in f221e1f. 1 (blocking): Fixed. The detail box now keys the Caller short-form on whether the caller's own trailing location is a repo#pr ( 2: Fixed — the 3: Fixed — the guard test now passes 4: Fixed — 5: Acknowledged, leaving as-is for now. The list endpoints ( 6: Fixed — repo segments are validated against a GitHub-safe character class ( 7: Fixed — PR numbers must be plain positive decimals: 8: Fixtures fixed — history and per-deployment previews now use wire-format callers, and the regenerated TEMPLATES.md shows the widest deployment SOURCE row. OSC 8 hyperlink emission is deferred: it's a CLI-wide presentation decision (every URL we print, plus terminal-capability detection), better taken as its own change than folded in here. This reply was generated by Claude Code (Fable 5). |
…ew-drift-rollup * origin/main: (357 commits) fix(github): render each lint violation as its own bullet in unsafe-change comments (#1105) feat(engine): disclose at plan time whether an apply continues or discards a copy (#1087) fix(operator): choose the drive mode from the generation manifest, not the attached row count (#1101) feat(tern): one deployment correlates to exactly one remote apply (#1060) fix(github): record the passing check when an apply plan finds no changes (#1099) feat(spirit): detect an unfinished row copy and log what the apply will do to it (#1048) docs: reserve metrics for signals worth alerting on (#1089) feat(cli): browse stored plan history with the list-plans command (#1083) feat(cli): render status sources as OSC 8 hyperlinks on interactive terminals (#1097) feat(github): show VSchema changes in sharded apply comments (#1096) test(webhook): PostgreSQL failure-matrix row — declined stop is terminal, apply completes (#1098) feat(observability): log the delivery GUID when a goroutine panics (#1092) test(webhook): pin apply-confirm lock-path dispositions (#1091) fix(api): type terminal rollback validation errors (#1090) build(deps): pin pg-sprite to released v0.1.0 (#1093) feat(cli): show apply provenance as a clickable source in status output (#1086) fix(github): give sharded applies a real terminal summary comment (#1085) fix(vitess): gate stored-plan applies on recorded VSchema deletions and mutations (#1084) webhook: PostgreSQL failure-matrix rows — restart survival and permanent privilege refusal (#1079) fix(tern): complete a deployment-keyed apply only when its generation manifest is satisfied (#1076) ... # Conflicts: # pkg/webhook/plan.go # pkg/webhook/templates/plan.go
Summary
An apply's caller string already records where it came from — the webhook path stores
github:<user>@<owner>/<repo>#<pr>— but the CLI rendered it raw, so the PR behind an apply was visible yet not clickable. This makes apply provenance a first-class, clickable field across the status surfaces, derived entirely client-side with no API change.cli:jdoe, so their origin still reads at a glance. The database history table gets the same treatment.Callerrow (github:octocat) plus a clickableSourcerow (the PR URL), replacing the single raw caller with its unclickablerepo#prtail. An apply without PR provenance keeps one rawCallerrow, trailing location included.pkg/callergainsPullRequest(), extracting the repository and PR number from a webhook-shaped caller. It splits at the last@likeShort, so email-shaped users parse correctly. The progress parser also carries the server'spull_requestURL through to the detail box and prefers it over the caller-derived one.CLI examples
Status list with the SOURCE column:
Status detail box with Caller and Source separated:
🤖 Generated with Claude Code