X Tutup
Skip to content

Commit f791bbd

Browse files
g14amislav
authored andcommitted
add search feature in listing issues
1 parent 2ab073d commit f791bbd

File tree

6 files changed

+300
-54
lines changed

6 files changed

+300
-54
lines changed

api/queries_issue.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,113 @@ func IssueByNumber(client *Client, repo ghrepo.Interface, number int) (*Issue, e
453453
return &resp.Repository.Issue, nil
454454
}
455455

456+
func IssueSearch(client *Client, repo ghrepo.Interface, searchQuery string, limit int) (*IssuesAndTotalCount, error) {
457+
query :=
458+
`query IssueSearch($repoName: String!, $owner: String!, $type: SearchType!, $first: Int, $after: String, $searchQuery: String!) {
459+
repository(name: $repoName, owner: $owner) {
460+
hasIssuesEnabled
461+
}
462+
search(type: $type, first: $first, after: $after, query: $searchQuery) {
463+
issueCount
464+
edges {
465+
node {
466+
... on Issue {
467+
repository {
468+
hasIssuesEnabled
469+
}
470+
number
471+
title
472+
updatedAt
473+
state
474+
labels(first: 100) {
475+
nodes {
476+
name
477+
}
478+
}
479+
}
480+
}
481+
}
482+
pageInfo {
483+
hasNextPage
484+
endCursor
485+
}
486+
}
487+
}`
488+
489+
type response struct {
490+
Repository struct {
491+
HasIssuesEnabled bool
492+
}
493+
Search struct {
494+
IssueCount int
495+
Edges []struct {
496+
Node struct {
497+
Number int
498+
Title string
499+
State string
500+
UpdatedAt time.Time
501+
Labels Labels
502+
}
503+
}
504+
PageInfo struct {
505+
HasNextPage bool
506+
EndCursor string
507+
}
508+
}
509+
}
510+
511+
searchQuery = fmt.Sprintf("is:issue repo:%s/%s %s", repo.RepoOwner(), repo.RepoName(), searchQuery)
512+
513+
perPage := min(limit, 100)
514+
515+
variables := map[string]interface{}{
516+
"repoName": repo.RepoName(),
517+
"owner": repo.RepoOwner(),
518+
"type": "ISSUE",
519+
"first": perPage,
520+
"searchQuery": searchQuery,
521+
}
522+
523+
ic := IssuesAndTotalCount{}
524+
525+
loop:
526+
for {
527+
var resp response
528+
err := client.GraphQL(repo.RepoHost(), query, variables, &resp)
529+
if err != nil {
530+
return nil, err
531+
}
532+
533+
if !resp.Repository.HasIssuesEnabled {
534+
return nil, fmt.Errorf("the '%s' repository has disabled issues", ghrepo.FullName(repo))
535+
}
536+
537+
ic.TotalCount = resp.Search.IssueCount
538+
539+
for _, i := range resp.Search.Edges {
540+
ic.Issues = append(ic.Issues, Issue{
541+
Number: i.Node.Number,
542+
Title: i.Node.Title,
543+
State: i.Node.State,
544+
UpdatedAt: i.Node.UpdatedAt,
545+
Labels: i.Node.Labels,
546+
})
547+
if len(ic.Issues) == limit {
548+
break loop
549+
}
550+
}
551+
552+
if resp.Search.PageInfo.HasNextPage {
553+
variables["after"] = resp.Search.PageInfo.EndCursor
554+
variables["first"] = min(perPage, limit-len(resp.Search.Edges))
555+
} else {
556+
break
557+
}
558+
}
559+
560+
return &ic, nil
561+
}
562+
456563
func IssueClose(client *Client, repo ghrepo.Interface, issue Issue) error {
457564
var mutation struct {
458565
CloseIssue struct {

pkg/cmd/issue/list/fixtures/issueList.json

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,49 @@
66
"totalCount": 3,
77
"nodes": [
88
{
9-
"number": 1,
10-
"title": "number won",
11-
"url": "https://wow.com",
12-
"updatedAt": "2011-01-26T19:01:12Z",
13-
"labels": {
14-
"nodes": [
15-
{
16-
"name": "label"
17-
}
18-
],
19-
"totalCount": 1
20-
}
9+
"number": 1,
10+
"title": "number won",
11+
"url": "https://wow.com",
12+
"updatedAt": "2011-01-26T19:01:12Z",
13+
"labels": {
14+
"nodes": [
15+
{
16+
"name": "label"
17+
}
18+
],
19+
"totalCount": 1
20+
}
2121
},
2222
{
23-
"number": 2,
24-
"title": "number too",
25-
"url": "https://wow.com",
26-
"updatedAt": "2011-01-26T19:01:12Z",
27-
"labels": {
28-
"nodes": [
29-
{
30-
"name": "label"
31-
}
32-
],
33-
"totalCount": 1
34-
}
23+
"number": 2,
24+
"title": "number too",
25+
"url": "https://wow.com",
26+
"updatedAt": "2011-01-26T19:01:12Z",
27+
"labels": {
28+
"nodes": [
29+
{
30+
"name": "label"
31+
}
32+
],
33+
"totalCount": 1
34+
}
3535
},
3636
{
37-
"number": 4,
38-
"title": "number fore",
39-
"url": "https://wow.com",
40-
"updatedAt": "2011-01-26T19:01:12Z",
41-
"labels": {
42-
"nodes": [
43-
{
44-
"name": "label"
45-
}
46-
],
47-
"totalCount": 1
48-
}
37+
"number": 4,
38+
"title": "number fore",
39+
"url": "https://wow.com",
40+
"updatedAt": "2011-01-26T19:01:12Z",
41+
"labels": {
42+
"nodes": [
43+
{
44+
"name": "label"
45+
}
46+
],
47+
"totalCount": 1
48+
}
4949
}
5050
]
5151
}
5252
}
5353
}
54-
}
54+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"data": {
3+
"repository": {
4+
"hasIssuesEnabled": true
5+
},
6+
"search": {
7+
"issueCount": 3,
8+
"edges": [
9+
{
10+
"node": {
11+
"number": 1,
12+
"title": "number won",
13+
"url": "https://wow.com",
14+
"updatedAt": "2011-01-26T19:01:12Z",
15+
"labels": {
16+
"nodes": [
17+
{
18+
"name": "label"
19+
}
20+
],
21+
"totalCount": 1
22+
}
23+
}
24+
},
25+
{
26+
"node": {
27+
"number": 2,
28+
"title": "number too",
29+
"url": "https://wow.com",
30+
"updatedAt": "2011-01-26T19:01:12Z",
31+
"labels": {
32+
"nodes": [
33+
{
34+
"name": "label"
35+
}
36+
],
37+
"totalCount": 1
38+
}
39+
}
40+
},
41+
{
42+
"node": {
43+
"number": 4,
44+
"title": "number fore",
45+
"url": "https://wow.com",
46+
"updatedAt": "2011-01-26T19:01:12Z",
47+
"labels": {
48+
"nodes": [
49+
{
50+
"name": "label"
51+
}
52+
],
53+
"totalCount": 1
54+
}
55+
}
56+
}
57+
]
58+
}
59+
}
60+
}

pkg/cmd/issue/list/list.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type ListOptions struct {
3232
Author string
3333
Mention string
3434
Milestone string
35+
Search string
3536
}
3637

3738
func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Command {
@@ -50,6 +51,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
5051
$ gh issue list -a @me
5152
$ gh issue list --web
5253
$ gh issue list --milestone 'MVP'
54+
$ gh issue list --search "error no:assignee sort:created-asc"
5355
`),
5456
Args: cmdutil.NoArgsQuoteReminder,
5557
RunE: func(cmd *cobra.Command, args []string) error {
@@ -75,7 +77,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*ListOptions) error) *cobra.Comman
7577
cmd.Flags().StringVarP(&opts.Author, "author", "A", "", "Filter by author")
7678
cmd.Flags().StringVar(&opts.Mention, "mention", "", "Filter by mention")
7779
cmd.Flags().StringVarP(&opts.Milestone, "milestone", "m", "", "Filter by milestone `number` or `title`")
78-
80+
cmd.Flags().StringVarP(&opts.Search, "search", "S", "", "Search issues with filter")
7981
return cmd
8082
}
8183

@@ -107,29 +109,44 @@ func listRun(opts *ListOptions) error {
107109
return err
108110
}
109111

112+
filterOptions := prShared.FilterOptions{
113+
Entity: "issue",
114+
State: opts.State,
115+
Assignee: filterAssignee,
116+
Labels: opts.Labels,
117+
Author: filterAuthor,
118+
Mention: filterMention,
119+
Milestone: opts.Milestone,
120+
Search: opts.Search,
121+
}
122+
110123
if opts.WebMode {
111124
issueListURL := ghrepo.GenerateRepoURL(baseRepo, "issues")
112-
openURL, err := prShared.ListURLWithQuery(issueListURL, prShared.FilterOptions{
113-
Entity: "issue",
114-
State: opts.State,
115-
Assignee: filterAssignee,
116-
Labels: opts.Labels,
117-
Author: filterAuthor,
118-
Mention: filterMention,
119-
Milestone: opts.Milestone,
120-
})
125+
openURL, err := prShared.ListURLWithQuery(issueListURL, filterOptions)
121126
if err != nil {
122127
return err
123128
}
129+
124130
if isTerminal {
125131
fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", utils.DisplayURL(openURL))
126132
}
127133
return utils.OpenInBrowser(openURL)
128134
}
129135

130-
listResult, err := api.IssueList(apiClient, baseRepo, opts.State, opts.Labels, filterAssignee, opts.LimitResults, filterAuthor, filterMention, opts.Milestone)
131-
if err != nil {
132-
return err
136+
searchQuery := prShared.IssueSearchBuild(filterOptions)
137+
138+
var listResult *api.IssuesAndTotalCount
139+
140+
if opts.Search != "" {
141+
listResult, err = api.IssueSearch(apiClient, baseRepo, searchQuery, opts.LimitResults)
142+
if err != nil {
143+
return err
144+
}
145+
} else {
146+
listResult, err = api.IssueList(apiClient, baseRepo, opts.State, opts.Labels, filterAssignee, opts.LimitResults, filterAuthor, filterMention, opts.Milestone)
147+
if err != nil {
148+
return err
149+
}
133150
}
134151

135152
err = opts.IO.StartPager()

0 commit comments

Comments
 (0)
X Tutup