Expose creator date on ListRefs references

Problem

We are migrating the non-search Tags REST API listing from FindAllTags to ListRefs (gitlab#614152). Currently, offset pages 2 and above fetch all tags before Rails selects the requested page, even though FindAllTags supports limits and cursors.

The proposed migration has existing sources for most response data:

Tags API needs Source with ListRefs
Name, target ID Returned by default
Peeled commit ID for annotated tags peel_tags: true
Commit details Existing batch ListCommitsByOid RPC
Annotated-tag message Existing batch GetTagMessages RPC
Tag created_at Tagger timestamp missing from ListRefs

The API must preserve the tagger date for annotated tags and null for lightweight tags. An annotated tag without a tagger date also has no creation date.

Existing API behavior and lookup alternative
  • Gitlab::Git::Tag#date reads the tagger timestamp, with no commit-date fallback.
  • Tag entity specs explicitly expect created_at: nil for lightweight tags.
  • Git's creatordate returns a commit date for lightweight tags. It is used for sorting but does not match the API field's semantics.
  • FindTag supports lightweight tags by name. Individual lookups are possible, but introduce per-tag RPC overhead; their cost has not been established by our benchmark.

Proposal

Extend the existing ListRefs RPC with an opt-in tagger-date field, following the optional-output pattern used by peel_tags:

  1. In proto/ref.proto, add a request flag, tentatively include_tagger_date, and a field on ListRefsResponse.Reference with explicit presence. For example, google.protobuf.Timestamp tagger_date distinguishes absence from Unix epoch zero. Names and type remain subject to Gitaly team agreement.
  2. In list_refs.go, append %(taggerdate:unix) to the existing for-each-ref format when requested. Read the tag object's own timestamp, not the peeled object's timestamp.
  3. In newListRefsWriter, parse the extra element. Leave the field absent for blank output; preserve 0 as a valid timestamp.

No new RPC or per-tag lookup is needed for this field. Keep it opt-in so existing callers retain their current behavior.

Requesting the field may require additional object reads, particularly with name sorting. Benchmark enabled versus disabled behavior for both name and creation-date sorting, including large tag counts; do not assume the field adds negligible work.

Tests should cover the flag disabled, annotated and lightweight tags, missing dates, epoch zero, and pagination combined with peeling.

I am happy to implement this once the Gitaly team confirms the field semantics, name, type, and opt-in design.

Impact

Blocks final adoption of the non-search Tags API migration: gitlab#614152. Rails must also preserve the returned timestamp through its finder and tag-object mapping.

Edited by Emma Park