Skip to content

Releases mode: browse, create, edit, delete GitHub releases from ghui#1

Merged
MrgSub merged 7 commits intomainfrom
releases-mode
May 5, 2026
Merged

Releases mode: browse, create, edit, delete GitHub releases from ghui#1
MrgSub merged 7 commits intomainfrom
releases-mode

Conversation

@MrgSub
Copy link
Copy Markdown
Owner

@MrgSub MrgSub commented May 5, 2026

Implements plans/create-releases.md — a Releases overlay reachable from the command palette that gives 1:1 parity with github.com's "Create a new release" page for the active repository, plus a list/details browser for existing releases.

What you can do

  • Browse — Open the command palette → Releases… → list with draft / pre-release / latest badges, paginated, refresh, load-more, open in browser, copy URL.
  • Viewenter on a release → full body wrapped to width, asset list, scrollable.
  • Cut a new releaseNew release… in the palette or n on the overlay → form with tag, target (lazy default-branch fetch), title, multi-line body, pre-release toggle, latest tri-state. ctrl-g generates notes (only fills empty title/body), ctrl-s saves draft, ctrl-↵ publishes. The tag field is prefilled with the previous tag so bumping a version is one backspace + edit.
  • Edite on a selected release → same form, prefilled.
  • Deleteshift-d → confirmation modal that calls out tag preservation; optimistic removal on success.

Shape of the change

  • Domain & service layer — new Release / ReleaseSummary / Tag / Branch / DiscussionCategory / MakeLatest types, plus 12 typed GitHubService methods (listReleases, getRelease, getLatestRelease, listTags, listBranches, getDefaultBranch, generateReleaseNotes, listDiscussionCategories, createRelease, updateRelease, deleteRelease) backed by gh api and gh api graphql. Mock layer mirrors all of them.
  • UI — three new components (ReleasesModal, ReleaseForm, DeleteReleaseModal) and three new keymap layers wired through appKeymap. Discriminated Modal enum extended with Releases / ReleaseForm / DeleteRelease.
  • App.tsx — new atoms, action handlers, ctx wiring, render. Releases-modal-active flags participate in textInputActive so quit-on-q is suppressed while editing the form.
  • Docs — README "Releases" section with the full keybinding reference; README's elevator pitch updated.
  • Tests — 8 new unit tests for the service methods covering REST endpoint shape, payload encoding, and gh api flag plumbing.

Decisions baked in (from the plan)

  • Command-palette only in v1 (no top-level keybind yet).
  • Single-repo release list (no cross-repo feed).
  • Default target branch is fetched lazily.
  • Generate-notes mirrors github.com — only fills empty fields.
  • Asset upload deferred to v2 (form notes you can do it from the web).

Deferred to follow-ups (documented in the plan)

Tag autocomplete dropdown, target branch picker, previous-tag picker, discussion category UI (service method already wired), persistent SQLite cache, asset upload, markdown preview pane.

Commits

Phase Commit LOC What landed
1 — service layer 02df24f +782 Domain types, 12 GitHubService methods + mock, 8 unit tests
2 — list + details 9e52db8 +682 Releases overlay, command-palette entry, async loaders
3 — create/edit form 99a091e +765 Form, generate-notes, draft, publish, edit-mode
— bugfix 4905b78 -2 Do not gate release commands on a selected repo (palette hides disabled commands)
— bugfix 35e33a6 +36/-18 Avoid nesting TokenLine inside TextLine (opentui rejects nested <text>)
4 — delete + docs 83d02b5 +270 shift-d delete-with-confirm, README section
— refinement e94b06f +34 Prefill new-release tag with the previous tag

Checks

bun run format:check, bun run typecheck, bun run lint, bun run test (324 pass) all green on every commit.

Changesets queued: 5 (4× minor, 1× patch). Ready for bun run changeset:version.

MrgSub added 7 commits May 5, 2026 14:26
Phase 1 of plans/create-releases.md. Adds Release/ReleaseSummary/Tag/Branch/
DiscussionCategory/MakeLatest types, plus listReleases, getRelease,
getLatestRelease, listTags, listBranches, getDefaultBranch,
generateReleaseNotes, listDiscussionCategories, createRelease, updateRelease,
deleteRelease on GitHubService and the mock layer. No UI yet.
Phase 2 of plans/create-releases.md. Adds a 'Releases…' command that opens
a full-screen modal showing the active repository's releases (tag, name,
draft/pre-release/latest badges, published date, author) with pagination,
plus an inline details view with the release body and assets. Supports
'o' (open in browser), 'y' (copy URL), 'r' (refresh), ']' (load more).
Read-only; create/edit/delete come in phase 3.

Persistent caching deferred from the plan — releases refetch on each open
and live in the modal state. Will revisit when the form lands and we need
to bust caches on local mutations.
Phase 3 of plans/create-releases.md. Adds a 'New release…' command and an
'e'/'n' keybind on the releases overlay that open a form modal mirroring
github.com's create-release page. Fields: tag, target (defaults to the
repo's default branch, fetched lazily), title, multi-line description
(reusing the comment editor), pre-release checkbox, make_latest tri-state.

Submission:
- ctrl-g generates release notes (only fills empty title/body, matching web)
- ctrl-s saves as draft
- ctrl-↵ (or shift-↵ outside the body) publishes
- esc cancels back to the releases overlay (or closes if opened directly)

The same form handles edits when invoked from the releases list — body is
hydrated from the full release fetch so the tag/title/etc. are usable
immediately while the body loads in.

Tag autocomplete dropdown, target picker, previous-tag picker, and
discussion category support are still deferred to phase 4 along with the
delete-with-confirm flow.
The command palette filters out disabled commands entirely
(commandEnabled check in App.tsx), so gating release.list / release.new
on selectedRepository made them vanish instead of showing as greyed.
Drop the disabledReason — the action handlers already flashNotice
'Open a repository first.' when invoked without a repo.
opentui's <text> rejects nested <text> children with 'TextNodeRenderable
only accepts strings, TextNodeRenderable instances, or StyledText
instances'. ReleaseForm's MakeLatestRow and ReleasesModal's release-
details badges row both wrapped a TokenLine inside a TextLine, which is a
<text> in <text>. Inline the spans directly instead.
Phase 4 (final) of plans/create-releases.md. Adds a 'shift-d' keybind on
the releases overlay (and details panel) that opens a confirmation modal
for deleting a release; deletion is optimistic on the in-memory list
state and bounces back to the releases overlay. Documents the full
Releases workflow in the README.

The plan is closed out with explicit follow-ups for the remaining
nice-to-haves (tag autocomplete dropdown, discussion categories, target
branch picker, persistent cache, asset upload). The v1 loop — browse,
create, edit, publish/draft, delete — is complete.
Opening 'New release' now seeds the tag field with the repo's latest
release tag and shows 'previous: vX.Y.Z' in the form subtitle. Bumping
versions is a backspace + edit instead of remembering the last tag.

If the releases overlay is already open we reuse its cached latest tag
so the prefill is instant; otherwise we kick off getLatestRelease in
the background and fill the field if the user hasn't typed yet (mirrors
the 'only fill empty fields' rule we already use for generate-notes).
@MrgSub MrgSub merged commit 6aaabd9 into main May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant