mesirendon

Mesi Rendon

about

articles

tags

publications

wandering

nvim-ghrelease

Creating GitHub releases inside Neovim with the gh CLI

  ·   5 min read

My daily workflow usually is all about getting a PR approved, merged into the main branch and, depending on the urgency, wait and release a production version. So, when I’m done with the PR, I quit my Neovim session and, through the gh CLI, create the release.

After looking for an already available plugin that does that, and not finding it, I decided to create a simple one that I could use to keep working from Neovim.

The project is available at https://github.com/mesirendon/nvim-ghrelease.

Features

  • Lists current releases for context before you start.
  • Suggests the next version with a semver bump menu (major / minor / patch / prerelease / custom).
  • Buffer-per-step editing: :wq saves the answer and advances.
  • Release-notes sources mirroring gh: write your own, GitHub-generated template, commit-log template, or leave blank.
  • Final Publish / Save as draft / Cancel step, plus a prerelease question.
  • Fully async (vim.system), no blocking of the editor.

Requirements

  • Neovim 0.10+ (needs vim.system; the plugin refuses to load and warns on older versions). Tested in CI on 0.10, 0.11, stable, and nightly.
  • The GitHub CLI gh, installed and authenticated: gh auth login
  • Run the command from within a GitHub repository

A typical workflow

Open Neovim in any repo you want to create the release. Invoke the dialog by typing the keys Space g r. That will open the dialog that shows the current releases and allows you to select the base release.

Select base release
Select base release

Once you select the base release a new dialog opens asking you to select the next version by using a semver bump.

Semver bump
Semver bump

For this example I’m choosing just a patch release. I won’t change any description for the tag, so I press : q to continue to the next step.

Tag name
Tag name

Then, I need to choose a release title. I won’t change this either. So I press again : q.

Release title
Release title

The next step is to write the release notes. I usually go with the option 2, letting GitHub generated release notes because I usually merge my code out of PRs, so the release notes is left with the descriptions in a bullet list for each one of the changes I’m including in the release. But for the sake of this simple example, I’ll choose the first option to include my own notes.

Release notes
Release notes

Then, I simply write and save by pressing : w q.

Release notes editor
Release notes editor

The next question is to tell if this is a prerelease. We choose No.

Prerelease selection
Prerelease selection

Then we submit the release by choosing Publish release, or Save as draft, or the unlikely Cancel.

Submit the release
Submit the release

When done, the plugin launches two notifications. The first one shows the release creation.

Release creation notification
Release creation notification

If all goes well the second notification confirms the release creation.

Release creation confirmation
Release creation confirmation

And we can check this in the project’s release screen.

GitHub Project’s Releases
GitHub Project’s Releases

Further work

I created this plugin due to the need of creating a new release without closing Neovim to do so. But, I think I will make improvements. So far, I’m planning to work on the following ones for starters:

  • GH Release creation stabilization
    • Tag collision + existence check. Right now if tag already exists, gh fails at step 10 after the user has typed notes. Add a gh release view <tag> / git rev-parse <tag> probe right after step 4 and offer overwrite via edit / pick another / cancel."
    • --verify-tag. When the tag already exists locally, pass it so gh refuses to create a release against a tag that doesn’t exist on the remote.
  • Flags that round out create:
    • Asset upload. gh release create <tag> file1 file2#Label. Add an optional step taking globs (dist/*), resolved with vim.fn.glob, with a confirm listing resolved paths. I think this is going to be the single most-requested thing missing from a release helper.
    • --generate-notes properly. Currently, the plugin POSTs to repos/{}/releases/generate-notes to seed the buffer, which is good UX. But add a fifth notes source: “Let GitHub generate at publish time” when passing, --generate-notes and skip the buffer entirely.
  • New commands, new entry points
    • :GhReleaseEdit [tag] as gh release edit. Same buffer machinery, seeded from gh release view <tag> --json body,name,isDraft,isPrerelease. This is where draft-publishing lives: edit a draft yields --draft=false. Probably the highest-value new command since drafts are a dead end today.
    • :GhReleaseList as a picker over gh release list --json that dispatches to view/edit/delete/download, instead of the current read-only text dump. Makes M.list earn its keep.
    • :GhReleaseDelete [tag] as gh release delete --yes, plus a confirm on --cleanup-tag.
    • :GhReleaseView [tag] as render gh release view into a markdown scratch buffer.
    • :GhReleaseDownload as gh release download, with a pattern prompt and a dir prompt.
  • Polish
    • Repo override. Every gh call should thread an optional --repo owner/name from config, so the plugin works outside a checkout.
    • Structured errors. gh writes actionable messages to stderr; it currently trims and dumps. Special-case the common ones (tag exists, protected branch, missing repo scope) into a hint.
    • Config for defaults. default_target, assets glob list, generate_notes = true, so teams can codify a release convention and skip steps.