Migrate Tags API listing (non-search) to Gitaly-side TagsFinder via ListRefs

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Background

The Tags API (GET /projects/:id/repository/tags) is served by TagsFinder + FindAllTags. The Branches API was already migrated to a Gitaly-side finder (Gitlab::Git::Finders::BranchesFinder on top of Gitlab::Git::Finders::RefsFinder/ListRefs) behind the use_new_branches_finder_api feature flag (!229216 (merged), rollout #594929 (closed)).

This issue covers the non-search part of the same migration for tags, as scoped by spike #602972 (closed). Search is tracked separately in #372051.

Why

  • Consistency with the branches architecture (single ListRefs-based path for refs listing, FindAllTags/FindLocalBranches eventually retired — see epic &11057).
  • Fixes a real gap: numeric offset pagination (?page=2+) currently falls through to a fetch-all path — Gitaly streams every tag and Rails slices the page in Ruby (Gitlab::Pagination::GitalyKeysetPager#paginate fallback). The new finder handles this with the branches-style over-fetch (limit = page × per_page, slice in Ruby — see Gitlab::Git::Finders::BranchesFinder#effective_per_page).
  • ListRefs is lighter per-ref than FindAllTags (no per-tag cat-file parsing in Gitaly).

ToDo

Mirror the branches pattern:

  • 1: Gitlab::Git::Finders::TagsFinder** (mirror Gitlab::Git::Finders::BranchesFinder)
    • wraps Gitlab::Git::Finders::RefsFinder with ref_type: :tags, peel_tags: true
    • hydrates Gitlab::Git::Tag objects: peeled commit via Commit.batch_by_oid, message via batch GetTagMessages (existing Gitlab::Git::Tag.get_message), created_at via the new ListRefs timestamp field, preserving the tagger date for annotated tags and null for lightweight tags. (gitaly#7352)
    • numeric offset page support via over-fetch, like branches
  • 2: adopt in lib/api/tags.rb behind a feature flag
    • route to the new finder only when search is blank and order_by is not version (ListRefs has no version:refname sort key; those requests stay on TagsFinder)
    • Gitlab::Pagination::GitalyKeysetPager routing clauses for the new finder

Out of scope

  • Search (?search=): stays on legacy TagsFinder until gitaly#7351 is resolved — tracked in #372051
  • order_by=version: stays on legacy TagsFinder (no version sort in ListRefs)
  • UI tags page (Projects::TagsController): needs signature data, which ListRefs does not provide — REST API only, per spike scope

Dependencies

  • Blocked by gitaly#7352 (creator date on ListRefs references): without it the API cannot render created_at. The finder structure, message hydration, over-fetch logic, and specs can be built before that lands; final adoption cannot.
  • Blocks #372051.
Edited by 🤖 GitLab Bot 🤖