feat(ui): Releases box [5] #113

Merged
deadstyle merged 12 commits from feature/103-releases-box into develop 2026-10-09 17:30:35 -05:00
Owner

Summary

Adds box [5] Releases. It lists the repo's releases, newest first, and selecting one shows its notes in the Overview. Read-only; o opens the release in the browser.

Changes

  • Core sorts releases newest first. A ListReleases not-found error (for example, releases disabled on the repo) shows an empty box with — none — instead of a status error. Other errors go to the status line.
  • Gitea/Forgejo and GitHub adapters date an unpublished (draft) release by its creation time, so it sorts and shows an age.
  • New Releases box in the UI: rows with tag, name and age, draft and pre-release markers, and an Overview with the notes rendered as markdown. Tag and name are stripped of control characters like the Files tab.
  • Existing box numbering, tab order and tests updated for the new box; docs/design.md and docs/mockup.html updated.

Decisions

  • Decided: no new forge.Act*, since ListReleases is already on the core Forge interface; the box is always visible.
  • Decided: a draft and a published release with the same tag share an item id; accepted.
  • Assumed: draft and pre-release markers on rows, No release notes for blank notes, and tags without a release are not listed.
  • Assumed: a release with no publish date omits its age.

Test plan

  • go build, go vet, go test -race ./..., golangci-lint (0 issues) and the format check pass (builder run).
  • Tests were mutation-checked; hollow ones rewritten.
  • Adapter calls are verified against fixtures only, not a live server.

Refs #103

🤖 Generated with Claude Code

https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n

## Summary Adds box `[5]` Releases. It lists the repo's releases, newest first, and selecting one shows its notes in the Overview. Read-only; `o` opens the release in the browser. ## Changes - Core sorts releases newest first. A `ListReleases` not-found error (for example, releases disabled on the repo) shows an empty box with `— none —` instead of a status error. Other errors go to the status line. - Gitea/Forgejo and GitHub adapters date an unpublished (draft) release by its creation time, so it sorts and shows an age. - New Releases box in the UI: rows with tag, name and age, `draft` and `pre-release` markers, and an Overview with the notes rendered as markdown. Tag and name are stripped of control characters like the Files tab. - Existing box numbering, tab order and tests updated for the new box; `docs/design.md` and `docs/mockup.html` updated. ## Decisions - Decided: no new `forge.Act*`, since `ListReleases` is already on the core `Forge` interface; the box is always visible. - Decided: a draft and a published release with the same tag share an item id; accepted. - Assumed: `draft` and `pre-release` markers on rows, `No release notes` for blank notes, and tags without a release are not listed. - Assumed: a release with no publish date omits its age. ## Test plan - `go build`, `go vet`, `go test -race ./...`, `golangci-lint` (0 issues) and the format check pass (builder run). - Tests were mutation-checked; hollow ones rewritten. - Adapter calls are verified against fixtures only, not a live server. Refs #103 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
Fetch always calls the forge and stores the result, so a second Releases call hits the forge again; the plan only pins that the empty answer is cached. The test now checks PeekReleases for an ok empty entry.

Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
The tag count also matched the row and the breadcrumb, so dropping the heading fallback still passed. Assert the overview's first line instead.

Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
The overview always shows the selected release, so its sanitised heading and tag satisfied the row assertions. Put the control-character release second so only the list row carries it, and select it before checking the heading.

Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
The sanitised heading compares visible text, which a renderer can make identical with or without the replacement. Assert on the raw view bytes as well.

Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
test(ui): give both release notes overflow so a stale scroll is caught
All checks were successful
ci / check (pull_request) Successful in 1m50s
1a89576171
With rc-one's notes shorter than the pane, a scroll left over from rc-two was clamped away and the test passed. Give rc-one long, distinct notes so its first line must be the one shown.

Refs #103

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RTN2GnGvYhWwPhsSDiWp8n
deadstyle merged commit a6784adffa into develop 2026-10-09 17:30:35 -05:00
deadstyle deleted branch feature/103-releases-box 2026-10-09 17:30:35 -05:00
Sign in to join this conversation.
No description provided.