Skip to content

Commit 82661c1

Browse files
committed
Isolate pr list command
1 parent 558e3f3 commit 82661c1

16 files changed

Lines changed: 732 additions & 640 deletions

File tree

command/alias.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,8 @@ func aliasList(cmd *cobra.Command, args []string) error {
166166
return nil
167167
}
168168

169-
stdout := colorableOut(cmd)
170-
171-
tp := utils.NewTablePrinter(stdout)
169+
// TODO: connect to per-command io streams
170+
tp := utils.NewTablePrinter(defaultStreams)
172171

173172
aliasMap := aliasCfg.All()
174173
keys := []string{}

command/issue.go

Lines changed: 11 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package command
33
import (
44
"fmt"
55
"io"
6-
"net/url"
76
"strconv"
87
"strings"
98
"time"
@@ -122,57 +121,6 @@ var issueReopenCmd = &cobra.Command{
122121
RunE: issueReopen,
123122
}
124123

125-
type filterOptions struct {
126-
entity string
127-
state string
128-
assignee string
129-
labels []string
130-
author string
131-
baseBranch string
132-
mention string
133-
milestone string
134-
}
135-
136-
func listURLWithQuery(listURL string, options filterOptions) (string, error) {
137-
u, err := url.Parse(listURL)
138-
if err != nil {
139-
return "", err
140-
}
141-
query := fmt.Sprintf("is:%s ", options.entity)
142-
if options.state != "all" {
143-
query += fmt.Sprintf("is:%s ", options.state)
144-
}
145-
if options.assignee != "" {
146-
query += fmt.Sprintf("assignee:%s ", options.assignee)
147-
}
148-
for _, label := range options.labels {
149-
query += fmt.Sprintf("label:%s ", quoteValueForQuery(label))
150-
}
151-
if options.author != "" {
152-
query += fmt.Sprintf("author:%s ", options.author)
153-
}
154-
if options.baseBranch != "" {
155-
query += fmt.Sprintf("base:%s ", options.baseBranch)
156-
}
157-
if options.mention != "" {
158-
query += fmt.Sprintf("mentions:%s ", options.mention)
159-
}
160-
if options.milestone != "" {
161-
query += fmt.Sprintf("milestone:%s ", quoteValueForQuery(options.milestone))
162-
}
163-
q := u.Query()
164-
q.Set("q", strings.TrimSuffix(query, " "))
165-
u.RawQuery = q.Encode()
166-
return u.String(), nil
167-
}
168-
169-
func quoteValueForQuery(v string) string {
170-
if strings.ContainsAny(v, " \"\t\r\n") {
171-
return fmt.Sprintf("%q", v)
172-
}
173-
return v
174-
}
175-
176124
func issueList(cmd *cobra.Command, args []string) error {
177125
ctx := contextForCommand(cmd)
178126
apiClient, err := apiClientForContext(ctx)
@@ -230,14 +178,14 @@ func issueList(cmd *cobra.Command, args []string) error {
230178

231179
if web {
232180
issueListURL := ghrepo.GenerateRepoURL(baseRepo, "issues")
233-
openURL, err := listURLWithQuery(issueListURL, filterOptions{
234-
entity: "issue",
235-
state: state,
236-
assignee: assignee,
237-
labels: labels,
238-
author: author,
239-
mention: mention,
240-
milestone: milestone,
181+
openURL, err := shared.ListURLWithQuery(issueListURL, shared.FilterOptions{
182+
Entity: "issue",
183+
State: state,
184+
Assignee: assignee,
185+
Labels: labels,
186+
Author: author,
187+
Mention: mention,
188+
Milestone: milestone,
241189
})
242190
if err != nil {
243191
return err
@@ -259,7 +207,7 @@ func issueList(cmd *cobra.Command, args []string) error {
259207
}
260208
})
261209

262-
title := listHeader(ghrepo.FullName(baseRepo), "issue", len(listResult.Issues), listResult.TotalCount, hasFilters)
210+
title := shared.ListHeader(ghrepo.FullName(baseRepo), "issue", len(listResult.Issues), listResult.TotalCount, hasFilters)
263211
if connectedToTerminal(cmd) {
264212
fmt.Fprintf(colorableErr(cmd), "\n%s\n\n", title)
265213
}
@@ -362,25 +310,6 @@ func issueStateTitleWithColor(state string) string {
362310
return colorFunc(strings.Title(strings.ToLower(state)))
363311
}
364312

365-
func listHeader(repoName string, itemName string, matchCount int, totalMatchCount int, hasFilters bool) string {
366-
if totalMatchCount == 0 {
367-
if hasFilters {
368-
return fmt.Sprintf("No %ss match your search in %s", itemName, repoName)
369-
}
370-
return fmt.Sprintf("There are no open %ss in %s", itemName, repoName)
371-
}
372-
373-
if hasFilters {
374-
matchVerb := "match"
375-
if totalMatchCount == 1 {
376-
matchVerb = "matches"
377-
}
378-
return fmt.Sprintf("Showing %d of %s in %s that %s your search", matchCount, utils.Pluralize(totalMatchCount, itemName), repoName, matchVerb)
379-
}
380-
381-
return fmt.Sprintf("Showing %d of %s in %s", matchCount, utils.Pluralize(totalMatchCount, fmt.Sprintf("open %s", itemName)), repoName)
382-
}
383-
384313
func printRawIssuePreview(out io.Writer, issue *api.Issue) error {
385314
assignees := issueAssigneeList(*issue)
386315
labels := issueLabelList(*issue)
@@ -619,7 +548,8 @@ func issueCreate(cmd *cobra.Command, args []string) error {
619548
}
620549

621550
func printIssues(w io.Writer, prefix string, totalCount int, issues []api.Issue) {
622-
table := utils.NewTablePrinter(w)
551+
// TODO: accept io streams via argument
552+
table := utils.NewTablePrinter(defaultStreams)
623553
for _, issue := range issues {
624554
issueNum := strconv.Itoa(issue.Number)
625555
if table.IsTTY() {

command/issue_test.go

Lines changed: 0 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -803,117 +803,6 @@ func TestIssueCreate_webTitleBody(t *testing.T) {
803803
eq(t, output.String(), "Opening github.com/OWNER/REPO/issues/new in your browser.\n")
804804
}
805805

806-
func Test_listHeader(t *testing.T) {
807-
type args struct {
808-
repoName string
809-
itemName string
810-
matchCount int
811-
totalMatchCount int
812-
hasFilters bool
813-
}
814-
tests := []struct {
815-
name string
816-
args args
817-
want string
818-
}{
819-
{
820-
name: "no results",
821-
args: args{
822-
repoName: "REPO",
823-
itemName: "table",
824-
matchCount: 0,
825-
totalMatchCount: 0,
826-
hasFilters: false,
827-
},
828-
want: "There are no open tables in REPO",
829-
},
830-
{
831-
name: "no matches after filters",
832-
args: args{
833-
repoName: "REPO",
834-
itemName: "Luftballon",
835-
matchCount: 0,
836-
totalMatchCount: 0,
837-
hasFilters: true,
838-
},
839-
want: "No Luftballons match your search in REPO",
840-
},
841-
{
842-
name: "one result",
843-
args: args{
844-
repoName: "REPO",
845-
itemName: "genie",
846-
matchCount: 1,
847-
totalMatchCount: 23,
848-
hasFilters: false,
849-
},
850-
want: "Showing 1 of 23 open genies in REPO",
851-
},
852-
{
853-
name: "one result after filters",
854-
args: args{
855-
repoName: "REPO",
856-
itemName: "tiny cup",
857-
matchCount: 1,
858-
totalMatchCount: 23,
859-
hasFilters: true,
860-
},
861-
want: "Showing 1 of 23 tiny cups in REPO that match your search",
862-
},
863-
{
864-
name: "one result in total",
865-
args: args{
866-
repoName: "REPO",
867-
itemName: "chip",
868-
matchCount: 1,
869-
totalMatchCount: 1,
870-
hasFilters: false,
871-
},
872-
want: "Showing 1 of 1 open chip in REPO",
873-
},
874-
{
875-
name: "one result in total after filters",
876-
args: args{
877-
repoName: "REPO",
878-
itemName: "spicy noodle",
879-
matchCount: 1,
880-
totalMatchCount: 1,
881-
hasFilters: true,
882-
},
883-
want: "Showing 1 of 1 spicy noodle in REPO that matches your search",
884-
},
885-
{
886-
name: "multiple results",
887-
args: args{
888-
repoName: "REPO",
889-
itemName: "plant",
890-
matchCount: 4,
891-
totalMatchCount: 23,
892-
hasFilters: false,
893-
},
894-
want: "Showing 4 of 23 open plants in REPO",
895-
},
896-
{
897-
name: "multiple results after filters",
898-
args: args{
899-
repoName: "REPO",
900-
itemName: "boomerang",
901-
matchCount: 4,
902-
totalMatchCount: 23,
903-
hasFilters: true,
904-
},
905-
want: "Showing 4 of 23 boomerangs in REPO that match your search",
906-
},
907-
}
908-
for _, tt := range tests {
909-
t.Run(tt.name, func(t *testing.T) {
910-
if got := listHeader(tt.args.repoName, tt.args.itemName, tt.args.matchCount, tt.args.totalMatchCount, tt.args.hasFilters); got != tt.want {
911-
t.Errorf("listHeader() = %v, want %v", got, tt.want)
912-
}
913-
})
914-
}
915-
}
916-
917806
func TestIssueStateTitleWithColor(t *testing.T) {
918807
tests := map[string]struct {
919808
state string
@@ -1071,71 +960,3 @@ func TestIssueReopen_issuesDisabled(t *testing.T) {
1071960
t.Fatalf("got error: %v", err)
1072961
}
1073962
}
1074-
1075-
func Test_listURLWithQuery(t *testing.T) {
1076-
type args struct {
1077-
listURL string
1078-
options filterOptions
1079-
}
1080-
tests := []struct {
1081-
name string
1082-
args args
1083-
want string
1084-
wantErr bool
1085-
}{
1086-
{
1087-
name: "blank",
1088-
args: args{
1089-
listURL: "https://example.com/path?a=b",
1090-
options: filterOptions{
1091-
entity: "issue",
1092-
state: "open",
1093-
},
1094-
},
1095-
want: "https://example.com/path?a=b&q=is%3Aissue+is%3Aopen",
1096-
wantErr: false,
1097-
},
1098-
{
1099-
name: "all",
1100-
args: args{
1101-
listURL: "https://example.com/path",
1102-
options: filterOptions{
1103-
entity: "issue",
1104-
state: "open",
1105-
assignee: "bo",
1106-
author: "ka",
1107-
baseBranch: "trunk",
1108-
mention: "nu",
1109-
},
1110-
},
1111-
want: "https://example.com/path?q=is%3Aissue+is%3Aopen+assignee%3Abo+author%3Aka+base%3Atrunk+mentions%3Anu",
1112-
wantErr: false,
1113-
},
1114-
{
1115-
name: "spaces in values",
1116-
args: args{
1117-
listURL: "https://example.com/path",
1118-
options: filterOptions{
1119-
entity: "pr",
1120-
state: "open",
1121-
labels: []string{"docs", "help wanted"},
1122-
milestone: `Codename "What Was Missing"`,
1123-
},
1124-
},
1125-
want: "https://example.com/path?q=is%3Apr+is%3Aopen+label%3Adocs+label%3A%22help+wanted%22+milestone%3A%22Codename+%5C%22What+Was+Missing%5C%22%22",
1126-
wantErr: false,
1127-
},
1128-
}
1129-
for _, tt := range tests {
1130-
t.Run(tt.name, func(t *testing.T) {
1131-
got, err := listURLWithQuery(tt.args.listURL, tt.args.options)
1132-
if (err != nil) != tt.wantErr {
1133-
t.Errorf("listURLWithQuery() error = %v, wantErr %v", err, tt.wantErr)
1134-
return
1135-
}
1136-
if got != tt.want {
1137-
t.Errorf("listURLWithQuery() = %v, want %v", got, tt.want)
1138-
}
1139-
})
1140-
}
1141-
}

0 commit comments

Comments
 (0)