Skip to content

Add name filter to API for GetMilestoneList #12336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions integrations/api_issue_milestone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ func TestAPIIssuesMilestone(t *testing.T) {
assert.Equal(t, "wow", apiMilestone.Title)
assert.Equal(t, structs.StateClosed, apiMilestone.State)

var apiMilestones []structs.Milestone
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&token=%s", owner.Name, repo.Name, "all", token))
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiMilestones)
assert.Len(t, apiMilestones, 4)

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))
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiMilestones)
assert.Len(t, apiMilestones, 1)
assert.Equal(t, int64(2), apiMilestones[0].ID)

req = NewRequest(t, "DELETE", fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, apiMilestone.ID, token))
resp = session.MakeRequest(t, req, http.StatusNoContent)
}
47 changes: 24 additions & 23 deletions models/issue_milestone.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,41 +330,38 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 {
return ids
}

// GetMilestonesByRepoID returns all opened milestones of a repository.
func GetMilestonesByRepoID(repoID int64, state api.StateType, listOptions ListOptions) (MilestoneList, error) {
sess := x.Where("repo_id = ?", repoID)
// GetMilestonesOption contain options to get milestones
type GetMilestonesOption struct {
ListOptions
RepoID int64
State api.StateType
Name string
SortType string
}

// GetMilestones returns milestones filtered by GetMilestonesOption's
func GetMilestones(opts GetMilestonesOption) (MilestoneList, error) {
sess := x.Where("repo_id = ?", opts.RepoID)

switch state {
switch opts.State {
case api.StateClosed:
sess = sess.And("is_closed = ?", true)

case api.StateAll:
break

case api.StateOpen:
fallthrough

// api.StateOpen:
default:
sess = sess.And("is_closed = ?", false)
}

if listOptions.Page != 0 {
sess = listOptions.setSessionPagination(sess)
if len(opts.Name) != 0 {
sess = sess.And(builder.Like{"name", opts.Name})
}

miles := make([]*Milestone, 0, listOptions.PageSize)
return miles, sess.Asc("deadline_unix").Asc("id").Find(&miles)
}

// GetMilestones returns a list of milestones of given repository and status.
func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (MilestoneList, error) {
miles := make([]*Milestone, 0, setting.UI.IssuePagingNum)
sess := x.Where("repo_id = ? AND is_closed = ?", repoID, isClosed)
if page > 0 {
sess = sess.Limit(setting.UI.IssuePagingNum, (page-1)*setting.UI.IssuePagingNum)
if opts.Page != 0 {
sess = opts.setSessionPagination(sess)
}

switch sortType {
switch opts.SortType {
case "furthestduedate":
sess.Desc("deadline_unix")
case "leastcomplete":
Expand All @@ -375,9 +372,13 @@ func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (Mile
sess.Asc("num_issues")
case "mostissues":
sess.Desc("num_issues")
case "id":
sess.Asc("id")
default:
sess.Asc("deadline_unix")
sess.Asc("deadline_unix").Asc("id")
}

miles := make([]*Milestone, 0, opts.PageSize)
return miles, sess.Find(&miles)
}

Expand Down
32 changes: 28 additions & 4 deletions models/issue_milestone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sort"
"testing"

"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"

Expand Down Expand Up @@ -49,7 +50,10 @@ func TestGetMilestonesByRepoID(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
test := func(repoID int64, state api.StateType) {
repo := AssertExistsAndLoadBean(t, &Repository{ID: repoID}).(*Repository)
milestones, err := GetMilestonesByRepoID(repo.ID, state, ListOptions{})
milestones, err := GetMilestones(GetMilestonesOption{
RepoID: repo.ID,
State: state,
})
assert.NoError(t, err)

var n int
Expand Down Expand Up @@ -83,7 +87,10 @@ func TestGetMilestonesByRepoID(t *testing.T) {
test(3, api.StateClosed)
test(3, api.StateAll)

milestones, err := GetMilestonesByRepoID(NonexistentID, api.StateOpen, ListOptions{})
milestones, err := GetMilestones(GetMilestonesOption{
RepoID: NonexistentID,
State: api.StateOpen,
})
assert.NoError(t, err)
assert.Len(t, milestones, 0)
}
Expand All @@ -93,7 +100,15 @@ func TestGetMilestones(t *testing.T) {
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
test := func(sortType string, sortCond func(*Milestone) int) {
for _, page := range []int{0, 1} {
milestones, err := GetMilestones(repo.ID, page, false, sortType)
milestones, err := GetMilestones(GetMilestonesOption{
ListOptions: ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
State: api.StateOpen,
SortType: sortType,
})
assert.NoError(t, err)
assert.Len(t, milestones, repo.NumMilestones-repo.NumClosedMilestones)
values := make([]int, len(milestones))
Expand All @@ -102,7 +117,16 @@ func TestGetMilestones(t *testing.T) {
}
assert.True(t, sort.IntsAreSorted(values))

milestones, err = GetMilestones(repo.ID, page, true, sortType)
milestones, err = GetMilestones(GetMilestonesOption{
ListOptions: ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: repo.ID,
State: api.StateClosed,
Name: "",
SortType: sortType,
})
assert.NoError(t, err)
assert.Len(t, milestones, repo.NumClosedMilestones)
values = make([]int, len(milestones))
Expand Down
10 changes: 8 additions & 2 deletions modules/migrations/gitea_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,17 @@ func TestGiteaUploadRepo(t *testing.T) {
repo := models.AssertExistsAndLoadBean(t, &models.Repository{OwnerID: user.ID, Name: repoName}).(*models.Repository)
assert.True(t, repo.HasUncyclo())

milestones, err := models.GetMilestones(repo.ID, 0, false, "")
milestones, err := models.GetMilestones(models.GetMilestonesOption{
RepoID: repo.ID,
State: structs.StateOpen,
})
assert.NoError(t, err)
assert.EqualValues(t, 1, len(milestones))

milestones, err = models.GetMilestones(repo.ID, 0, true, "")
milestones, err = models.GetMilestones(models.GetMilestonesOption{
RepoID: repo.ID,
State: structs.StateClosed,
})
assert.NoError(t, err)
assert.EqualValues(t, 0, len(milestones))

Expand Down
13 changes: 11 additions & 2 deletions routers/api/v1/repo/milestone.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func ListMilestones(ctx *context.APIContext) {
// in: query
// description: Milestone state, Recognised values are open, closed and all. Defaults to "open"
// type: string
// - name: name
// in: query
// description: filter by milestone name
// type: string
// - name: page
// in: query
// description: page number of results to return (1-based)
Expand All @@ -51,9 +55,14 @@ func ListMilestones(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/MilestoneList"

milestones, err := models.GetMilestonesByRepoID(ctx.Repo.Repository.ID, api.StateType(ctx.Query("state")), utils.GetListOptions(ctx))
milestones, err := models.GetMilestones(models.GetMilestonesOption{
ListOptions: utils.GetListOptions(ctx),
RepoID: ctx.Repo.Repository.ID,
State: api.StateType(ctx.Query("state")),
Name: ctx.Query("name"),
})
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetMilestonesByRepoID", err)
ctx.Error(http.StatusInternalServerError, "GetMilestones", err)
return
}

Expand Down
17 changes: 13 additions & 4 deletions routers/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,11 @@ func Issues(ctx *context.Context) {
issues(ctx, ctx.QueryInt64("milestone"), util.OptionalBoolOf(isPullList))

var err error
// Get milestones.
ctx.Data["Milestones"], err = models.GetMilestonesByRepoID(ctx.Repo.Repository.ID, api.StateType(ctx.Query("state")), models.ListOptions{})
// Get milestones
ctx.Data["Milestones"], err = models.GetMilestones(models.GetMilestonesOption{
RepoID: ctx.Repo.Repository.ID,
State: api.StateType(ctx.Query("state")),
})
if err != nil {
ctx.ServerError("GetAllRepoMilestones", err)
return
Expand All @@ -375,12 +378,18 @@ func Issues(ctx *context.Context) {
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repository) {
var err error
ctx.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false, "")
ctx.Data["OpenMilestones"], err = models.GetMilestones(models.GetMilestonesOption{
RepoID: repo.ID,
State: api.StateOpen,
})
if err != nil {
ctx.ServerError("GetMilestones", err)
return
}
ctx.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true, "")
ctx.Data["ClosedMilestones"], err = models.GetMilestones(models.GetMilestonesOption{
RepoID: repo.ID,
State: api.StateClosed,
})
if err != nil {
ctx.ServerError("GetMilestones", err)
return
Expand Down
14 changes: 13 additions & 1 deletion routers/repo/milestone.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"

Expand Down Expand Up @@ -47,13 +48,24 @@ func Milestones(ctx *context.Context) {
}

var total int
var state structs.StateType
if !isShowClosed {
total = int(stats.OpenCount)
state = structs.StateOpen
} else {
total = int(stats.ClosedCount)
state = structs.StateClosed
}

miles, err := models.GetMilestones(ctx.Repo.Repository.ID, page, isShowClosed, sortType)
miles, err := models.GetMilestones(models.GetMilestonesOption{
ListOptions: models.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: ctx.Repo.Repository.ID,
State: state,
SortType: sortType,
})
if err != nil {
ctx.ServerError("GetMilestones", err)
return
Expand Down
6 changes: 6 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -6164,6 +6164,12 @@
"name": "state",
"in": "query"
},
{
"type": "string",
"description": "filter by milestone name",
"name": "name",
"in": "query"
},
{
"type": "integer",
"description": "page number of results to return (1-based)",
Expand Down