Files
kandev/docs/plans/gitlab-integration-parity/plan.md
T
2026-07-21 23:24:22 +01:00

11 KiB

spec, created, status
spec created status
docs/specs/gitlab-integration/spec.md 2026-07-20 done

Implementation Plan: GitLab Integration Parity

Overview

Finish the existing GitLab integration instead of replacing it. First make the connection and client resolution workspace-owned, then connect watches to the shared task dispatcher and complete the task-link/upstream write contracts. User-facing watch, quick-launch, and MR review flows land after those contracts; provider-aware MR creation and integrated desktop/mobile E2E close the build.

The legacy plan at docs/specs/gitlab-integration/plan.md describes the initial scaffold and is superseded by this plan for parity work.

Backend

Workspace-owned connection

  • Add GitLabConfig and gitlab_configs persistence in apps/backend/internal/gitlab/models.go, store.go, and new focused store_config.go, service_config.go, and copy.go files.
  • Refactor apps/backend/internal/gitlab/factory.go, provider.go, and service.go to resolve/cache a client by workspace_id; no service method or poll may call the legacy installation-wide Client() path.
  • Migrate the legacy gitlab_host system setting and GITLAB_TOKEN secret to a deterministic workspace using the Jira/Linear provider migration pattern.
  • Replace /status, /token, and /host write semantics with workspace config, test, delete, and copy routes while retaining compatibility only where an existing internal caller still needs it during the migration.
  • Require workspace scope on search, projects, feedback, presets, watches, and write actions in controller.go, controller_watches.go, and handlers.go.
  • Accept normalized http:// and https:// self-managed origins and preserve the configured scheme through API, web-link, clone, and MR-create paths.
  • Update apps/backend/internal/gitlab/poller.go and search/watch services to resolve the client from each watch's workspace.

Watch dispatch

  • Add GitLabReviewWatcherSource and GitLabIssueWatcherSource under apps/backend/internal/orchestrator/, implementing the existing WatcherSource reservation, request, attachment, auto-start, throttle, and self-heal contract.
  • Replace the nullable GitLab-specific task creators in event_handlers_gitlab.go with three-line forwards to WatcherDispatchCoordinator.Dispatch.
  • Extend GitLab watch rows/requests with optional repository/base branch, max_inflight_tasks, and last_error; validate every referenced resource is owned by the watch workspace.
  • Add disabled-with-error behavior plus GitHub-parity reset/delete lifecycle: reset previews, best-effort attempts all owned tasks (including archived), transactionally clears dedup/last-poll state, retains the watch, and reruns immediately for reviews or on the next issue poll; delete best-effort deletes owned tasks, removes watch/dedup state, and never reruns. Ensure e2e_reset.go removes GitLab poller-owned rows before tasks.

Task-to-MR association and quick launch support

  • Add a strict configured-host MR URL parser and AssociateExistingMRByURL/UnlinkTaskMR services in new service_task_mr_link.go and controller_task_mrs.go files.
  • Make association idempotent, validate task/repository workspace ownership, fetch live MR state before writing, and delete the linked refresh watch on unlink.
  • Keep SyncTaskMR as the internal project/IID refresh path, not the public paste-URL contract.

Reviewers and GitLab notification subscriptions

  • Preserve GitLab numeric member IDs in the public model.
  • Extend Client and PAT/glab/mock/noop implementations with project-member search, reviewer replacement, and issue/MR subscription read/write methods.
  • Add workspace-scoped routes in controller_watches.go; refresh the MR after successful reviewer writes and map ineligible members to an action error.

First-class merge request creation

  • Add prProviderGitLab and a GitLab remote parser/creator to apps/backend/internal/agentctl/server/process/git_pr_providers.go; prefer glab and use a JSON-safe REST fallback with GITLAB_TOKEN.
  • Extend the successful PRCreateResult with provider while preserving worktree.create_pr compatibility.
  • Make GitHandlers dispatch successful GitLab URLs to the GitLab association service through backendapp/gateway.go, including multi-repository identity.
  • Resolve the workspace GitLab host/token for clone and executor environment in backendapp, orchestrator/executor, and repoclone; never hardcode gitlab.com when the workspace has a configured host.

Frontend

Workspace settings

  • Replace global GitLab settings calls in apps/web/components/gitlab/gitlab-settings.tsx with workspace config APIs and status, including host, auth method, token, test, disconnect, and unavailable/auth-required states.
  • Add GitLab to integration-copy-config.ts; the settings route workspace switcher remains authoritative.
  • Make /gitlab and integration availability consume status for the active workspace rather than global state.

Watch settings

  • Build GitLab review/issue watch dialog and table components following the GitHub shells and Jira/Linear workspace/resource validation patterns.
  • Expose create/edit, enable/pause, run-now, reset-preview/reset, and delete in gitlab-settings.tsx, with stable desktop/mobile controls and confirmation for destructive reset.
  • Add GitLab QuickTaskLauncher, matching only provider = "gitlab" repositories on the configured host and project path.
  • Add preset menus to mr-list.tsx and issue-list.tsx. On MR task-create success, call the explicit association endpoint; issue launches retain URL context without a durable issue link.
  • Add a (host, project_path, mr_iid) -> tasks hook and task indicator so the browse list reflects links and unlinking.

MR review surface

  • Add GitLab MR detail/section components using existing feedback, files, commits, approvals, discussion, merge, label, and assignee endpoints plus the new reviewer/subscription endpoints.
  • Route task detail/dockview PR panels by provider and add linked GitLab MRs to auto-open, picker, changes-panel, and context behavior without regressing GitHub PRs.
  • Use "merge request" labels for GitLab while keeping protocol/internal PR names where compatibility requires them. All actions remain reachable on mobile.

Tests

  • Workspace isolation and migration: internal/gitlab/store_config_test.go, service_config_test.go, controller_config_test.go, and backendapp/gitlab_service_test.go cover two hosts/tokens, deterministic legacy migration, copy-without-watches, invalid config preservation, and cross-workspace denial, including preserved HTTP and HTTPS schemes.
  • Watch dispatch: orchestrator/source_gitlab_test.go and event_handlers_gitlab_test.go exercise reserve -> create -> attach, release-on-failure, auto-start params, throttle, and self-heal. GitLab service/controller/store tests cover resource validation and reset.
  • Task MR linking: GitLab parser/service/store/controller tests cover self-managed URLs, wrong-host rejection, idempotence, multi-repo identity, unlink, and workspace isolation.
  • Provider writes: PAT/glab/mock/noop/controller tests cover numeric reviewer IDs, empty reviewer replacement, subscription read/write, issue/MR endpoint selection, and sanitized failures.
  • MR creation: agentctl process and handler tests cover HTTPS/SSH/self-managed remotes, glab/REST selection, default/explicit target branch, draft output, partial push failure, and GitLab callback association.
  • Frontend units: API, slice, hook, settings, watch dialog/table, launcher, row indicator, MR detail, task dockview, and provider terminology tests cover the matching observable spec scenarios.

E2E Tests

  • Add GitLab mock seed/control APIs to apps/backend/internal/gitlab/mock_controller.go and apps/web/e2e/helpers/api-client.ts; reset all GitLab config/watch/link state in apps/backend/internal/backendapp/e2e_reset.go.
  • Desktop apps/web/e2e/tests/gitlab/gitlab-parity.spec.ts: connect two workspaces, prove isolation, quick-launch/link/unlink, open MR review, set a reviewer, reply/resolve, and toggle MR/issue subscriptions.
  • Desktop apps/web/e2e/tests/gitlab/gitlab-watches.spec.ts: create and run review/issue watches, prove exactly-once task creation, pause behavior, and reset confirmation.
  • Desktop apps/web/e2e/tests/gitlab/gitlab-mr-creation.spec.ts: create an MR from a task changes panel, verify provider terminology and automatic link.
  • Mobile apps/web/e2e/tests/gitlab/mobile-gitlab-parity.spec.ts: cover browse quick launch, watch controls, linked-MR detail/actions, and MR creation at the mobile viewport with no horizontal overflow or inaccessible controls.

Implementation Waves

Wave 1:

Wave 2 (parallel after Task 01):

Wave 3:

Wave 4 (parallel after Wave 2; Task 06 does not share Task 07 runtime files):

Wave 5:

Tasks 03 and 04 must put new HTTP handlers in separate focused controller files; their only shared route-registration edit should be integrated by the parent at the end of Wave 2. Task 05 finishes settings before Wave 4. Tasks 06 and 07 own task-review UI and runtime/create UI respectively; neither should refactor shared GitHub components.

Verification

Targeted commands are listed in each task. Final integrated verification runs in this order:

rtk make fmt
rtk make typecheck
rtk make test
rtk make lint
cd apps/web && rtk pnpm e2e:run tests/gitlab/gitlab-parity.spec.ts tests/gitlab/gitlab-watches.spec.ts tests/gitlab/gitlab-mr-creation.spec.ts
cd apps/web && rtk pnpm e2e:run --no-build --project mobile-chrome tests/gitlab/mobile-gitlab-parity.spec.ts
rtk node --test scripts/validate-public-docs.test.mjs
rtk node scripts/validate-public-docs.mjs

Risks

  • The global-to-workspace client refactor touches every GitLab call path. Keep a single clientForWorkspace boundary and reject missing scope rather than retaining mixed global/workspace behavior.
  • GitLab discussion and reviewer capabilities vary by version/tier. Test against REST v4 contracts and surface unsupported writes without hiding readable MR state.
  • GitHub task review UI is deeply named around PRs. Add provider routing and GitLab-specific components before extracting shared abstractions; broad UI unification is outside this build.
  • glab is optional in agent executors. The REST fallback must parse remote host/project safely, redact credentials, and never send a token to a host that does not match the workspace connection.