Skip to content

Commit 8bdc979

Browse files
authored
Add name filter to API for GetMilestoneList (#12336)
Adds a name filter to the API for GetMilestoneList Includes a small refactor: merge GetMilestones and GetMilestonesByRepoID Close #12260 Needed for https://gitea.com/gitea/go-sdk/issues/383 and https://gitea.com/gitea/tea/pulls/149
1 parent 78cbd0c commit 8bdc979

File tree

8 files changed

+115
-36
lines changed

8 files changed

+115
-36
lines changed

integrations/api_issue_milestone_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ func TestAPIIssuesMilestone(t *testing.T) {
5555
assert.Equal(t, "wow", apiMilestone.Title)
5656
assert.Equal(t, structs.StateClosed, apiMilestone.State)
5757

58+
var apiMilestones []structs.Milestone
59+
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&token=%s", owner.Name, repo.Name, "all", token))
60+
resp = session.MakeRequest(t, req, http.StatusOK)
61+
DecodeJSON(t, resp, &apiMilestones)
62+
assert.Len(t, apiMilestones, 4)
63+
64+
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&name=%s&token=%s", owner.Name, repo.Name, "all", "milestone2", token))
65+
resp = session.MakeRequest(t, req, http.StatusOK)
66+
DecodeJSON(t, resp, &apiMilestones)
67+
assert.Len(t, apiMilestones, 1)
68+
assert.Equal(t, int64(2), apiMilestones[0].ID)
69+
5870
req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, apiMilestone.ID, token))
5971
resp = session.MakeRequest(t, req, http.StatusNoContent)
6072
}

models/issue_milestone.go

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -330,41 +330,38 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 {
330330
return ids
331331
}
332332

333-
// GetMilestonesByRepoID returns all opened milestones of a repository.
334-
func GetMilestonesByRepoID(repoID int64, state api.StateType, listOptions ListOptions) (MilestoneList, error) {
335-
sess := x.Where("repo_id = ?", repoID)
333+
// GetMilestonesOption contain options to get milestones
334+
type GetMilestonesOption struct {
335+
ListOptions
336+
RepoID int64
337+
State api.StateType
338+
Name string
339+
SortType string
340+
}
341+
342+
// GetMilestones returns milestones filtered by GetMilestonesOption's
343+
func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) {
344+
sess := x.Where("repo_id = ?", opts.RepoID)
336345

337-
switch state {
346+
switch opts.State {
338347
case api.StateClosed:
339348
sess = sess.And("is_closed = ?", true)
340-
341349
case api.StateAll:
342350
break
343-
344-
case api.StateOpen:
345-
fallthrough
346-
351+
// api.StateOpen:
347352
default:
348353
sess = sess.And("is_closed = ?", false)
349354
}
350355

351-
if listOptions.Page != 0 {
352-
sess = listOptions.setSessionPagination(sess)
356+
if len(opts.Name) != 0 {
357+
sess = sess.And(builder.Like{"name", opts.Name})
353358
}
354359

355-
miles := make([]*Milestone, 0, listOptions.PageSize)
356-
return miles, sess.Asc("deadline_unix").Asc("id").Find(&miles)
357-
}
358-
359-
// GetMilestones returns a list of milestones of given repository and status.
360-
func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
361-
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
362-
sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
363-
if page > 0 {
364-
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
360+
if opts.Page != 0 {
361+
sess = opts.setSessionPagination(sess)
365362
}
366363

367-
switch sortType {
364+
switch opts.SortType {
368365
case "furthestduedate":
369366
sess.Desc("deadline_unix")
370367
case "leastcomplete":
@@ -375,9 +372,13 @@ func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (Mile
375372
sess.Asc("num_issues")
376373
case "mostissues":
377374
sess.Desc("num_issues")
375+
case "id":
376+
sess.Asc("id")
378377
default:
379-
sess.Asc("deadline_unix")
378+
sess.Asc("deadline_unix").Asc("id")
380379
}
380+
381+
miles := make([]*Milestone, 0, opts.PageSize)
381382
return miles, sess.Find(&miles)
382383
}
383384

models/issue_milestone_test.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"sort"
99
"testing"
1010

11+
"code.gitea.io/gitea/modules/setting"
1112
api "code.gitea.io/gitea/modules/structs"
1213
"code.gitea.io/gitea/modules/timeutil"
1314

@@ -49,7 +50,10 @@ func TestGetMilestonesByRepoID(t *testing.T) {
4950
assert.NoError(t, PrepareTestDatabase())
5051
test := func(repoID int64, state api.StateType) {
5152
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
52-
milestones, err := GetMilestonesByRepoID(repo.ID, state, ListOptions{})
53+
milestones, err := GetMilestones(GetMilestonesOption{
54+
RepoID: repo.ID,
55+
State: state,
56+
})
5357
assert.NoError(t, err)
5458

5559
var n int
@@ -83,7 +87,10 @@ func TestGetMilestonesByRepoID(t *testing.T) {
8387
test(3, api.StateClosed)
8488
test(3, api.StateAll)
8589

86-
milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen, ListOptions{})
90+
milestones, err := GetMilestones(GetMilestonesOption{
91+
RepoID: NonexistentID,
92+
State: api.StateOpen,
93+
})
8794
assert.NoError(t, err)
8895
assert.Len(t, milestones, 0)
8996
}
@@ -93,7 +100,15 @@ func TestGetMilestones(t *testing.T) {
93100
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
94101
test := func(sortType string, sortCond func(*Milestone) int) {
95102
for _, page := range []int{0, 1} {
96-
milestones, err := GetMilestones(repo.ID, page, false, sortType)
103+
milestones, err := GetMilestones(GetMilestonesOption{
104+
ListOptions: ListOptions{
105+
Page: page,
106+
PageSize: setting.UI.IssuePagingNum,
107+
},
108+
RepoID: repo.ID,
109+
State: api.StateOpen,
110+
SortType: sortType,
111+
})
97112
assert.NoError(t, err)
98113
assert.Len(t, milestones, repo.NumMilestones-repo.NumClosedMilestones)
99114
values := make([]int, len(milestones))
@@ -102,7 +117,16 @@ func TestGetMilestones(t *testing.T) {
102117
}
103118
assert.True(t, sort.IntsAreSorted(values))
104119

105-
milestones, err = GetMilestones(repo.ID, page, true, sortType)
120+
milestones, err = GetMilestones(GetMilestonesOption{
121+
ListOptions: ListOptions{
122+
Page: page,
123+
PageSize: setting.UI.IssuePagingNum,
124+
},
125+
RepoID: repo.ID,
126+
State: api.StateClosed,
127+
Name: "",
128+
SortType: sortType,
129+
})
106130
assert.NoError(t, err)
107131
assert.Len(t, milestones, repo.NumClosedMilestones)
108132
values = make([]int, len(milestones))

modules/migrations/gitea_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,17 @@ func TestGiteaUploadRepo(t *testing.T) {
5151
repo := models.AssertExistsAndLoadBean(t, &models.Repository{OwnerID: user.ID, Name: repoName}).(*models.Repository)
5252
assert.True(t, repo.HasUncyclo())
5353

54-
milestones, err := models.GetMilestones(repo.ID, 0, false, "")
54+
milestones, err := models.GetMilestones(models.GetMilestonesOption{
55+
RepoID: repo.ID,
56+
State: structs.StateOpen,
57+
})
5558
assert.NoError(t, err)
5659
assert.EqualValues(t, 1, len(milestones))
5760

58-
milestones, err = models.GetMilestones(repo.ID, 0, true, "")
61+
milestones, err = models.GetMilestones(models.GetMilestonesOption{
62+
RepoID: repo.ID,
63+
State: structs.StateClosed,
64+
})
5965
assert.NoError(t, err)
6066
assert.EqualValues(t, 0, len(milestones))
6167

routers/api/v1/repo/milestone.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ func ListMilestones(ctx *context.APIContext) {
3939
// in: query
4040
// description: Milestone state, Recognised values are open, closed and all. Defaults to "open"
4141
// type: string
42+
// - name: name
43+
// in: query
44+
// description: filter by milestone name
45+
// type: string
4246
// - name: page
4347
// in: query
4448
// description: page number of results to return (1-based)
@@ -51,9 +55,14 @@ func ListMilestones(ctx *context.APIContext) {
5155
// "200":
5256
// "$ref": "#/responses/MilestoneList"
5357

54-
milestones, err := models.GetMilestonesByRepoID(ctx.Repo.Repository.ID, api.StateType(ctx.Query("state")), utils.GetListOptions(ctx))
58+
milestones, err := models.GetMilestones(models.GetMilestonesOption{
59+
ListOptions: utils.GetListOptions(ctx),
60+
RepoID: ctx.Repo.Repository.ID,
61+
State: api.StateType(ctx.Query("state")),
62+
Name: ctx.Query("name"),
63+
})
5564
if err != nil {
56-
ctx.Error(http.StatusInternalServerError, "GetMilestonesByRepoID", err)
65+
ctx.Error(http.StatusInternalServerError, "GetMilestones", err)
5766
return
5867
}
5968

routers/repo/issue.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,11 @@ func Issues(ctx *context.Context) {
360360
issues(ctx, ctx.QueryInt64("milestone"), util.OptionalBoolOf(isPullList))
361361

362362
var err error
363-
// Get milestones.
364-
ctx.Data["Milestones"], err = models.GetMilestonesByRepoID(ctx.Repo.Repository.ID, api.StateType(ctx.Query("state")), models.ListOptions{})
363+
// Get milestones
364+
ctx.Data["Milestones"], err = models.GetMilestones(models.GetMilestonesOption{
365+
RepoID: ctx.Repo.Repository.ID,
366+
State: api.StateType(ctx.Query("state")),
367+
})
365368
if err != nil {
366369
ctx.ServerError("GetAllRepoMilestones", err)
367370
return
@@ -375,12 +378,18 @@ func Issues(ctx *context.Context) {
375378
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository
376379
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repository) {
377380
var err error
378-
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false, "")
381+
ctx.Data["OpenMilestones"], err = models.GetMilestones(models.GetMilestonesOption{
382+
RepoID: repo.ID,
383+
State: api.StateOpen,
384+
})
379385
if err != nil {
380386
ctx.ServerError("GetMilestones", err)
381387
return
382388
}
383-
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true, "")
389+
ctx.Data["ClosedMilestones"], err = models.GetMilestones(models.GetMilestonesOption{
390+
RepoID: repo.ID,
391+
State: api.StateClosed,
392+
})
384393
if err != nil {
385394
ctx.ServerError("GetMilestones", err)
386395
return

routers/repo/milestone.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"code.gitea.io/gitea/modules/context"
1414
"code.gitea.io/gitea/modules/markup/markdown"
1515
"code.gitea.io/gitea/modules/setting"
16+
"code.gitea.io/gitea/modules/structs"
1617
"code.gitea.io/gitea/modules/timeutil"
1718
"code.gitea.io/gitea/modules/util"
1819

@@ -47,13 +48,24 @@ func Milestones(ctx *context.Context) {
4748
}
4849

4950
var total int
51+
var state structs.StateType
5052
if !isShowClosed {
5153
total = int(stats.OpenCount)
54+
state = structs.StateOpen
5255
} else {
5356
total = int(stats.ClosedCount)
57+
state = structs.StateClosed
5458
}
5559

56-
miles, err := models.GetMilestones(ctx.Repo.Repository.ID, page, isShowClosed, sortType)
60+
miles, err := models.GetMilestones(models.GetMilestonesOption{
61+
ListOptions: models.ListOptions{
62+
Page: page,
63+
PageSize: setting.UI.IssuePagingNum,
64+
},
65+
RepoID: ctx.Repo.Repository.ID,
66+
State: state,
67+
SortType: sortType,
68+
})
5769
if err != nil {
5870
ctx.ServerError("GetMilestones", err)
5971
return

templates/swagger/v1_json.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6164,6 +6164,12 @@
61646164
"name": "state",
61656165
"in": "query"
61666166
},
6167+
{
6168+
"type": "string",
6169+
"description": "filter by milestone name",
6170+
"name": "name",
6171+
"in": "query"
6172+
},
61676173
{
61686174
"type": "integer",
61696175
"description": "page number of results to return (1-based)",

0 commit comments

Comments
 (0)