Skip to content

Commit da1edbf

Browse files
richmahnzeripath
authored andcommitted
Feature - Pagination for git tree API (#5838)
* Feature - Pagination for git tree API * Handles case when page is negative * Does a for loop over the start and end rather than all entries * Removed redundent logic * Adds per_page as a query parameter * Adds DEFAULT_GIT_TREES_PER_PAGE for settings, ran make fmt * Fix typo in cheat-sheet en * Makes page start at 1, generated swagger * Use updates to SDK * Updates to use latest sdk * Updates swagger for tree api * Adds test for GetTreeBySHA * Updates per PR reviews * Updates per PR reviews * Remove file * Formatting * Fix to swagger file * Fix to swagger * Update v1_json.tmpl * Fix to swagger file
1 parent 0c840a9 commit da1edbf

File tree

9 files changed

+144
-30
lines changed

9 files changed

+144
-30
lines changed

Gopkg.lock

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

custom/conf/app.ini.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,8 @@ ENABLE_SWAGGER = true
629629
MAX_RESPONSE_ITEMS = 50
630630
; Default paging number of api
631631
DEFAULT_PAGING_NUM = 30
632+
; Default and maximum number of items per page for git trees api
633+
DEFAULT_GIT_TREES_PER_PAGE = 1000
632634

633635
[i18n]
634636
LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
332332
- `ENABLE_SWAGGER`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
333333
- `MAX_RESPONSE_ITEMS`: **50**: Max number of items in a page.
334334
- `DEFAULT_PAGING_NUM`: **30**: Default paging number of api.
335+
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: Default and maximum number of items per page for git trees api.
335336

336337
## i18n (`i18n`)
337338

docs/content/doc/advanced/config-cheat-sheet.zh-cn.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ menu:
199199
- `ENABLE_SWAGGER`: **true**: 是否启用swagger路由 /api/swagger, /api/v1/swagger etc. endpoints. True 或 false; 默认是 true.
200200
- `MAX_RESPONSE_ITEMS`: **50**: 一个页面最大的项目数。
201201
- `DEFAULT_PAGING_NUM`: **30**: API中默认分页条数。
202+
- `DEFAULT_GIT_TREES_PER_PAGE`: **1000**: GIT TREES API每页的默认和最大项数.
202203

203204
## Markup (`markup`)
204205

modules/setting/setting.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -561,13 +561,15 @@ var (
561561

562562
// API settings
563563
API = struct {
564-
EnableSwagger bool
565-
MaxResponseItems int
566-
DefaultPagingNum int
564+
EnableSwagger bool
565+
MaxResponseItems int
566+
DefaultPagingNum int
567+
DefaultGitTreesPerPage int
567568
}{
568-
EnableSwagger: true,
569-
MaxResponseItems: 50,
570-
DefaultPagingNum: 30,
569+
EnableSwagger: true,
570+
MaxResponseItems: 50,
571+
DefaultPagingNum: 30,
572+
DefaultGitTreesPerPage: 1000,
571573
}
572574

573575
U2F = struct {

routers/api/v1/repo/tree.go

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,34 @@ func GetTree(ctx *context.APIContext) {
3737
// description: sha of the commit
3838
// type: string
3939
// required: true
40+
// - name: recursive
41+
// in: query
42+
// description: show all directories and files
43+
// required: false
44+
// type: boolean
45+
// - name: page
46+
// in: query
47+
// description: page number; the 'truncated' field in the response will be true if there are still more items after this page, false if the last page
48+
// required: false
49+
// type: integer
50+
// - name: per_page
51+
// in: query
52+
// description: number of items per page; default is 1000 or what is set in app.ini as DEFAULT_GIT_TREES_PER_PAGE
53+
// required: false
54+
// type: integer
4055
// responses:
4156
// "200":
4257
// "$ref": "#/responses/GitTreeResponse"
4358
sha := ctx.Params("sha")
4459
if len(sha) == 0 {
45-
ctx.Error(400, "sha not provided", nil)
60+
ctx.Error(400, "", "sha not provided")
4661
return
4762
}
4863
tree := GetTreeBySHA(ctx, sha)
4964
if tree != nil {
5065
ctx.JSON(200, tree)
5166
} else {
52-
ctx.Error(400, "sha invalid", nil)
67+
ctx.Error(400, "", "sha invalid")
5368
}
5469
}
5570

@@ -87,29 +102,44 @@ func GetTreeBySHA(ctx *context.APIContext, sha string) *gitea.GitTreeResponse {
87102
// 40 is the size of the sha1 hash in hexadecimal format.
88103
copyPos := len(treeURL) - 40
89104

90-
if len(entries) > 1000 {
91-
tree.Entries = make([]gitea.GitEntry, 1000)
105+
page := ctx.QueryInt("page")
106+
perPage := ctx.QueryInt("per_page")
107+
if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage {
108+
perPage = setting.API.DefaultGitTreesPerPage
109+
}
110+
if page <= 0 {
111+
page = 1
112+
}
113+
tree.Page = page
114+
tree.TotalCount = len(entries)
115+
rangeStart := perPage * (page - 1)
116+
if rangeStart >= len(entries) {
117+
return tree
118+
}
119+
var rangeEnd int
120+
if len(entries) > perPage {
121+
tree.Truncated = true
122+
}
123+
if rangeStart+perPage < len(entries) {
124+
rangeEnd = rangeStart + perPage
92125
} else {
93-
tree.Entries = make([]gitea.GitEntry, len(entries))
126+
rangeEnd = len(entries)
94127
}
95-
for e := range entries {
96-
if e > 1000 {
97-
tree.Truncated = true
98-
break
99-
}
100-
101-
tree.Entries[e].Path = entries[e].Name()
102-
tree.Entries[e].Mode = fmt.Sprintf("%06x", entries[e].Mode())
103-
tree.Entries[e].Type = string(entries[e].Type)
104-
tree.Entries[e].Size = entries[e].Size()
105-
tree.Entries[e].SHA = entries[e].ID.String()
128+
tree.Entries = make([]gitea.GitEntry, rangeEnd-rangeStart)
129+
for e := rangeStart; e < rangeEnd; e++ {
130+
i := e - rangeStart
131+
tree.Entries[i].Path = entries[e].Name()
132+
tree.Entries[i].Mode = fmt.Sprintf("%06x", entries[e].Mode())
133+
tree.Entries[i].Type = string(entries[e].Type)
134+
tree.Entries[i].Size = entries[e].Size()
135+
tree.Entries[i].SHA = entries[e].ID.String()
106136

107137
if entries[e].IsDir() {
108138
copy(treeURL[copyPos:], entries[e].ID.String())
109-
tree.Entries[e].URL = string(treeURL[:])
139+
tree.Entries[i].URL = string(treeURL[:])
110140
} else {
111141
copy(blobURL[copyPos:], entries[e].ID.String())
112-
tree.Entries[e].URL = string(blobURL[:])
142+
tree.Entries[i].URL = string(blobURL[:])
113143
}
114144
}
115145
return tree

routers/api/v1/repo/tree_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright 2019 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"github.com/stretchr/testify/assert"
9+
"testing"
10+
11+
"code.gitea.io/gitea/models"
12+
"code.gitea.io/gitea/modules/context"
13+
"code.gitea.io/gitea/modules/test"
14+
"code.gitea.io/sdk/gitea"
15+
)
16+
17+
func TestGetTreeBySHA(t *testing.T) {
18+
models.PrepareTestEnv(t)
19+
sha := "master"
20+
ctx := test.MockContext(t, "user2/repo1")
21+
ctx.SetParams(":id", "1")
22+
ctx.SetParams(":sha", sha)
23+
test.LoadRepo(t, ctx, 1)
24+
test.LoadRepoCommit(t, ctx)
25+
test.LoadUser(t, ctx, 2)
26+
test.LoadGitRepo(t, ctx)
27+
28+
tree := GetTreeBySHA(&context.APIContext{Context: ctx, Org: nil}, ctx.Params("sha"))
29+
expectedTree := &gitea.GitTreeResponse{
30+
SHA: "65f1bf27bc3bf70f64657658635e66094edbcb4d",
31+
URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/trees/65f1bf27bc3bf70f64657658635e66094edbcb4d",
32+
Entries: []gitea.GitEntry{
33+
{
34+
Path: "README.md",
35+
Mode: "100644",
36+
Type: "blob",
37+
Size: 30,
38+
SHA: "4b4851ad51df6a7d9f25c979345979eaeb5b349f",
39+
URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/4b4851ad51df6a7d9f25c979345979eaeb5b349f",
40+
},
41+
},
42+
Truncated: false,
43+
Page: 1,
44+
TotalCount: 1,
45+
}
46+
47+
assert.EqualValues(t, tree, expectedTree)
48+
}

templates/swagger/v1_json.tmpl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,24 @@
17751775
"name": "sha",
17761776
"in": "path",
17771777
"required": true
1778+
},
1779+
{
1780+
"type": "boolean",
1781+
"description": "show all directories and files",
1782+
"name": "recursive",
1783+
"in": "query"
1784+
},
1785+
{
1786+
"type": "integer",
1787+
"description": "page number; the 'truncated' field in the response will be true if there are still more items after this page, false if the last page",
1788+
"name": "page",
1789+
"in": "query"
1790+
},
1791+
{
1792+
"type": "integer",
1793+
"description": "number of items per page; default is 1000 or what is set in app.ini as DEFAULT_GIT_TREES_PER_PAGE",
1794+
"name": "per_page",
1795+
"in": "query"
17781796
}
17791797
],
17801798
"responses": {
@@ -7352,10 +7370,20 @@
73527370
"description": "GitTreeResponse returns a git tree",
73537371
"type": "object",
73547372
"properties": {
7373+
"page": {
7374+
"type": "integer",
7375+
"format": "int64",
7376+
"x-go-name": "Page"
7377+
},
73557378
"sha": {
73567379
"type": "string",
73577380
"x-go-name": "SHA"
73587381
},
7382+
"total_count": {
7383+
"type": "integer",
7384+
"format": "int64",
7385+
"x-go-name": "TotalCount"
7386+
},
73597387
"tree": {
73607388
"type": "array",
73617389
"items": {

vendor/code.gitea.io/sdk/gitea/repo_tree.go

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

0 commit comments

Comments
 (0)