From 024871ade60c619302430a2852018dcbd1b35b79 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Mon, 4 Feb 2019 16:20:44 +0100 Subject: [PATCH] Add label names as filter in issue search api (#5946) --- models/issue_label.go | 15 ++++++++++++++- models/issue_label_test.go | 24 ++++++++++++++++++++++++ routers/api/v1/repo/issue.go | 16 +++++++++++++++- templates/swagger/v1_json.tmpl | 6 ++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/models/issue_label.go b/models/issue_label.go index 6adb4eedc..3c593e72f 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -203,13 +203,26 @@ func GetLabelInRepoByName(repoID int64, labelName string) (*Label, error) { return getLabelInRepoByName(x, repoID, labelName) } +// GetLabelIDsInRepoByNames returns a list of labelIDs by names in a given +// repository. +// it silently ignores label names that do not belong to the repository. +func GetLabelIDsInRepoByNames(repoID int64, labelNames []string) ([]int64, error) { + labelIDs := make([]int64, 0, len(labelNames)) + return labelIDs, x.Table("label"). + Where("repo_id = ?", repoID). + In("name", labelNames). + Asc("name"). + Cols("id"). + Find(&labelIDs) +} + // GetLabelInRepoByID returns a label by ID in given repository. func GetLabelInRepoByID(repoID, labelID int64) (*Label, error) { return getLabelInRepoByID(x, repoID, labelID) } // GetLabelsInRepoByIDs returns a list of labels by IDs in given repository, -// it silently ignores label IDs that are not belong to the repository. +// it silently ignores label IDs that do not belong to the repository. func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) return labels, x. diff --git a/models/issue_label_test.go b/models/issue_label_test.go index aef3f70c0..d103778df 100644 --- a/models/issue_label_test.go +++ b/models/issue_label_test.go @@ -81,6 +81,30 @@ func TestGetLabelInRepoByName(t *testing.T) { assert.True(t, IsErrLabelNotExist(err)) } +func TestGetLabelInRepoByNames(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + labelIDs, err := GetLabelIDsInRepoByNames(1, []string{"label1", "label2"}) + assert.NoError(t, err) + + assert.Len(t, labelIDs, 2) + + assert.Equal(t, int64(1), labelIDs[0]) + assert.Equal(t, int64(2), labelIDs[1]) +} + +func TestGetLabelInRepoByNamesDiscardsNonExistentLabels(t *testing.T) { + assert.NoError(t, PrepareTestDatabase()) + // label3 doesn't exists.. See labels.yml + labelIDs, err := GetLabelIDsInRepoByNames(1, []string{"label1", "label2", "label3"}) + assert.NoError(t, err) + + assert.Len(t, labelIDs, 2) + + assert.Equal(t, int64(1), labelIDs[0]) + assert.Equal(t, int64(2), labelIDs[1]) + assert.NoError(t, err) +} + func TestGetLabelInRepoByID(t *testing.T) { assert.NoError(t, PrepareTestDatabase()) label, err := GetLabelInRepoByID(1, 1) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index fe0071594..1cb9c2f81 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -43,6 +43,10 @@ func ListIssues(ctx *context.APIContext) { // in: query // description: whether issue is open or closed // type: string + // - name: labels + // in: query + // description: comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded + // type: string // - name: page // in: query // description: page number of requested issues @@ -71,20 +75,30 @@ func ListIssues(ctx *context.APIContext) { keyword = "" } var issueIDs []int64 + var labelIDs []int64 var err error if len(keyword) > 0 { issueIDs, err = indexer.SearchIssuesByKeyword(ctx.Repo.Repository.ID, keyword) } + if splitted := strings.Split(ctx.Query("labels"), ","); len(splitted) > 0 { + labelIDs, err = models.GetLabelIDsInRepoByNames(ctx.Repo.Repository.ID, splitted) + if err != nil { + ctx.Error(500, "GetLabelIDsInRepoByNames", err) + return + } + } + // 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. - if len(keyword) == 0 || len(issueIDs) > 0 { + if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 { issues, err = models.Issues(&models.IssuesOptions{ RepoIDs: []int64{ctx.Repo.Repository.ID}, Page: ctx.QueryInt("page"), PageSize: setting.UI.IssuePagingNum, IsClosed: isClosed, IssueIDs: issueIDs, + LabelIDs: labelIDs, }) } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 0ce6b805f..bde496c7f 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2059,6 +2059,12 @@ "name": "state", "in": "query" }, + { + "type": "string", + "description": "comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded", + "name": "labels", + "in": "query" + }, { "type": "integer", "description": "page number of requested issues",