Skip to content

Commit e2f8ef6

Browse files
authored
fix(api): respect since/until when counting commits for X-Total-Count (go-gitea#38204)
The repository commits API (`GET /repos/{owner}/{repo}/commits`) accepts `since` and `until` query parameters and filters the returned page of commits by commit date. However, the `X-Total-Count` and `X-Total` response headers reported the *unfiltered* total number of commits, so the advertised total could be far larger than the number of commits actually returned for the requested date range. With a range that matches no commits, the page is correctly empty while the headers still claim the full repository total. ## Root cause `gitrepo.CommitsCount` declared `Since` and `Until` options and the API handler populated them, but the function never appended `--since`/`--until` to the underlying `git rev-list --count` invocation. The date filters were silently dropped, so the count always reflected the entire revision history. ## Fix Pass the `Since`/`Until` options through to `git rev-list`, mirroring the existing commit-listing path (`commitsByRangeWithTime`). The reported total now matches the filtered range used to build the page. ## Testing Added `TestCommitsCountWithSinceUntil` in `modules/gitrepo/commit_test.go`, a table-driven unit test against the `repo1_bare` fixture covering `since`, `until`, and a bounded `since`+`until` range. It fails on the pre-fix code (every case returns the full count of 3) and passes after the change. Existing `CommitsCount` tests remain green. ## Notes - No new settings, no default changes; this corrects an incorrect header value and is backward compatible. Clients that depend on `since`/`until` already filter the returned commits, and the headers now agree with that filtering. Fixes go-gitea#35886. --- *AI-assistance disclosure:* this change was developed with the assistance of agent (Claude Opus 4.8). I have reviewed and understand the change and take responsibility for it.
1 parent 76c33de commit e2f8ef6

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

modules/gitrepo/commit.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ func CommitsCount(ctx context.Context, repo Repository, opts CommitsCountOptions
3232
cmd.AddOptionValues("--not", opts.Not)
3333
}
3434

35+
if opts.Since != "" {
36+
cmd.AddOptionFormat("--since=%s", opts.Since)
37+
}
38+
39+
if opts.Until != "" {
40+
cmd.AddOptionFormat("--until=%s", opts.Until)
41+
}
42+
3543
if len(opts.RelPath) > 0 {
3644
cmd.AddDashesAndList(opts.RelPath...)
3745
}

modules/gitrepo/commit_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,37 @@ func TestCommitsCountWithoutBase(t *testing.T) {
3434
assert.Equal(t, int64(2), commitsCount)
3535
}
3636

37+
func TestCommitsCountWithSinceUntil(t *testing.T) {
38+
bareRepo1 := &mockRepository{path: "repo1_bare"}
39+
revision := []string{"8006ff9adbf0cb94da7dad9e537e53817f9fa5c0"}
40+
41+
// The three commits on this revision are dated 2018-04-18, 2017-12-19 and 2017-12-19.
42+
cases := []struct {
43+
name string
44+
since string
45+
until string
46+
expected int64
47+
}{
48+
{name: "no filter", expected: 3},
49+
{name: "since keeps newer commits", since: "2018-01-01", expected: 1},
50+
{name: "until keeps older commits", until: "2018-01-01", expected: 2},
51+
{name: "since and until bound the range", since: "2017-12-19T22:16:00-08:00", until: "2018-01-01", expected: 1},
52+
}
53+
for _, tc := range cases {
54+
t.Run(tc.name, func(t *testing.T) {
55+
commitsCount, err := CommitsCount(t.Context(), bareRepo1,
56+
CommitsCountOptions{
57+
Revision: revision,
58+
Since: tc.since,
59+
Until: tc.until,
60+
})
61+
62+
assert.NoError(t, err)
63+
assert.Equal(t, tc.expected, commitsCount)
64+
})
65+
}
66+
}
67+
3768
func TestGetLatestCommitTime(t *testing.T) {
3869
bareRepo1 := &mockRepository{path: "repo1_bare"}
3970
lct, err := GetLatestCommitTime(t.Context(), bareRepo1)

0 commit comments

Comments
 (0)