Skip to content

Improve GitHub branch listing pagination#102

Open
HarshMN2345 wants to merge 17 commits into
mainfrom
feature/github-branch-search-pagination
Open

Improve GitHub branch listing pagination#102
HarshMN2345 wants to merge 17 commits into
mainfrom
feature/github-branch-search-pagination

Conversation

@HarshMN2345
Copy link
Copy Markdown
Member

No description provided.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Greptile Summary

This PR rewrites listBranches across all four VCS adapters to support cursor-based pagination, per-page size, and prefix search, and changes the return type from a flat array<string> to a structured {items, hasNext, nextCursor} shape.

  • GitHub now uses GraphQL repository.refs with per-edge cursors and a "+1 probe" strategy to determine hasNext without ever returning an empty items alongside a truthy hasNext.
  • GitLab issues a single paginated API call with ^prefix server-side search and reads X-Next-Page for hasNext; Gitea and Gogs fetch all branches from the API and apply prefix filtering and page slicing client-side. Gogs::getLatestCommit is updated to page through all virtual pages when scanning for a branch.

Confidence Score: 5/5

The PR is safe to merge; all adapters return the new structured shape consistently and the pagination logic is correct across providers.

All adapters correctly implement the new signature, return type, and pagination contract. The GitHub GraphQL probe logic ensures items is never empty when hasNext is true. The Gogs branch-existence scan iterates through all virtual pages. The abstract contract, concrete implementations, and tests are all in sync. The only note is a minor efficiency opportunity in the GitHub adapter for $perPage less than 100.

No files require special attention.

Important Files Changed

Filename Overview
src/VCS/Adapter/Git/GitHub.php Moved branch listing from REST to GraphQL with cursor-based pagination, probe-based hasNext detection, and server-side prefix search; logic is correct and addresses all previously flagged issues
src/VCS/Adapter/Git/GitLab.php Replaced all-pages loop with single-page server-side request using GitLab's ^prefix search syntax and X-Next-Page header for hasNext detection; correct implementation
src/VCS/Adapter/Git/Gitea.php Adds $search/$perPage/$page support: fetches all branches from API, applies prefix filter and page-slice client-side; hasNext calculation is correct
src/VCS/Adapter/Git/Gogs.php listBranches now filters/paginates client-side; getLatestCommit correctly iterates through all virtual pages to find a branch instead of being silently limited to the first 100
src/VCS/Adapter.php Abstract signature updated to match all implementations; PHPDoc correctly documents the cursor vs integer page semantics and structured return type

Reviews (11): Last reviewed commit: "Document that Gitea has no server-side b..." | Re-trigger Greptile

Comment thread src/VCS/Adapter/Git/GitHub.php Outdated
Comment thread src/VCS/Adapter/Git/GitHub.php Outdated
Comment thread src/VCS/Adapter.php Outdated
@HarshMN2345 HarshMN2345 force-pushed the feature/github-branch-search-pagination branch from 43e2053 to e71e384 Compare May 14, 2026 11:32
Comment thread src/VCS/Adapter/Git/GitLab.php Outdated
Comment thread src/VCS/Adapter/Git/Gogs.php Outdated
All providers now return array{items, hasNext, nextCursor} so callers
get a consistent shape regardless of provider. GitHub uses true GraphQL
cursor pagination; GitLab/Gitea/Gogs/Forgejo compute hasNext from the
client-side slice and always return nextCursor: null. Error-path early
returns and the Gogs internal branch-existence check are updated to match.
Tests updated and testListBranchesNonExistingRepository added for GitLab
and Gitea (inherited by Gogs and Forgejo).
@HarshMN2345 HarshMN2345 force-pushed the feature/github-branch-search-pagination branch from 3a84574 to f85fa75 Compare May 25, 2026 13:08
Comment thread src/VCS/Adapter/Git/GitHub.php Outdated
@HarshMN2345 HarshMN2345 requested a review from Meldiron May 25, 2026 14:38
Comment thread src/VCS/Adapter/Git/GitHub.php Outdated
'name' => $repositoryName,
'first' => $perPage,
'after' => $currentCursor,
'query' => $search !== '' ? $search : null,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do I understand this query parameter is reasin to use GraphQL? Can we try same endpoint with HTTP to have proof query isnt accepted there?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Tested this. REST branches API has no search support and only supports page-based pagination. We need GraphQL here for both branch search and cursor-based pagination (nextCursor). Added comments above the query documenting both limitations.

Comment thread src/VCS/Adapter/Git/GitLab.php
Comment thread src/VCS/Adapter/Git/Gogs.php Outdated
$gql = <<<'GRAPHQL'
query ListBranches($owner: String!, $name: String!, $first: Int!, $after: String, $query: String) {
repository(owner: $owner, name: $name) {
refs(refPrefix: "refs/heads/", first: $first, after: $after, orderBy: {field: ALPHABETICAL, direction: ASC}, query: $query) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Curious, does Gitea have refs endpoints too? I recall they try to be compatible with GitHub, I would expect we can urilize same thing there.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Nope, Gitea does not support server-side branch filtering
Parameters like q or search are ignored server-side (verified against Codeberg/Forgejo). Since Gitea also lacks GraphQL support, fetching all branches and filtering client-side is currently unavoidable. Added a comment documenting this behavior.

The private helper was only called from one place; the logic is now
directly inside listBranches with an explanatory comment block.
Two REST limitations make GraphQL necessary:
1. REST branches endpoint has no search/filter param (query is GraphQL-only)
2. REST only supports integer page offsets (per-edge cursors are GraphQL-only)
GitLab's branches API accepts search=^term to filter branches that begin
with term, so we no longer need to fetch all pages before filtering.
A single paginated request is made; hasNext is read from X-Next-Page.
The parameter was being reassigned and then used 10 lines later for
client-side slicing, which looked like dead code. Renaming it and
adding a comment makes the intent clear.
Live test on Codeberg (Forgejo/Gitea) confirmed the q param is silently
ignored — fetch-all + client-side str_starts_with is the only option.
@HarshMN2345 HarshMN2345 requested a review from Meldiron May 26, 2026 12:30
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