Skip to content

Add GitLab::listNamespaces() to list personal namespace + groups#122

Merged
HarshMN2345 merged 6 commits into
mainfrom
feat/gitlab-list-namespaces
Jul 23, 2026
Merged

Add GitLab::listNamespaces() to list personal namespace + groups#122
HarshMN2345 merged 6 commits into
mainfrom
feat/gitlab-list-namespaces

Conversation

@HarshMN2345

Copy link
Copy Markdown
Member

Summary

  • GitLab's OAuth2 grant covers a user's personal namespace and every group they belong to in one authorization — there's no step in the flow itself where the user picks one, unlike GitHub's per-installation org picker.
  • Adds GitLab::listNamespaces(int $page, int $per_page, string $search), returning {items, total} (same shape as searchRepositories()), so a caller (e.g. Appwrite) can build its own namespace/group picker after the OAuth redirect.

Test plan

  • composer format / composer analyze pass
  • New testListNamespaces / testListNamespacesWithSearch in GitLabTest.php (skip cleanly without a live GitLab instance, same as existing GitLab integration tests)

…oups

GitLab's OAuth2 grant covers the user's personal namespace and every
group they belong to in one authorization -- unlike GitHub's per-
installation org picker, there's no step in the flow where the user
chooses one. Appwrite needs this to build its own namespace/group
picker after the OAuth redirect, similar to how Vercel/Netlify let you
switch between orgs post-connect.
Total only included the personal namespace on page 1 (it was gated
behind the same page===1 check as the item itself), so a caller
paginating would see a different total depending on which page they
requested first. Fetch /user on every page to decide the search match
consistently, and drop the redundant min_access_level filter -- /groups
already scopes to groups the user belongs to.
@greptile-apps

greptile-apps Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Replaces manual GitLab namespace merging with the paginated /namespaces API.

  • Normalizes personal and group namespaces into a shared {items, total} response.
  • Adds live integration coverage for listing and searching namespaces.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failures remain within the scope of the previous review threads.

Important Files Changed

Filename Overview
src/VCS/Adapter/Git/GitLab.php Adds a thin authenticated /namespaces API wrapper that resolves the previously reported combined-pagination issue.
tests/VCS/Adapter/GitLabTest.php Adds integration tests covering combined personal/group results and namespace searching.

Reviews (5): Last reviewed commit: "Use GitLab's native /namespaces endpoint..." | Re-trigger Greptile

Comment thread src/VCS/Adapter/Git/GitLab.php Outdated
The previous fix fetched /user on every page to keep the total
consistent, but that's wasteful: without a search term the personal
namespace always counts, so only page 1 (to build the item) or an
active search (to resolve the match) actually need the call.
Comment thread src/VCS/Adapter/Git/GitLab.php
HarshMN2345 added a commit to appwrite/appwrite that referenced this pull request Jul 23, 2026
Exposes GitLab::listNamespaces() (utopia-php/vcs#122) so the console
can build a group/namespace picker after OAuth connect -- GitLab has
no per-installation org scoping like GitHub's App flow, so there's
nowhere else in the stack that knows about a user's groups.

For providers without listNamespaces() (currently everything but
GitLab), falls back to a single-item list wrapping the installation's
own organization, so the response shape stays uniform for callers.
…ast page

Page 1 always requested a full per_page groups before prepending the
personal namespace, so a full group page pushed it to per_page+1
items -- and when the group count was exactly divisible by per_page,
the incremented total advertised a final page whose group request
returned nothing (Greptile P1).

Reserves one slot for the personal namespace on page 1 only, and
fetches groups via a 0-based offset into the full group list (shifted
by 1 whenever the personal namespace occupies a slot), walking GitLab's
own page/per_page boundaries since that offset rarely aligns with them.

Adds a pure-unit test faking the HTTP layer to cover the exact
boundary case a live-only test can't reach without seeding 20+ real
groups. Also drops the page/per_page defaults on listNamespaces() to
match searchRepositories()' pattern of requiring callers to pass them
explicitly.
Comment thread src/VCS/Adapter/Git/GitLab.php
Comment thread src/VCS/Adapter/Git/GitLab.php Outdated
Comment thread src/VCS/Adapter/Git/GitLab.php Outdated
Comment thread src/VCS/Adapter/Git/GitLab.php Outdated
Comment thread src/VCS/Adapter/Git/GitLab.php
Comment thread src/VCS/Adapter/Git/GitLab.php Outdated
…r + /groups

GitLab already exposes GET /namespaces, which combines the personal
namespace and every group into one correctly-paginated list with the
exact fields needed (id, name, path, kind, avatar_url) and its own
search param. The previous implementation manually merged /user with
/groups and shifted pagination offsets to account for the personal
namespace taking a slot -- solving a problem GitLab's own API already
solves, and the source of the P1 pagination bug found in review.

This also settles review naming questions: "namespaces" (not "groups")
and "kind" (not "type") both mirror GitLab's own /namespaces API
terminology directly, since this is an adapter for that API.
@HarshMN2345
HarshMN2345 merged commit 4abcc51 into main Jul 23, 2026
10 of 13 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.

2 participants