[API] Issue Search Add filter for MilestoneNames (#16173)
This commit is contained in:
parent
fdf9ab11cd
commit
9469e14dc6
4 changed files with 40 additions and 1 deletions
|
@ -222,6 +222,20 @@ func TestAPISearchIssues(t *testing.T) {
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &apiIssues)
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
assert.Len(t, apiIssues, 1)
|
assert.Len(t, apiIssues, 1)
|
||||||
|
|
||||||
|
query = url.Values{"milestones": {"milestone1"}, "state": {"all"}}
|
||||||
|
link.RawQuery = query.Encode()
|
||||||
|
req = NewRequest(t, "GET", link.String())
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
|
assert.Len(t, apiIssues, 1)
|
||||||
|
|
||||||
|
query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}}
|
||||||
|
link.RawQuery = query.Encode()
|
||||||
|
req = NewRequest(t, "GET", link.String())
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &apiIssues)
|
||||||
|
assert.Len(t, apiIssues, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
func TestAPISearchIssuesWithLabels(t *testing.T) {
|
||||||
|
|
|
@ -1100,6 +1100,7 @@ type IssuesOptions struct {
|
||||||
LabelIDs []int64
|
LabelIDs []int64
|
||||||
IncludedLabelNames []string
|
IncludedLabelNames []string
|
||||||
ExcludedLabelNames []string
|
ExcludedLabelNames []string
|
||||||
|
IncludeMilestones []string
|
||||||
SortType string
|
SortType string
|
||||||
IssueIDs []int64
|
IssueIDs []int64
|
||||||
UpdatedAfterUnix int64
|
UpdatedAfterUnix int64
|
||||||
|
@ -1241,6 +1242,13 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
|
||||||
if len(opts.ExcludedLabelNames) > 0 {
|
if len(opts.ExcludedLabelNames) > 0 {
|
||||||
sess.And(builder.NotIn("issue.id", BuildLabelNamesIssueIDsCondition(opts.ExcludedLabelNames)))
|
sess.And(builder.NotIn("issue.id", BuildLabelNamesIssueIDsCondition(opts.ExcludedLabelNames)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(opts.IncludeMilestones) > 0 {
|
||||||
|
sess.In("issue.milestone_id",
|
||||||
|
builder.Select("id").
|
||||||
|
From("milestone").
|
||||||
|
Where(builder.In("name", opts.IncludeMilestones)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
|
func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
|
||||||
|
|
|
@ -42,6 +42,10 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
// in: query
|
// in: query
|
||||||
// description: comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded
|
// description: comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded
|
||||||
// type: string
|
// type: string
|
||||||
|
// - name: milestones
|
||||||
|
// in: query
|
||||||
|
// description: comma separated list of milestone names. Fetch only issues that have any of this milestones. Non existent are discarded
|
||||||
|
// type: string
|
||||||
// - name: q
|
// - name: q
|
||||||
// in: query
|
// in: query
|
||||||
// description: search string
|
// description: search string
|
||||||
|
@ -164,6 +168,12 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
includedLabelNames = strings.Split(labels, ",")
|
includedLabelNames = strings.Split(labels, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
milestones := strings.TrimSpace(ctx.Query("milestones"))
|
||||||
|
var includedMilestones []string
|
||||||
|
if len(milestones) > 0 {
|
||||||
|
includedMilestones = strings.Split(milestones, ",")
|
||||||
|
}
|
||||||
|
|
||||||
// this api is also used in UI,
|
// this api is also used in UI,
|
||||||
// so the default limit is set to fit UI needs
|
// so the default limit is set to fit UI needs
|
||||||
limit := ctx.QueryInt("limit")
|
limit := ctx.QueryInt("limit")
|
||||||
|
@ -175,7 +185,7 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
|
|
||||||
// Only fetch the issues if we either don't have a keyword or the search returned issues
|
// Only fetch the issues if we either don't have a keyword or the search returned issues
|
||||||
// This would otherwise return all issues if no issues were found by the search.
|
// This would otherwise return all issues if no issues were found by the search.
|
||||||
if len(keyword) == 0 || len(issueIDs) > 0 || len(includedLabelNames) > 0 {
|
if len(keyword) == 0 || len(issueIDs) > 0 || len(includedLabelNames) > 0 || len(includedMilestones) > 0 {
|
||||||
issuesOpt := &models.IssuesOptions{
|
issuesOpt := &models.IssuesOptions{
|
||||||
ListOptions: models.ListOptions{
|
ListOptions: models.ListOptions{
|
||||||
Page: ctx.QueryInt("page"),
|
Page: ctx.QueryInt("page"),
|
||||||
|
@ -185,6 +195,7 @@ func SearchIssues(ctx *context.APIContext) {
|
||||||
IsClosed: isClosed,
|
IsClosed: isClosed,
|
||||||
IssueIDs: issueIDs,
|
IssueIDs: issueIDs,
|
||||||
IncludedLabelNames: includedLabelNames,
|
IncludedLabelNames: includedLabelNames,
|
||||||
|
IncludeMilestones: includedMilestones,
|
||||||
SortType: "priorityrepo",
|
SortType: "priorityrepo",
|
||||||
PriorityRepoID: ctx.QueryInt64("priority_repo_id"),
|
PriorityRepoID: ctx.QueryInt64("priority_repo_id"),
|
||||||
IsPull: isPull,
|
IsPull: isPull,
|
||||||
|
|
|
@ -1876,6 +1876,12 @@
|
||||||
"name": "labels",
|
"name": "labels",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "comma separated list of milestone names. Fetch only issues that have any of this milestones. Non existent are discarded",
|
||||||
|
"name": "milestones",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "search string",
|
"description": "search string",
|
||||||
|
|
Reference in a new issue