feat(glab): add GitLab CLI (glab) command support#314
feat(glab): add GitLab CLI (glab) command support#314tnucera wants to merge 1 commit intortk-ai:developfrom
Conversation
861d24d to
fab7a76
Compare
Manual smoke test resultsTested against a live GitLab instance with multiple projects. Without
|
| Command | Result | Notes |
|---|---|---|
rtk glab mr list |
✅ | Compact table with state icons |
rtk glab mr view <N> |
✅ | JSON extraction + markdown filtering |
rtk glab mr diff <N> |
✅ | Diff compaction via git::compact_diff |
rtk glab ci status |
✅ | Current branch pipeline status |
rtk glab ci list |
✅ | 10 pipelines with status icons |
rtk glab ci view |
✅ | Passthrough (interactive TUI, cannot capture) |
rtk glab pipeline list |
✅ | Alias for ci list, works correctly |
rtk glab issue list |
✅ | Graceful fallback when no issues (plain text) |
rtk glab api /projects/<id> |
✅ | JSON schema filtering |
rtk glab repo view |
✅ | Passthrough for unknown subcommands |
With -R owner/repo (cross-project)
| Command | Result | Notes |
|---|---|---|
rtk glab -R owner/repo mr list |
✅ | Correct project targeting |
rtk glab -R owner/repo mr view <N> |
✅ | Correct MR from target project |
rtk glab -R owner/repo mr diff <N> |
✅ | Diff from target project |
rtk glab -R owner/repo ci list |
✅ | Pipelines from target project |
rtk glab -R owner/repo ci status |
✅ | Correct error when no pipeline on branch |
rtk glab -R owner/repo issue list |
✅ | Issues from target project |
rtk glab -R owner/repo issue view <N> |
✅ | Full issue details from target project |
With -g group (cross-group)
| Command | Result | Notes |
|---|---|---|
rtk glab -g group mr list |
✅ | MRs from all projects in group (20+, cap applied) |
rtk glab -g group issue list |
✅ | Issues from all projects in group (plain text fallback) |
Action commands (tested on a dedicated test project)
| Command | Result | Notes |
|---|---|---|
rtk glab mr create --source-branch ... --title ... |
✅ | ok created !2 <url> — MR created (verified with mr view) |
rtk glab mr note <N> -m "..." |
✅ | ok noted !1 — comment added |
rtk glab mr update <N> --title "..." |
✅ | ok updated !1 — title changed (verified with mr view) |
rtk glab mr approve <N> |
✅ | 401 self-approve restriction propagated correctly (GitLab limitation) |
rtk glab mr merge <N> --yes |
✅ | ok merged !1 — MR merged (verified with mr view → state: merged) |
Edge cases — empty project (0 MRs, 0 issues, 0 pipelines)
| Command | Result | Notes |
|---|---|---|
rtk glab -R owner/repo mr list |
✅ | Header only, no crash |
rtk glab -R owner/repo issue list |
✅ | Graceful plain text fallback |
rtk glab -R owner/repo ci list |
✅ | Header only, no crash |
rtk glab -R owner/repo mr view 1 |
✅ | glab 404 error propagated, exit code 1 |
Hook rewrite tests (rtk-rewrite.sh)
| Input command | Rewritten to | Result |
|---|---|---|
glab mr list |
rtk glab mr list |
✅ |
glab ci status |
rtk glab ci status |
✅ |
glab issue view 42 |
rtk glab issue view 42 |
✅ |
glab pipeline list |
rtk glab pipeline list |
✅ |
glab api /projects |
rtk glab api /projects |
✅ |
glab auth login |
(not rewritten) | ✅ |
glab repo clone foo |
(not rewritten) | ✅ |
Token savings observed
| Command | Savings |
|---|---|
glab mr list |
49-99% (varies with result count) |
glab mr view |
77-94% |
glab mr diff |
36-98% (varies with diff size) |
glab ci list |
76-95% |
glab api |
~86% |
Bugs found and fixed during testing
- Non-JSON fallback: glab returns plain text (not JSON) when there are no results (e.g. empty issue list). Added graceful fallback in all JSON-parsing handlers.
-Rflag not parsed by clap:-R/--repoand-g/--groupwere not declared in theCommands::Glabclap definition, causing the command to fall through torun_fallback. Fixed by adding them as explicit#[arg]fields (same pattern asgit -C).mr_view/issue_viewnot forwarding extra args: Functions that extract a number fromargs[0]were not passing remaining args (including-R) to glab. Added the missingfor arg in &args[1..]loop.ci viewTUI crash:glab ci viewlaunches an interactive TUI (tcell/tview) that panics when stdout is captured. Moved to passthrough (inherited stdio).mr_actionwrong subcommand:mr noteandmr updatepassed the confirmation label ("noted","updated") as the glab subcommand instead of the actual command ("note","update"). Split into separatesubcmdandlabelparameters.
eb8302d to
74194ba
Compare
|
Hi @tnucera, good structural work. Hook rule, registry entry, and CHANGELOG are all present, making this the most complete of the CLI integration PRs on that front. Two things to address:
Missing tee integration is also worth noting, though it's not a blocker for a first merge. |
|
Note: this PR adds rules to Please remove the changes to |
74194ba to
7fe56d5
Compare
Review feedback addressedRebased on @FlorianBruniaux
@pszymkowiak
Quality gatesLive smoke tests (private GitLab instance)
|
0153790 to
a4dfe04
Compare
|
Polish pass on Two fixes to align with
Net: -33 lines, 739 tests passing. |
c8c8aad to
64bc295
Compare
|
Hey! Quick update on this PR:
All quality gates pass locally: cargo fmt clean, cargo clippy 0 new warnings, cargo test 986 passed. Tested manually against a live GitLab instance. @FlorianBruniaux @pszymkowiak Is there anything else needed to get this merged? Happy to address any feedback. |
|
We need it ! Thank you @tnucera |
|
Hi! Two things needed before we can review:
Thanks! |
|
Hey We are cleaning up the codebase and improving the project structure for better onboarding. As part of this effort, PR #826 reorganizes No logic changes — only file moves and import path updates. What you need to doRebase your branch on git fetch origin && git rebase origin/developGit detects renames automatically. If you get import conflicts, update the paths: use crate::git; // now: use crate::cmds::git::git;
use crate::tracking; // now: use crate::core::tracking;
use crate::config; // now: use crate::core::config;
use crate::init; // now: use crate::hooks::init;
use crate::gain; // now: use crate::analytics::gain;Need help rebasing? Tag @aeppling |
64bc295 to
f4d9867
Compare
|
Rebased on
Quality gates: |
d2e028f to
ff9bf9d
Compare
da25fde to
80e950b
Compare
80e950b to
a3aa5a8
Compare
|
Hi @pszymkowiak, @FlorianBruniaux, @aeppling 👋 Just rebased this PR on latest Current status:
What's missing to get this merged? 🙏 |
Add token-optimized filters for glab CLI commands: - mr list/view/create/merge/approve/diff/note/update - issue list/view - ci list/status/trace (strip ANSI, section markers, runner boilerplate) - release list/view (strip SOURCES block, markdown noise) - api passthrough - Markdown body filtering (HTML comments, badges, blank lines) - Graceful JSON/plain-text fallback for empty results - -R/--repo and -g/--group flag forwarding at clap level - resolved_command() for Windows compat - has_output_flag() / should_passthrough_view() guards - Rewrite rules and classify/rewrite tests for rtk discover Adapted to post-refactoring src/cmds/git/ module structure. Token savings: mr 87%, ci 82%, issue 80% (avg 82%) Closes rtk-ai#851
a3aa5a8 to
4ea78b0
Compare
|
Quick follow-up to tighten things before review:
|
|
Hey @tnucera , thanks for following our guidelines and codebase architecture updates. Here is a review on filter quality, to ensure no important signal lost by aggressive filtering. Could you please verify those to ensure we do not integrate invalid filter ? Filters qualitymr_view drops source/target branch infoThe format_mr_view output has: state, title, author, merge_status, pipeline, URL, description. But it omits source_branch/target_branch. An LLM working on a merge workflow needs to know which branch is being merged into which. The gh_cmd.rs format_pr_view similarly doesn't show branches, but GitHub's PR model makes this less critical (the URL encodes it). For GitLab MRs, the branch info is often the most actionable signal. mr_view drops labels and reviewersLabels (e.g., bug, enhancement, blocked) and reviewer assignments are decision-relevant for an LLM asked to review/merge/triage MRs. The format_mr_list also drops labels — less critical there since it's a summary, but mr view is the detailed view. Suggestionspipeline_icon uses emoji for non-ultra-compact mode"✅" and "❌" are multi-byte characters. The gh_cmd.rs may uses text tags [pass]/[fail] for non-compact mode. Tech docs may be interesting for others contributorsThis is a new integration and some technical documentation in the cmds/git/README.md could be interesting for futur contributors. ThanksFor contributing to RKT and adding more coverage ! Others maintainers already reviewed, awaiting for their approvals since i've only reviewed on the surface :) |
Summary
Adds token-optimized output for
glab(GitLab CLI) commands, mirroringgh_cmd.rspatterns adapted for GitLab-specific differences. Integrated into the post-#826 module structure (src/cmds/git/).Subcommands:
mr(list/view/create/merge/approve/diff/note/update),issue(list/view),ci(list/status/trace),release(list/view),api(passthrough). Unhandled subcommands forwarded to nativeglab.glab vs gh adaptations
#42!42OPEN/MERGED/CLOSEDopened/merged/closedauthor.loginauthor.usernameurlweb_urlbodydescriptionmergeablemerge_statusstatusCheckRolluphead_pipeline.statusToken savings
glab mr listglab mr viewglab issue listglab issue viewglab ci listglab ci statusglab ci traceglab release listglab release viewglab api,glab *Savings tested empirically (Apr 2026 smoke tests). Unit tests assert a floor of ≥60% on JSON filters and ≥20-30% on text filters.
Key design choices
runner::run_filtered+RunOptions(mirrorsgh_cmd.rs) via a localrun_glab_json<F>()helper — unified exit-code propagation, tracking, and JSON-fallback-to-rawresolved_command("glab")everywhere (Windows.cmdwrapper compat, mirrorsgh_cmd.rs)has_output_flag()guard at top ofrun()— passthrough when user passes-F/--output/--jsonshould_passthrough_view()for--web,--commentson mr/issue viewmr_action()for merge/approve/note/update withextract_identifier_and_extra_args(handlesglab mr note -m "msg" 42)-R/--repoand-g/--groupdeclared at clap level, appended to args (not prepended — avoids breaking subcommand dispatch)ci status: text-based parsing (glab doesn't support-F jsonfor this subcommand), with raw fallback for unrecognized outputci trace: strip ANSI codes, GitLab CI section markers, runner/git/artifact boilerplate; preserve build output and errorsrelease view: strip SOURCES archive URLs, image lines, HTML comments, horizontal rules; collapse blank linesglab api: passthrough by design — API responses vary and filtering would destroy values[open]/[merged]/[closed]), functional icons only, aligned with fix: remove decorative emojis from CLI output (#511) #558glab_cmd.rs(shared-module refactor deferred to a separate PR)Files changed
src/cmds/git/glab_cmd.rs(new) — all handlers + 54 unit tests (auto-discovered viaautomod::dir!)src/main.rs—Commands::Glabvariant with-R/-gflags, routing,is_operational_commandsrc/discover/rules.rs— glab rewrite pattern +RtkRulesrc/discover/registry.rs—"GitLab" => 200incategory_avg_tokens+ 5 classification/rewrite teststests/fixtures/—glab_mr_list_raw.json,glab_issue_list_raw.json,glab_release_list_raw.txt,glab_release_view_raw.txt,glab_ci_trace_raw.txtCloses #851, closes #1085. Partially addresses #122.
Test plan
cargo fmt --all --check— cleancargo clippy --all-targets— 0 new warningscargo test --all— 1665 passed, 6 ignored-Rcross-project targeting)-F jsonpassthrough guard, empty results fallback, 404 error propagation