Skip to content

fix(scm): restore GitLab inline posting after the bin/ launcher removal - #111

Merged
mountainowl merged 1 commit into
mainfrom
fix/gitlab-mcp-posting
Jun 17, 2026
Merged

fix(scm): restore GitLab inline posting after the bin/ launcher removal#111
mountainowl merged 1 commit into
mainfrom
fix/gitlab-mcp-posting

Conversation

@mountainowl

Copy link
Copy Markdown
Owner

Severity: production regression (since v0.13.0 / #77)

Found while converging the gaps left in PRs merged yesterday/today.

#77 consolidated bin/ and deleted bin/mcp-upstream-gitlab + bin/mcp-upstream-github, but the Python posting path still referenced them:

  • mcp.DEFAULT_MCP_SERVER and scm/github.py:_GITHUB_MCP_SERVER pointed at the deleted wrappers.
  • GitLabProvider.post_inline_comment called mcp.call_tool(...) with no try/exceptcall_tool does Popen([deleted_path]) → uncaught FileNotFoundError before the REST fallback.

Result: every real (non-dry_run) GitLab inline finding post crashed and the review recorded FAILED. GitLab is the default provider. GitHub survived only because its post path already caught OSError → REST.

dry_run (the default) plans findings instead of posting, so default-config runs and the unit suite (which mocks call_tool) never surfaced it.

Fix

  • scm/gitlab.py — wrap the MCP call in try/except (RuntimeError, TimeoutError, OSError) and fall back to REST, mirroring the GitHub provider. (restores posting — the critical fix)
  • mcp.py / scm/github.py — repoint the dead constants at the real dispatcher as argv lists ([.../bin/bubo, mcp-upstream, <provider>]); call_tool now accepts a command list, so MCP posting works again when the upstream server is installed, and there's no shell-split space-in-path risk.
  • tests/test_gitlab_provider.py (new) — pins the regression: REST recovery on FileNotFoundError/RuntimeError, MCP preferred when it returns an id, and a guard that the default targets the dispatcher (not a deleted wrapper).

Verification

  • Full suite under a memory watchdog: 428 passed, peak 158 MB.
  • ruff + mypy clean on all changed files.

#77 consolidated the bin/ launchers and deleted bin/mcp-upstream-gitlab and
bin/mcp-upstream-github, but left mcp.DEFAULT_MCP_SERVER and
scm.github._GITHUB_MCP_SERVER pointing at the deleted wrappers.
GitLabProvider.post_inline_comment called mcp.call_tool with no try/except, so
the missing launcher raised FileNotFoundError (an OSError) from the subprocess
spawn BEFORE the REST fallback — crashing every real (non-dry-run) GitLab
inline finding post since v0.13.0. GitHub survived only because its post path
already caught OSError and fell back to REST.

- scm/gitlab.py: wrap the MCP call in try/except (RuntimeError, TimeoutError,
  OSError) and fall back to REST, mirroring the GitHub provider.
- mcp.py / scm/github.py: repoint the dead launcher constants at the real
  dispatcher as argv lists ([.../bin/bubo, mcp-upstream, <provider>]) so MCP
  posting works again when the upstream server is installed; call_tool now
  accepts a command list (argv), avoiding shell-split space-in-path issues.
- tests/test_gitlab_provider.py: pin the regression — REST recovery on a
  FileNotFoundError/RuntimeError MCP failure, MCP preferred when it returns an
  id, and the default targets the dispatcher.

dry_run reviews were unaffected (findings are planned, not posted), which is
why default-config runs and the suite never surfaced it.
@mountainowl
mountainowl merged commit c20082e into main Jun 17, 2026
4 checks passed
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