💅 cleanup switching to search mode in issue list
This commit is contained in:
parent
f791bbdbcb
commit
80035aa686
5 changed files with 396 additions and 269 deletions
|
|
@ -454,37 +454,20 @@ func IssueByNumber(client *Client, repo ghrepo.Interface, number int) (*Issue, e
|
|||
}
|
||||
|
||||
func IssueSearch(client *Client, repo ghrepo.Interface, searchQuery string, limit int) (*IssuesAndTotalCount, error) {
|
||||
query :=
|
||||
`query IssueSearch($repoName: String!, $owner: String!, $type: SearchType!, $first: Int, $after: String, $searchQuery: String!) {
|
||||
repository(name: $repoName, owner: $owner) {
|
||||
query := fragments +
|
||||
`query IssueSearch($repo: String!, $owner: String!, $type: SearchType!, $limit: Int, $after: String, $query: String!) {
|
||||
repository(name: $repo, owner: $owner) {
|
||||
hasIssuesEnabled
|
||||
}
|
||||
search(type: $type, first: $first, after: $after, query: $searchQuery) {
|
||||
search(type: $type, last: $limit, after: $after, query: $query) {
|
||||
issueCount
|
||||
edges {
|
||||
node {
|
||||
... on Issue {
|
||||
repository {
|
||||
hasIssuesEnabled
|
||||
}
|
||||
number
|
||||
title
|
||||
updatedAt
|
||||
state
|
||||
labels(first: 100) {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes { ...issue }
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}`
|
||||
}`
|
||||
|
||||
type response struct {
|
||||
Repository struct {
|
||||
|
|
@ -492,32 +475,23 @@ func IssueSearch(client *Client, repo ghrepo.Interface, searchQuery string, limi
|
|||
}
|
||||
Search struct {
|
||||
IssueCount int
|
||||
Edges []struct {
|
||||
Node struct {
|
||||
Number int
|
||||
Title string
|
||||
State string
|
||||
UpdatedAt time.Time
|
||||
Labels Labels
|
||||
}
|
||||
}
|
||||
PageInfo struct {
|
||||
Nodes []Issue
|
||||
PageInfo struct {
|
||||
HasNextPage bool
|
||||
EndCursor string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
searchQuery = fmt.Sprintf("is:issue repo:%s/%s %s", repo.RepoOwner(), repo.RepoName(), searchQuery)
|
||||
|
||||
perPage := min(limit, 100)
|
||||
searchQuery = fmt.Sprintf("repo:%s/%s %s", repo.RepoOwner(), repo.RepoName(), searchQuery)
|
||||
|
||||
variables := map[string]interface{}{
|
||||
"repoName": repo.RepoName(),
|
||||
"owner": repo.RepoOwner(),
|
||||
"type": "ISSUE",
|
||||
"first": perPage,
|
||||
"searchQuery": searchQuery,
|
||||
"owner": repo.RepoOwner(),
|
||||
"repo": repo.RepoName(),
|
||||
"type": "ISSUE",
|
||||
"limit": perPage,
|
||||
"query": searchQuery,
|
||||
}
|
||||
|
||||
ic := IssuesAndTotalCount{}
|
||||
|
|
@ -536,25 +510,18 @@ loop:
|
|||
|
||||
ic.TotalCount = resp.Search.IssueCount
|
||||
|
||||
for _, i := range resp.Search.Edges {
|
||||
ic.Issues = append(ic.Issues, Issue{
|
||||
Number: i.Node.Number,
|
||||
Title: i.Node.Title,
|
||||
State: i.Node.State,
|
||||
UpdatedAt: i.Node.UpdatedAt,
|
||||
Labels: i.Node.Labels,
|
||||
})
|
||||
for _, issue := range resp.Search.Nodes {
|
||||
ic.Issues = append(ic.Issues, issue)
|
||||
if len(ic.Issues) == limit {
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
if resp.Search.PageInfo.HasNextPage {
|
||||
variables["after"] = resp.Search.PageInfo.EndCursor
|
||||
variables["first"] = min(perPage, limit-len(resp.Search.Edges))
|
||||
} else {
|
||||
if !resp.Search.PageInfo.HasNextPage {
|
||||
break
|
||||
}
|
||||
variables["after"] = resp.Search.PageInfo.EndCursor
|
||||
variables["perPage"] = min(perPage, limit-len(ic.Issues))
|
||||
}
|
||||
|
||||
return &ic, nil
|
||||
|
|
|
|||
|
|
@ -5,56 +5,50 @@
|
|||
},
|
||||
"search": {
|
||||
"issueCount": 3,
|
||||
"edges": [
|
||||
"nodes": [
|
||||
{
|
||||
"node": {
|
||||
"number": 1,
|
||||
"title": "number won",
|
||||
"url": "https://wow.com",
|
||||
"updatedAt": "2011-01-26T19:01:12Z",
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "label"
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
"number": 1,
|
||||
"title": "number won",
|
||||
"url": "https://wow.com",
|
||||
"updatedAt": "2011-01-26T19:01:12Z",
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "label"
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"number": 2,
|
||||
"title": "number too",
|
||||
"url": "https://wow.com",
|
||||
"updatedAt": "2011-01-26T19:01:12Z",
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "label"
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
"number": 2,
|
||||
"title": "number too",
|
||||
"url": "https://wow.com",
|
||||
"updatedAt": "2011-01-26T19:01:12Z",
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "label"
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"number": 4,
|
||||
"title": "number fore",
|
||||
"url": "https://wow.com",
|
||||
"updatedAt": "2011-01-26T19:01:12Z",
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "label"
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
"number": 4,
|
||||
"title": "number fore",
|
||||
"url": "https://wow.com",
|
||||
"updatedAt": "2011-01-26T19:01:12Z",
|
||||
"labels": {
|
||||
"nodes": [
|
||||
{
|
||||
"name": "label"
|
||||
}
|
||||
],
|
||||
"totalCount": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package list
|
|||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/api"
|
||||
|
|
@ -46,11 +47,11 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
|
|||
Use: "list",
|
||||
Short: "List and filter issues in this repository",
|
||||
Example: heredoc.Doc(`
|
||||
$ gh issue list -l "help wanted"
|
||||
$ gh issue list -l "bug" -l "help wanted"
|
||||
$ gh issue list -A monalisa
|
||||
$ gh issue list -a @me
|
||||
$ gh issue list --web
|
||||
$ gh issue list --milestone 'MVP'
|
||||
$ gh issue list --milestone "The big 1.0"
|
||||
$ gh issue list --search "error no:assignee sort:created-asc"
|
||||
`),
|
||||
Args: cmdutil.NoArgsQuoteReminder,
|
||||
|
|
@ -86,40 +87,25 @@ func listRun(opts *ListOptions) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apiClient := api.NewClientFromHTTP(httpClient)
|
||||
|
||||
baseRepo, err := opts.BaseRepo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isTerminal := opts.IO.IsStdoutTTY()
|
||||
|
||||
meReplacer := shared.NewMeReplacer(apiClient, baseRepo.RepoHost())
|
||||
filterAssignee, err := meReplacer.Replace(opts.Assignee)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filterAuthor, err := meReplacer.Replace(opts.Author)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filterMention, err := meReplacer.Replace(opts.Mention)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
filterOptions := prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: opts.State,
|
||||
Assignee: filterAssignee,
|
||||
Assignee: opts.Assignee,
|
||||
Labels: opts.Labels,
|
||||
Author: filterAuthor,
|
||||
Mention: filterMention,
|
||||
Author: opts.Author,
|
||||
Mention: opts.Mention,
|
||||
Milestone: opts.Milestone,
|
||||
Search: opts.Search,
|
||||
}
|
||||
|
||||
isTerminal := opts.IO.IsStdoutTTY()
|
||||
|
||||
if opts.WebMode {
|
||||
issueListURL := ghrepo.GenerateRepoURL(baseRepo, "issues")
|
||||
openURL, err := prShared.ListURLWithQuery(issueListURL, filterOptions)
|
||||
|
|
@ -133,20 +119,9 @@ func listRun(opts *ListOptions) error {
|
|||
return utils.OpenInBrowser(openURL)
|
||||
}
|
||||
|
||||
searchQuery := prShared.IssueSearchBuild(filterOptions)
|
||||
|
||||
var listResult *api.IssuesAndTotalCount
|
||||
|
||||
if opts.Search != "" {
|
||||
listResult, err = api.IssueSearch(apiClient, baseRepo, searchQuery, opts.LimitResults)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
listResult, err = api.IssueList(apiClient, baseRepo, opts.State, opts.Labels, filterAssignee, opts.LimitResults, filterAuthor, filterMention, opts.Milestone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listResult, err := issueList(httpClient, baseRepo, filterOptions, opts.LimitResults)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = opts.IO.StartPager()
|
||||
|
|
@ -156,7 +131,7 @@ func listRun(opts *ListOptions) error {
|
|||
defer opts.IO.StopPager()
|
||||
|
||||
if isTerminal {
|
||||
hasFilters := opts.State != "open" || len(opts.Labels) > 0 || opts.Assignee != "" || opts.Author != "" || opts.Mention != "" || opts.Milestone != ""
|
||||
hasFilters := opts.State != "open" || len(opts.Labels) > 0 || opts.Assignee != "" || opts.Author != "" || opts.Mention != "" || opts.Milestone != "" || opts.Search != ""
|
||||
title := prShared.ListHeader(ghrepo.FullName(baseRepo), "issue", len(listResult.Issues), listResult.TotalCount, hasFilters)
|
||||
fmt.Fprintf(opts.IO.Out, "\n%s\n\n", title)
|
||||
}
|
||||
|
|
@ -165,3 +140,46 @@ func listRun(opts *ListOptions) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func issueList(client *http.Client, repo ghrepo.Interface, filters prShared.FilterOptions, limit int) (*api.IssuesAndTotalCount, error) {
|
||||
apiClient := api.NewClientFromHTTP(client)
|
||||
|
||||
if filters.Search != "" {
|
||||
if milestoneNumber, err := strconv.ParseInt(filters.Milestone, 10, 32); err == nil {
|
||||
milestone, err := api.MilestoneByNumber(apiClient, repo, int32(milestoneNumber))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filters.Milestone = milestone.Title
|
||||
}
|
||||
|
||||
searchQuery := prShared.IssueSearchBuild(filters)
|
||||
return api.IssueSearch(apiClient, repo, searchQuery, limit)
|
||||
}
|
||||
|
||||
meReplacer := shared.NewMeReplacer(apiClient, repo.RepoHost())
|
||||
filterAssignee, err := meReplacer.Replace(filters.Assignee)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filterAuthor, err := meReplacer.Replace(filters.Author)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filterMention, err := meReplacer.Replace(filters.Mention)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.IssueList(
|
||||
apiClient,
|
||||
repo,
|
||||
filters.State,
|
||||
filters.Labels,
|
||||
filterAssignee,
|
||||
limit,
|
||||
filterAuthor,
|
||||
filterMention,
|
||||
filters.Milestone,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package list
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
|
@ -13,6 +12,7 @@ import (
|
|||
"github.com/cli/cli/internal/config"
|
||||
"github.com/cli/cli/internal/ghrepo"
|
||||
"github.com/cli/cli/internal/run"
|
||||
prShared "github.com/cli/cli/pkg/cmd/pr/shared"
|
||||
"github.com/cli/cli/pkg/cmdutil"
|
||||
"github.com/cli/cli/pkg/httpmock"
|
||||
"github.com/cli/cli/pkg/iostreams"
|
||||
|
|
@ -148,31 +148,6 @@ No issues match your search in OWNER/REPO
|
|||
`, output.String())
|
||||
}
|
||||
|
||||
func TestIssueList_atMe(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query UserCurrent\b`),
|
||||
httpmock.StringResponse(`{"data": {"viewer": {"login": "monalisa"} } }`))
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, "monalisa", params["assignee"].(string))
|
||||
assert.Equal(t, "monalisa", params["author"].(string))
|
||||
assert.Equal(t, "monalisa", params["mention"].(string))
|
||||
}))
|
||||
|
||||
_, err := runCommand(http, true, "-a @me -A @me --mention @me")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `issue list`: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueList_withInvalidLimitFlag(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
|
@ -184,36 +159,6 @@ func TestIssueList_withInvalidLimitFlag(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIssueList_nullAssigneeLabels(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`),
|
||||
)
|
||||
|
||||
_, err := runCommand(http, true, "")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `issue list`: %v", err)
|
||||
}
|
||||
|
||||
bodyBytes, _ := ioutil.ReadAll(http.Requests[0].Body)
|
||||
reqBody := struct {
|
||||
Variables map[string]interface{}
|
||||
}{}
|
||||
_ = json.Unmarshal(bodyBytes, &reqBody)
|
||||
|
||||
_, assigneeDeclared := reqBody.Variables["assignee"]
|
||||
_, labelsDeclared := reqBody.Variables["labels"]
|
||||
assert.Equal(t, false, assigneeDeclared)
|
||||
assert.Equal(t, false, labelsDeclared)
|
||||
}
|
||||
|
||||
func TestIssueList_disabledIssues(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
|
@ -253,78 +198,6 @@ func TestIssueList_web(t *testing.T) {
|
|||
assert.Equal(t, "Opening github.com/OWNER/REPO/issues in your browser.\n", output.Stderr())
|
||||
}
|
||||
|
||||
func TestIssueList_milestoneNotFound(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query RepositoryMilestoneList\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": { "milestones": {
|
||||
"nodes": [{ "title":"1.x", "id": "MDk6TWlsZXN0b25lMTIzNDU=" }],
|
||||
"pageInfo": { "hasNextPage": false }
|
||||
} } } }
|
||||
`))
|
||||
|
||||
_, err := runCommand(http, true, "--milestone NotFound")
|
||||
if err == nil || err.Error() != `no milestone found with title "NotFound"` {
|
||||
t.Errorf("error running command `issue list`: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueList_milestoneByNumber(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query RepositoryMilestoneByNumber\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": { "milestone": {
|
||||
"id": "MDk6TWlsZXN0b25lMTIzNDU="
|
||||
} } } }
|
||||
`))
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, "12345", params["milestone"].(string)) // Database ID for the Milestone (see #1462)
|
||||
}))
|
||||
|
||||
_, err := runCommand(http, true, "--milestone 13")
|
||||
if err != nil {
|
||||
t.Fatalf("error running issue list: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssueList_Search_tty(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
||||
http.Register(
|
||||
httpmock.GraphQL(`query IssueSearch\b`),
|
||||
httpmock.FileResponse("./fixtures/issueSearch.json"))
|
||||
|
||||
output, err := runCommand(http, true, "--search \"auth bug\"")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `issue list`: %v", err)
|
||||
}
|
||||
|
||||
out := output.String()
|
||||
timeRE := regexp.MustCompile(`\d+ years`)
|
||||
out = timeRE.ReplaceAllString(out, "X years")
|
||||
|
||||
assert.Equal(t, heredoc.Doc(`
|
||||
|
||||
Showing 3 of 3 open issues in OWNER/REPO
|
||||
|
||||
#1 number won (label) about X years ago
|
||||
#2 number too (label) about X years ago
|
||||
#4 number fore (label) about X years ago
|
||||
`), out)
|
||||
}
|
||||
|
||||
func TestIssueList_Search_web(t *testing.T) {
|
||||
http := &httpmock.Registry{}
|
||||
defer http.Verify(t)
|
||||
|
|
@ -344,5 +217,280 @@ func TestIssueList_Search_web(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "", output.String())
|
||||
assert.Equal(t, "Opening github.com/OWNER/REPO/issues in your browser.\n", output.Stderr())
|
||||
|
||||
}
|
||||
|
||||
func Test_issueList(t *testing.T) {
|
||||
type args struct {
|
||||
repo ghrepo.Interface
|
||||
filters prShared.FilterOptions
|
||||
limit int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
httpStubs func(*httpmock.Registry)
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "default",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"states": []interface{}{"OPEN"},
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "milestone by number",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
Milestone: "13",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query RepositoryMilestoneByNumber\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": { "milestone": {
|
||||
"id": "MDk6TWlsZXN0b25lMTIzNDU="
|
||||
} } } }
|
||||
`))
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"states": []interface{}{"OPEN"},
|
||||
"milestone": "12345",
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "milestone by number with search",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
Milestone: "13",
|
||||
Search: "auth bug",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query RepositoryMilestoneByNumber\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": { "milestone": {
|
||||
"title": "Big 1.0",
|
||||
"id": "MDk6TWlsZXN0b25lMTIzNDU="
|
||||
} } } }
|
||||
`))
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueSearch\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": {
|
||||
"repository": { "hasIssuesEnabled": true },
|
||||
"search": {
|
||||
"issueCount": 0,
|
||||
"nodes": []
|
||||
}
|
||||
} }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"query": "repo:OWNER/REPO is:issue is:open milestone:\"Big 1.0\" auth bug",
|
||||
"type": "ISSUE",
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "milestone by title with search",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
Milestone: "Big 1.0",
|
||||
Search: "auth bug",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueSearch\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": {
|
||||
"repository": { "hasIssuesEnabled": true },
|
||||
"search": {
|
||||
"issueCount": 0,
|
||||
"nodes": []
|
||||
}
|
||||
} }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"query": "repo:OWNER/REPO is:issue is:open milestone:\"Big 1.0\" auth bug",
|
||||
"type": "ISSUE",
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "milestone by title",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
Milestone: "1.x",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query RepositoryMilestoneList\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "repository": { "milestones": {
|
||||
"nodes": [{ "title":"1.x", "id": "MDk6TWlsZXN0b25lMTIzNDU=" }],
|
||||
"pageInfo": { "hasNextPage": false }
|
||||
} } } }
|
||||
`))
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"states": []interface{}{"OPEN"},
|
||||
"milestone": "12345",
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "@me syntax",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
Author: "@me",
|
||||
Assignee: "@me",
|
||||
Mention: "@me",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query UserCurrent\b`),
|
||||
httpmock.StringResponse(`{"data": {"viewer": {"login": "monalisa"} } }`))
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueList\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": { "repository": {
|
||||
"hasIssuesEnabled": true,
|
||||
"issues": { "nodes": [] }
|
||||
} } }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"states": []interface{}{"OPEN"},
|
||||
"assignee": "monalisa",
|
||||
"author": "monalisa",
|
||||
"mention": "monalisa",
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "@me with search",
|
||||
args: args{
|
||||
limit: 30,
|
||||
repo: ghrepo.New("OWNER", "REPO"),
|
||||
filters: prShared.FilterOptions{
|
||||
Entity: "issue",
|
||||
State: "open",
|
||||
Author: "@me",
|
||||
Assignee: "@me",
|
||||
Mention: "@me",
|
||||
Search: "auth bug",
|
||||
},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query IssueSearch\b`),
|
||||
httpmock.GraphQLQuery(`
|
||||
{ "data": {
|
||||
"repository": { "hasIssuesEnabled": true },
|
||||
"search": {
|
||||
"issueCount": 0,
|
||||
"nodes": []
|
||||
}
|
||||
} }`, func(_ string, params map[string]interface{}) {
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"owner": "OWNER",
|
||||
"repo": "REPO",
|
||||
"limit": float64(30),
|
||||
"query": "repo:OWNER/REPO is:issue is:open assignee:@me author:@me mentions:@me auth bug",
|
||||
"type": "ISSUE",
|
||||
}, params)
|
||||
}))
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
httpreg := &httpmock.Registry{}
|
||||
defer httpreg.Verify(t)
|
||||
if tt.httpStubs != nil {
|
||||
tt.httpStubs(httpreg)
|
||||
}
|
||||
client := &http.Client{Transport: httpreg}
|
||||
_, err := issueList(client, tt.args.repo, tt.args.filters, tt.args.limit)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,17 +157,17 @@ func ListURLWithQuery(listURL string, options FilterOptions) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
query := IssueSearchBuild(options)
|
||||
|
||||
q := u.Query()
|
||||
q.Set("q", strings.TrimSuffix(query, " "))
|
||||
u.RawQuery = q.Encode()
|
||||
params := u.Query()
|
||||
params.Set("q", IssueSearchBuild(options))
|
||||
u.RawQuery = params.Encode()
|
||||
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func IssueSearchBuild(options FilterOptions) string {
|
||||
|
||||
query := fmt.Sprintf("is:%s ", options.Entity)
|
||||
|
||||
if options.State != "all" {
|
||||
query += fmt.Sprintf("is:%s ", options.State)
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ func IssueSearchBuild(options FilterOptions) string {
|
|||
query += fmt.Sprintf("author:%s ", options.Author)
|
||||
}
|
||||
if options.BaseBranch != "" {
|
||||
query += fmt.Sprintf("base:%s ", options.BaseBranch)
|
||||
query += fmt.Sprintf("base:%s ", quoteValueForQuery(options.BaseBranch))
|
||||
}
|
||||
if options.Mention != "" {
|
||||
query += fmt.Sprintf("mentions:%s ", options.Mention)
|
||||
|
|
@ -193,7 +193,7 @@ func IssueSearchBuild(options FilterOptions) string {
|
|||
query += options.Search
|
||||
}
|
||||
|
||||
return query
|
||||
return strings.TrimSpace(query)
|
||||
}
|
||||
|
||||
func quoteValueForQuery(v string) string {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue