Skip to content

Commit 1dd83db

Browse files
authored
Filters for GetAllCommits (#24568)
The `GetAllCommits` endpoint can be pretty slow, especially in repos with a lot of commits. The issue is that it spends a lot of time calculating information that may not be useful/needed by the user. The `stat` param was previously added in #21337 to address this, by allowing the user to disable the calculating stats for each commit. But this has two issues: 1. The name `stat` is rather misleading, because disabling `stat` disables the Stat **and** Files. This should be separated out into two different params, because getting a list of affected files is much less expensive than calculating the stats 2. There's still other costly information provided that the user may not need, such as `Verification` This PR, adds two parameters to the endpoint, `files` and `verification` to allow the user to explicitly disable this information when listing commits. The default behavior is true.
1 parent 707c7e6 commit 1dd83db

File tree

6 files changed

+72
-8
lines changed

6 files changed

+72
-8
lines changed

routers/api/v1/repo/commits.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func getCommit(ctx *context.APIContext, identifier string) {
6969
return
7070
}
7171

72-
json, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil, true)
72+
json, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, nil, convert.ToCommitOptions{Stat: true})
7373
if err != nil {
7474
ctx.Error(http.StatusInternalServerError, "toCommit", err)
7575
return
@@ -107,6 +107,14 @@ func GetAllCommits(ctx *context.APIContext) {
107107
// in: query
108108
// description: include diff stats for every commit (disable for speedup, default 'true')
109109
// type: boolean
110+
// - name: verification
111+
// in: query
112+
// description: include verification for every commit (disable for speedup, default 'true')
113+
// type: boolean
114+
// - name: files
115+
// in: query
116+
// description: include a list of affected files for every commit (disable for speedup, default 'true')
117+
// type: boolean
110118
// - name: page
111119
// in: query
112120
// description: page number of results to return (1-based)
@@ -238,10 +246,18 @@ func GetAllCommits(ctx *context.APIContext) {
238246
apiCommits := make([]*api.Commit, len(commits))
239247

240248
stat := ctx.FormString("stat") == "" || ctx.FormBool("stat")
249+
verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
250+
files := ctx.FormString("files") == "" || ctx.FormBool("files")
241251

242252
for i, commit := range commits {
243253
// Create json struct
244-
apiCommits[i], err = convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache, stat)
254+
apiCommits[i], err = convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, commit, userCache,
255+
convert.ToCommitOptions{
256+
Stat: stat,
257+
Verification: verification,
258+
Files: files,
259+
})
260+
245261
if err != nil {
246262
ctx.Error(http.StatusInternalServerError, "toCommit", err)
247263
return

routers/api/v1/repo/notes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func getNote(ctx *context.APIContext, identifier string) {
7878
return
7979
}
8080

81-
cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, true)
81+
cmt, err := convert.ToCommit(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, note.Commit, nil, convert.ToCommitOptions{Stat: true})
8282
if err != nil {
8383
ctx.Error(http.StatusInternalServerError, "ToCommit", err)
8484
return

routers/api/v1/repo/pull.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ func GetPullRequestCommits(ctx *context.APIContext) {
13181318

13191319
apiCommits := make([]*api.Commit, 0, end-start)
13201320
for i := start; i < end; i++ {
1321-
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache, true)
1321+
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache, convert.ToCommitOptions{Stat: true})
13221322
if err != nil {
13231323
ctx.ServerError("toCommit", err)
13241324
return

services/convert/git_commit.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,14 @@ func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, c *git.Co
7272
}
7373
}
7474

75+
type ToCommitOptions struct {
76+
Stat bool
77+
Verification bool
78+
Files bool
79+
}
80+
7581
// ToCommit convert a git.Commit to api.Commit
76-
func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, stat bool) (*api.Commit, error) {
82+
func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, commit *git.Commit, userCache map[string]*user_model.User, opts ToCommitOptions) (*api.Commit, error) {
7783
var apiAuthor, apiCommitter *api.User
7884

7985
// Retrieve author and committer information
@@ -162,19 +168,24 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
162168
SHA: commit.ID.String(),
163169
Created: commit.Committer.When,
164170
},
165-
Verification: ToVerification(ctx, commit),
166171
},
167172
Author: apiAuthor,
168173
Committer: apiCommitter,
169174
Parents: apiParents,
170175
}
171176

177+
// Retrieve verification for commit
178+
if opts.Verification {
179+
res.RepoCommit.Verification = ToVerification(ctx, commit)
180+
}
181+
172182
// Retrieve files affected by the commit
173-
if stat {
183+
if opts.Files {
174184
fileStatus, err := git.GetCommitFileStatus(gitRepo.Ctx, repo.RepoPath(), commit.ID.String())
175185
if err != nil {
176186
return nil, err
177187
}
188+
178189
affectedFileList := make([]*api.CommitAffectedFiles, 0, len(fileStatus.Added)+len(fileStatus.Removed)+len(fileStatus.Modified))
179190
for _, files := range [][]string{fileStatus.Added, fileStatus.Removed, fileStatus.Modified} {
180191
for _, filename := range files {
@@ -184,14 +195,18 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
184195
}
185196
}
186197

198+
res.Files = affectedFileList
199+
}
200+
201+
// Get diff stats for commit
202+
if opts.Stat {
187203
diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{
188204
AfterCommitID: commit.ID.String(),
189205
})
190206
if err != nil {
191207
return nil, err
192208
}
193209

194-
res.Files = affectedFileList
195210
res.Stats = &api.CommitStats{
196211
Total: diff.TotalAddition + diff.TotalDeletion,
197212
Additions: diff.TotalAddition,

templates/swagger/v1_json.tmpl

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/integration/api_repo_git_commits_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,27 @@ func TestAPIReposGitCommitListDifferentBranch(t *testing.T) {
135135
compareCommitFiles(t, []string{"readme.md"}, apiData[0].Files)
136136
}
137137

138+
func TestAPIReposGitCommitListWithoutSelectFields(t *testing.T) {
139+
defer tests.PrepareTestEnv(t)()
140+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
141+
// Login as User2.
142+
session := loginUser(t, user.Name)
143+
token := getTokenForLoggedInUser(t, session)
144+
145+
// Test getting commits without files, verification, and stats
146+
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo16/commits?token="+token+"&sha=good-sign&stat=false&files=false&verification=false", user.Name)
147+
resp := MakeRequest(t, req, http.StatusOK)
148+
149+
var apiData []api.Commit
150+
DecodeJSON(t, resp, &apiData)
151+
152+
assert.Len(t, apiData, 1)
153+
assert.Equal(t, "f27c2b2b03dcab38beaf89b0ab4ff61f6de63441", apiData[0].CommitMeta.SHA)
154+
assert.Equal(t, (*api.CommitStats)(nil), apiData[0].Stats)
155+
assert.Equal(t, (*api.PayloadCommitVerification)(nil), apiData[0].RepoCommit.Verification)
156+
assert.Equal(t, ([]*api.CommitAffectedFiles)(nil), apiData[0].Files)
157+
}
158+
138159
func TestDownloadCommitDiffOrPatch(t *testing.T) {
139160
defer tests.PrepareTestEnv(t)()
140161
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})

0 commit comments

Comments
 (0)