Skip to content

Fix glab fetch failures from non-repo cwd and nested-group slug truncation#233

Merged
dhilgaertner merged 1 commit intomainfrom
feature/crow-232-glab-not-git-repo
May 1, 2026
Merged

Fix glab fetch failures from non-repo cwd and nested-group slug truncation#233
dhilgaertner merged 1 commit intomainfrom
feature/crow-232-glab-not-git-repo

Conversation

@dhilgaertner
Copy link
Copy Markdown
Contributor

Summary

  • fetchGitLabIssues was running glab issue list -a @me --output-format json with cwd: NSHomeDirectory(). glab issue list shells out to git even when no repo is involved and aborts with "fatal: not a git repository" when the cwd is not a git working tree. Swap to glab api "issues?scope=assigned_to_me&state=opened&per_page=100" — same JSON fields the existing parser already reads (iid, title, web_url, state, labels, references.full), no git-repo dependency. Same pattern Crow already uses in fetchGitLabMRsForReconcile.
  • resolveRepoInfo truncated nested-group GitLab slugs because its regex [:/]([^/:]+/[^/:]+)$ only captured the last two path segments. big-bang/product/packages/elasticsearch-kibana collapsed to packages/elasticsearch-kibana, then the reconcile path hit a 404 against a non-existent project. Replaced with a new IssueTracker.extractSlug(fromRemote:) helper (parallel to extractHost) that returns the full path after the host for both SSH and HTTPS remotes and strips a trailing .git.
  • Added a IssueTrackerRemoteSlugTests Swift Testing suite mirroring the existing IssueTrackerRemoteHostTests: GitHub SSH/HTTPS, two-level GitLab, nested-group GitLab (HTTPS and SSH — the regression for IssueTracker: glab calls fail with 'not a git repository' and malformed nested-group slugs #232), .git stripping, and unrecognized inputs.

Closes #232

Test plan

  • swift test — all 38 tests in 5 suites pass, including the new IssueTracker remote slug extraction suite (7 tests).
  • Manual: with no GitLab repo cloned at ~, confirm Crow's GitLab issue tracker now returns assigned issues instead of an empty list.
  • Manual: register a worktree whose origin points at a nested GitLab group (e.g. big-bang/product/packages/elasticsearch-kibana) and confirm the merged-MR reconcile flow finds the project (no 404).

🤖 Generated with Claude Code

…ation

`fetchGitLabIssues` shelled out to `glab issue list -a @me --output-format
json` with `cwd: NSHomeDirectory()`. `glab issue list` invokes `git`
internally and aborts with "fatal: not a git repository" whenever the home
directory is not a git working tree, so users got zero GitLab issues even
though `glab` was authenticated. Switch to `glab api
"issues?scope=assigned_to_me&state=opened&per_page=100"`, which has no
git-repo dependency and returns the same JSON shape (iid, title, web_url,
state, labels, references.full).

`resolveRepoInfo` extracted the repo slug via the regex
`[:/]([^/:]+/[^/:]+)$`, which only captures the last two path segments. For
nested GitLab groups like `big-bang/product/packages/elasticsearch-kibana`
this collapsed to `packages/elasticsearch-kibana`, so the reconcile path
hit a non-existent project at `glab api projects/<encoded>/merge_requests`
and got 404. Replace the regex with a new `extractSlug(fromRemote:)`
helper, parallel to `extractHost`, that returns the full path after the
host for both SSH and HTTPS remotes and strips a trailing `.git`.

Add a `IssueTrackerRemoteSlugTests` Swift Testing suite covering GitHub
SSH/HTTPS, two-level GitLab, nested-group GitLab (HTTPS and SSH),
trailing-`.git` stripping, and unrecognized inputs.

Closes #232

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@dgershman dgershman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code & Security Review

Critical Issues

None.

Security Review

Strengths:

  • The glab api endpoint change eliminates a dependency on git-repo context, which was the root cause of the failure. The query-string parameters (scope=assigned_to_me&state=opened&per_page=100) are static/trusted, so there's no injection risk.
  • extractSlug(fromRemote:) only operates on locally-obtained git remote URLs (from git remote get-url), not user-supplied input, so the regex parsing is safe.

Concerns:

  • None identified.

Code Quality

Minor: double .git stripping in resolveRepoInforesolveRepoInfo (line 1338) strips .git from the URL before passing it to extractSlug, but extractSlug itself also strips .git (line 1381). This is harmless (the second strip is a no-op), but worth noting as a minor redundancy. Not blocking.

Positive observations:

  • The extractSlug helper is clean, well-documented, and nonisolated static — easy to test in isolation. The parallel structure with extractHost is a good pattern.
  • Comprehensive test coverage: 7 new tests covering GitHub SSH/HTTPS, GitLab two-level and nested-group (both SSH and HTTPS), .git suffix stripping, and unrecognized input — all exercising the exact regression from #232.
  • The glab api approach mirrors the existing fetchGitLabMRsForReconcile pattern, keeping the codebase consistent.
  • The existing parser for fetchGitLabIssues (reading iid, title, web_url, state, labels, references.full) remains compatible with the glab api JSON response shape since the REST endpoint returns the same fields.

Summary Table

Priority Issue
Green Double .git strip between resolveRepoInfo and extractSlug is redundant but harmless

Recommendation: Approve — the fix is well-scoped, addresses both root causes cleanly, and has strong test coverage.

@dhilgaertner dhilgaertner merged commit 4e33fc2 into main May 1, 2026
3 checks passed
@dhilgaertner dhilgaertner deleted the feature/crow-232-glab-not-git-repo branch May 1, 2026 21:55
dhilgaertner added a commit that referenced this pull request May 4, 2026
…xes (#238)

Closes #235

## Summary

- Adds `docs/automation.md` as the canonical guide to Settings →
Automation and the full auto-flow lifecycle.
- Updates `docs/architecture.md` with the dual Ghostty/tmux backend
(#229), the new `TerminalRouter` dispatch, the Settings tab split
(#228), and the Review Board surface (#188, #205, #207, #210, #212,
#220, #226, #231).
- Adds `crow rename-terminal` (#206) to `docs/cli-reference.md`.
- Adds troubleshooting rows for tmux backend missing, Ghostty surface
retry (#218), GitLab nested groups (#233), `GITLAB_HOST` silent skip
(#215), auto-respond not firing, and the silent no-op `hook-event`
behavior (#234).
- Adds `CROW_TMUX_BACKEND` and `CROW_HOOK_DEBUG` to the
`docs/configuration.md` env-var table.
- Backfills `CHANGELOG.md` `[Unreleased]` with every PR from #137
through #234, grouped by theme.
- Updates `README.md` features list and docs index for the new
automation suite, review board, terminal renaming, and tmux opt-in.
- Appends an "Implementation Status (2026-05)" footer to
`docs/terminal-runtime-research.md` noting #229 shipped the headless-PTY
backend recommended in the original research.

The audit checklist called out as deliverable #1 in the issue is posted
as a [comment on
#235](#235 (comment)).

## Test plan

- [ ] `git diff --stat main` shows only the listed `docs/`,
`CHANGELOG.md`, and `README.md` files
- [ ] Render each modified doc on GitHub and confirm anchors /
cross-links resolve
- [ ] Confirm `crow --help` matches the command list in
`docs/cli-reference.md` (only `rename-terminal` was missing pre-PR)
- [ ] Walk every PR number in the CHANGELOG against `git log
--since=2026-04-15 main --oneline` and confirm each one resolves
- [ ] Re-export `docs/crow-screenshot.jpeg` against the current
Settings/Review-Board UI — **deferred to a follow-up**, called out in
the audit comment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IssueTracker: glab calls fail with 'not a git repository' and malformed nested-group slugs

2 participants