Skip to content

Commit ff56292

Browse files
authored
Pass 'not' to commit count (#24473)
Due to #24409 , we can now specify '--not' when getting all commits from a repo to exclude commits from a different branch. When I wrote that PR, I forgot to also update the code that counts the number of commits in the repo. So now, if the --not option is used, it may return too many commits, which can indicate that another page of data is available when it is not. This PR passes --not to the commands that count the number of commits in a repo
1 parent e962ade commit ff56292

File tree

10 files changed

+177
-30
lines changed

10 files changed

+177
-30
lines changed

modules/context/repo.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,12 @@ func (r *Repository) GetCommitGraphsCount(ctx context.Context, hidePRRefs bool,
208208
if len(branches) == 0 {
209209
return git.AllCommitsCount(ctx, r.Repository.RepoPath(), hidePRRefs, files...)
210210
}
211-
return git.CommitsCountFiles(ctx, r.Repository.RepoPath(), branches, files)
211+
return git.CommitsCount(ctx,
212+
git.CommitsCountOptions{
213+
RepoPath: r.Repository.RepoPath(),
214+
Revision: branches,
215+
RelPath: files,
216+
})
212217
})
213218
}
214219

modules/git/commit.go

+24-12
Original file line numberDiff line numberDiff line change
@@ -160,30 +160,42 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
160160
return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
161161
}
162162

163-
// CommitsCountFiles returns number of total commits of until given revision.
164-
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
163+
// CommitsCountOptions the options when counting commits
164+
type CommitsCountOptions struct {
165+
RepoPath string
166+
Not string
167+
Revision []string
168+
RelPath []string
169+
}
170+
171+
// CommitsCount returns number of total commits of until given revision.
172+
func CommitsCount(ctx context.Context, opts CommitsCountOptions) (int64, error) {
165173
cmd := NewCommand(ctx, "rev-list", "--count")
166-
cmd.AddDynamicArguments(revision...)
167-
if len(relpath) > 0 {
168-
cmd.AddDashesAndList(relpath...)
174+
175+
cmd.AddDynamicArguments(opts.Revision...)
176+
177+
if opts.Not != "" {
178+
cmd.AddOptionValues("--not", opts.Not)
169179
}
170180

171-
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
181+
if len(opts.RelPath) > 0 {
182+
cmd.AddDashesAndList(opts.RelPath...)
183+
}
184+
185+
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: opts.RepoPath})
172186
if err != nil {
173187
return 0, err
174188
}
175189

176190
return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
177191
}
178192

179-
// CommitsCount returns number of total commits of until given revision.
180-
func CommitsCount(ctx context.Context, repoPath string, revision ...string) (int64, error) {
181-
return CommitsCountFiles(ctx, repoPath, revision, []string{})
182-
}
183-
184193
// CommitsCount returns number of total commits of until current revision.
185194
func (c *Commit) CommitsCount() (int64, error) {
186-
return CommitsCount(c.repo.Ctx, c.repo.Path, c.ID.String())
195+
return CommitsCount(c.repo.Ctx, CommitsCountOptions{
196+
RepoPath: c.repo.Path,
197+
Revision: []string{c.ID.String()},
198+
})
187199
}
188200

189201
// CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize

modules/git/commit_test.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,30 @@ import (
1414
func TestCommitsCount(t *testing.T) {
1515
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
1616

17-
commitsCount, err := CommitsCount(DefaultContext, bareRepo1Path, "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0")
17+
commitsCount, err := CommitsCount(DefaultContext,
18+
CommitsCountOptions{
19+
RepoPath: bareRepo1Path,
20+
Revision: []string{"8006ff9adbf0cb94da7dad9e537e53817f9fa5c0"},
21+
})
22+
1823
assert.NoError(t, err)
1924
assert.Equal(t, int64(3), commitsCount)
2025
}
2126

27+
func TestCommitsCountWithoutBase(t *testing.T) {
28+
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
29+
30+
commitsCount, err := CommitsCount(DefaultContext,
31+
CommitsCountOptions{
32+
RepoPath: bareRepo1Path,
33+
Not: "master",
34+
Revision: []string{"branch1"},
35+
})
36+
37+
assert.NoError(t, err)
38+
assert.Equal(t, int64(2), commitsCount)
39+
}
40+
2241
func TestGetFullCommitID(t *testing.T) {
2342
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
2443

modules/git/repo_commit.go

+32-8
Original file line numberDiff line numberDiff line change
@@ -205,12 +205,24 @@ func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bo
205205

206206
// FileCommitsCount return the number of files at a revision
207207
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
208-
return CommitsCountFiles(repo.Ctx, repo.Path, []string{revision}, []string{file})
208+
return CommitsCount(repo.Ctx,
209+
CommitsCountOptions{
210+
RepoPath: repo.Path,
211+
Revision: []string{revision},
212+
RelPath: []string{file},
213+
})
214+
}
215+
216+
type CommitsByFileAndRangeOptions struct {
217+
Revision string
218+
File string
219+
Not string
220+
Page int
209221
}
210222

211223
// CommitsByFileAndRange return the commits according revision file and the page
212-
func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) ([]*Commit, error) {
213-
skip := (page - 1) * setting.Git.CommitsRangeSize
224+
func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) ([]*Commit, error) {
225+
skip := (opts.Page - 1) * setting.Git.CommitsRangeSize
214226

215227
stdoutReader, stdoutWriter := io.Pipe()
216228
defer func() {
@@ -220,10 +232,15 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
220232
go func() {
221233
stderr := strings.Builder{}
222234
gitCmd := NewCommand(repo.Ctx, "rev-list").
223-
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize*page).
235+
AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize*opts.Page).
224236
AddOptionFormat("--skip=%d", skip)
225-
gitCmd.AddDynamicArguments(revision)
226-
gitCmd.AddDashesAndList(file)
237+
gitCmd.AddDynamicArguments(opts.Revision)
238+
239+
if opts.Not != "" {
240+
gitCmd.AddOptionValues("--not", opts.Not)
241+
}
242+
243+
gitCmd.AddDashesAndList(opts.File)
227244
err := gitCmd.Run(&RunOpts{
228245
Dir: repo.Path,
229246
Stdout: stdoutWriter,
@@ -365,11 +382,18 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) ([]*Commit, error
365382

366383
// CommitsCountBetween return numbers of commits between two commits
367384
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
368-
count, err := CommitsCountFiles(repo.Ctx, repo.Path, []string{start + ".." + end}, []string{})
385+
count, err := CommitsCount(repo.Ctx, CommitsCountOptions{
386+
RepoPath: repo.Path,
387+
Revision: []string{start + ".." + end},
388+
})
389+
369390
if err != nil && strings.Contains(err.Error(), "no merge base") {
370391
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
371392
// previously it would return the results of git rev-list before last so let's try that...
372-
return CommitsCountFiles(repo.Ctx, repo.Path, []string{start, end}, []string{})
393+
return CommitsCount(repo.Ctx, CommitsCountOptions{
394+
RepoPath: repo.Path,
395+
Revision: []string{start, end},
396+
})
373397
}
374398

375399
return count, err

routers/api/v1/repo/commits.go

+23-4
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func GetAllCommits(ctx *context.APIContext) {
146146

147147
sha := ctx.FormString("sha")
148148
path := ctx.FormString("path")
149+
not := ctx.FormString("not")
149150

150151
var (
151152
commitsCountTotal int64
@@ -178,14 +179,18 @@ func GetAllCommits(ctx *context.APIContext) {
178179
}
179180

180181
// Total commit count
181-
commitsCountTotal, err = baseCommit.CommitsCount()
182+
commitsCountTotal, err = git.CommitsCount(ctx.Repo.GitRepo.Ctx, git.CommitsCountOptions{
183+
RepoPath: ctx.Repo.GitRepo.Path,
184+
Not: not,
185+
Revision: []string{baseCommit.ID.String()},
186+
})
187+
182188
if err != nil {
183189
ctx.Error(http.StatusInternalServerError, "GetCommitsCount", err)
184190
return
185191
}
186192

187193
// Query commits
188-
not := ctx.FormString("not")
189194
commits, err = baseCommit.CommitsByRange(listOptions.Page, listOptions.PageSize, not)
190195
if err != nil {
191196
ctx.Error(http.StatusInternalServerError, "CommitsByRange", err)
@@ -196,7 +201,14 @@ func GetAllCommits(ctx *context.APIContext) {
196201
sha = ctx.Repo.Repository.DefaultBranch
197202
}
198203

199-
commitsCountTotal, err = ctx.Repo.GitRepo.FileCommitsCount(sha, path)
204+
commitsCountTotal, err = git.CommitsCount(ctx,
205+
git.CommitsCountOptions{
206+
RepoPath: ctx.Repo.GitRepo.Path,
207+
Not: not,
208+
Revision: []string{sha},
209+
RelPath: []string{path},
210+
})
211+
200212
if err != nil {
201213
ctx.Error(http.StatusInternalServerError, "FileCommitsCount", err)
202214
return
@@ -205,7 +217,14 @@ func GetAllCommits(ctx *context.APIContext) {
205217
return
206218
}
207219

208-
commits, err = ctx.Repo.GitRepo.CommitsByFileAndRange(sha, path, listOptions.Page)
220+
commits, err = ctx.Repo.GitRepo.CommitsByFileAndRange(
221+
git.CommitsByFileAndRangeOptions{
222+
Revision: sha,
223+
File: path,
224+
Not: not,
225+
Page: listOptions.Page,
226+
})
227+
209228
if err != nil {
210229
ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err)
211230
return

routers/api/v1/repo/wiki.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,12 @@ func ListPageRevisions(ctx *context.APIContext) {
429429
}
430430

431431
// get Commit Count
432-
commitsHistory, err := wikiRepo.CommitsByFileAndRange("master", pageFilename, page)
432+
commitsHistory, err := wikiRepo.CommitsByFileAndRange(
433+
git.CommitsByFileAndRangeOptions{
434+
Revision: "master",
435+
File: pageFilename,
436+
Page: page,
437+
})
433438
if err != nil {
434439
ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err)
435440
return

routers/web/feed/file.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"code.gitea.io/gitea/models/repo"
1212
"code.gitea.io/gitea/modules/context"
13+
"code.gitea.io/gitea/modules/git"
1314
"code.gitea.io/gitea/modules/util"
1415

1516
"github.com/gorilla/feeds"
@@ -21,7 +22,12 @@ func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string
2122
if len(fileName) == 0 {
2223
return
2324
}
24-
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(ctx.Repo.RefName, fileName, 1)
25+
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
26+
git.CommitsByFileAndRangeOptions{
27+
Revision: ctx.Repo.RefName,
28+
File: fileName,
29+
Page: 1,
30+
})
2531
if err != nil {
2632
ctx.ServerError("ShowBranchFeed", err)
2733
return

routers/web/repo/commit.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,12 @@ func FileHistory(ctx *context.Context) {
230230
page = 1
231231
}
232232

233-
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(ctx.Repo.RefName, fileName, page)
233+
commits, err := ctx.Repo.GitRepo.CommitsByFileAndRange(
234+
git.CommitsByFileAndRangeOptions{
235+
Revision: ctx.Repo.RefName,
236+
File: fileName,
237+
Page: page,
238+
})
234239
if err != nil {
235240
ctx.ServerError("CommitsByFileAndRange", err)
236241
return

routers/web/repo/wiki.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,12 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
376376
}
377377

378378
// get Commit Count
379-
commitsHistory, err := wikiRepo.CommitsByFileAndRange(wiki_service.DefaultBranch, pageFilename, page)
379+
commitsHistory, err := wikiRepo.CommitsByFileAndRange(
380+
git.CommitsByFileAndRangeOptions{
381+
Revision: wiki_service.DefaultBranch,
382+
File: pageFilename,
383+
Page: page,
384+
})
380385
if err != nil {
381386
if wikiRepo != nil {
382387
wikiRepo.Close()

tests/integration/api_repo_git_commits_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,29 @@ func TestAPIReposGitCommitList(t *testing.T) {
5858
session := loginUser(t, user.Name)
5959
token := getTokenForLoggedInUser(t, session)
6060

61+
// Test getting commits (Page 1)
62+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo20/commits?token="+token+"&not=master&sha=remove-files-a", user.Name)
63+
resp := MakeRequest(t, req, http.StatusOK)
64+
65+
var apiData []api.Commit
66+
DecodeJSON(t, resp, &apiData)
67+
68+
assert.Len(t, apiData, 2)
69+
assert.EqualValues(t, "cfe3b3c1fd36fba04f9183287b106497e1afe986", apiData[0].CommitMeta.SHA)
70+
compareCommitFiles(t, []string{"link_hi", "test.csv"}, apiData[0].Files)
71+
assert.EqualValues(t, "c8e31bc7688741a5287fcde4fbb8fc129ca07027", apiData[1].CommitMeta.SHA)
72+
compareCommitFiles(t, []string{"test.csv"}, apiData[1].Files)
73+
74+
assert.EqualValues(t, resp.Header().Get("X-Total"), "2")
75+
}
76+
77+
func TestAPIReposGitCommitListNotMaster(t *testing.T) {
78+
defer tests.PrepareTestEnv(t)()
79+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
80+
// Login as User2.
81+
session := loginUser(t, user.Name)
82+
token := getTokenForLoggedInUser(t, session)
83+
6184
// Test getting commits (Page 1)
6285
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token, user.Name)
6386
resp := MakeRequest(t, req, http.StatusOK)
@@ -72,6 +95,8 @@ func TestAPIReposGitCommitList(t *testing.T) {
7295
compareCommitFiles(t, []string{"readme.md"}, apiData[1].Files)
7396
assert.EqualValues(t, "5099b81332712fe655e34e8dd63574f503f61811", apiData[2].CommitMeta.SHA)
7497
compareCommitFiles(t, []string{"readme.md"}, apiData[2].Files)
98+
99+
assert.EqualValues(t, resp.Header().Get("X-Total"), "3")
75100
}
76101

77102
func TestAPIReposGitCommitListPage2Empty(t *testing.T) {
@@ -148,4 +173,26 @@ func TestGetFileHistory(t *testing.T) {
148173
assert.Len(t, apiData, 1)
149174
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
150175
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
176+
177+
assert.EqualValues(t, resp.Header().Get("X-Total"), "1")
178+
}
179+
180+
func TestGetFileHistoryNotOnMaster(t *testing.T) {
181+
defer tests.PrepareTestEnv(t)()
182+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
183+
// Login as User2.
184+
session := loginUser(t, user.Name)
185+
token := getTokenForLoggedInUser(t, session)
186+
187+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo20/commits?path=test.csv&token="+token+"&sha=add-csv&not=master", user.Name)
188+
resp := MakeRequest(t, req, http.StatusOK)
189+
190+
var apiData []api.Commit
191+
DecodeJSON(t, resp, &apiData)
192+
193+
assert.Len(t, apiData, 1)
194+
assert.Equal(t, "c8e31bc7688741a5287fcde4fbb8fc129ca07027", apiData[0].CommitMeta.SHA)
195+
compareCommitFiles(t, []string{"test.csv"}, apiData[0].Files)
196+
197+
assert.EqualValues(t, resp.Header().Get("X-Total"), "1")
151198
}

0 commit comments

Comments
 (0)