feat: Refactor Commits API list endpoint to use CommitsFinder
Why
Part of epic &21573, closing #595508 (closed). Refactors the Commits API list endpoint (GET /projects/:id/repository/commits) to use Repositories::CommitsFinder (merged in !235257 (merged)) and GitalyKeysetPager (merged in!239139).
Keyset mode also fixes #586997, where page/cursor were silently ignored with all=true.
What
- Endpoint now delegates to
CommitsFinder+GitalyKeysetPagerfor the new keyset mode and keeps existing code untouched. - Keyset mode gated by
commits_keyset_paginationFF (default off); when off, behavior is unchanged. - Params unsupported with keyset (
path,first_parent, non-defaultorder,trailers,follow) return400. The finder raisesRepositories::CommitsFinder::UnsupportedKeysetParamError(a subclass ofArgumentError), and the endpoint rescues that class to surface the400— no error-message string matching.
How to validate locally
How to validate locally
Note: The
commits_keyset_paginationflag is cached per Puma worker. After enabling or disabling it, rungdk restart rails-web(wait ~15s) before testing — otherwise requests hitting stale workers give inconsistent400/200results.
Set a token and pick a project with enough commit history to paginate:
export TOKEN=<your_gdk_token>
export ID=<project_id>1. Enable the flag
In rails console:
Feature.enable(:commits_keyset_pagination)Then restart: gdk restart rails-web.
2. Keyset pagination advances the cursor (fixes #586997)
Fetch page 1 and inspect the Link header:
curl -s -D - --header "PRIVATE-TOKEN: $TOKEN" \
"http://gdk.test:3000/api/v4/projects/$ID/repository/commits?pagination=keyset&all=true&per_page=5"Copy the page_token=<SHA> from the Link: ...; rel="next" header, then fetch page 2:
curl -s -D - --header "PRIVATE-TOKEN: $TOKEN" \
"http://gdk.test:3000/api/v4/projects/$ID/repository/commits?pagination=keyset&all=true&per_page=5&page_token=<SHA>"Expected: page 2 returns different commits than page 1, and its Link header carries a new page_token. (Before the fix, all=true returned the same commits on every page.)
3. Unsupported params return 400 (keyset mode only)
curl -s -o /dev/null -w '%{http_code}\n' --header "PRIVATE-TOKEN: $TOKEN" \
"http://gdk.test:3000/api/v4/projects/$ID/repository/commits?pagination=keyset&first_parent=true"Expected: 400 for each of path, first_parent, order (non-default), trailers, and follow. The same params without pagination=keyset still return 200 (offset mode is unaffected).
4. Flag off = unchanged legacy behavior
In rails console:
Feature.disable(:commits_keyset_pagination)Then restart (gdk restart rails-web) and confirm offset pagination still works:
curl -s -D - --header "PRIVATE-TOKEN: $TOKEN" \
"http://gdk.test:3000/api/v4/projects/$ID/repository/commits?all=true&per_page=5&page=2"Expected: 200 with normal offset results; page>1 slicing works, and X-Total / rel="last" headers are absent (offset-without-count behavior, unchanged from master).