@@ -2,41 +2,49 @@ package command
22
33import (
44 "fmt"
5+ "os"
56 "strconv"
67
78 "github.com/github/gh-cli/api"
89 "github.com/github/gh-cli/utils"
910 "github.com/spf13/cobra"
11+ "golang.org/x/crypto/ssh/terminal"
1012)
1113
1214func init () {
1315 RootCmd .AddCommand (prCmd )
14- prCmd .AddCommand (
15- & cobra.Command {
16- Use : "list" ,
17- Short : "List pull requests" ,
18- RunE : prList ,
19- },
20- & cobra.Command {
21- Use : "view [pr-number]" ,
22- Short : "Open a pull request in the browser" ,
23- RunE : prView ,
24- },
25- )
16+ prCmd .AddCommand (prListCmd )
17+ prCmd .AddCommand (prStatusCmd )
18+ prCmd .AddCommand (prViewCmd )
19+
20+ prListCmd .Flags ().IntP ("limit" , "L" , 30 , "maximum number of items to fetch" )
21+ prListCmd .Flags ().StringP ("state" , "s" , "open" , "filter by state" )
22+ prListCmd .Flags ().StringP ("base" , "b" , "" , "filter by base branch" )
23+ prListCmd .Flags ().StringArrayP ("label" , "l" , nil , "filter by label" )
2624}
2725
2826var prCmd = & cobra.Command {
2927 Use : "pr" ,
3028 Short : "Work with pull requests" ,
31- Long : `This command allows you to
32- work with pull requests.` ,
33- Args : cobra .MinimumNArgs (1 ),
34- RunE : func (cmd * cobra.Command , args []string ) error {
35- return fmt .Errorf ("%+v is not a valid PR command" , args )
36- },
29+ Long : `Helps you work with pull requests.` ,
30+ }
31+ var prListCmd = & cobra.Command {
32+ Use : "list" ,
33+ Short : "List pull requests" ,
34+ RunE : prList ,
35+ }
36+ var prStatusCmd = & cobra.Command {
37+ Use : "status" ,
38+ Short : "Show status of relevant pull requests" ,
39+ RunE : prStatus ,
40+ }
41+ var prViewCmd = & cobra.Command {
42+ Use : "view [pr-number]" ,
43+ Short : "Open a pull request in the browser" ,
44+ RunE : prView ,
3745}
3846
39- func prList (cmd * cobra.Command , args []string ) error {
47+ func prStatus (cmd * cobra.Command , args []string ) error {
4048 ctx := contextForCommand (cmd )
4149 apiClient , err := apiClientForContext (ctx )
4250 if err != nil {
@@ -89,6 +97,117 @@ func prList(cmd *cobra.Command, args []string) error {
8997 return nil
9098}
9199
100+ func prList (cmd * cobra.Command , args []string ) error {
101+ ctx := contextForCommand (cmd )
102+ apiClient , err := apiClientForContext (ctx )
103+ if err != nil {
104+ return err
105+ }
106+
107+ baseRepo , err := ctx .BaseRepo ()
108+ if err != nil {
109+ return err
110+ }
111+
112+ limit , err := cmd .Flags ().GetInt ("limit" )
113+ if err != nil {
114+ return err
115+ }
116+ state , err := cmd .Flags ().GetString ("state" )
117+ if err != nil {
118+ return err
119+ }
120+ baseBranch , err := cmd .Flags ().GetString ("base" )
121+ if err != nil {
122+ return err
123+ }
124+ labels , err := cmd .Flags ().GetStringArray ("label" )
125+ if err != nil {
126+ return err
127+ }
128+
129+ var graphqlState []string
130+ switch state {
131+ case "open" :
132+ graphqlState = []string {"OPEN" }
133+ case "closed" :
134+ graphqlState = []string {"CLOSED" }
135+ case "merged" :
136+ graphqlState = []string {"MERGED" }
137+ case "all" :
138+ graphqlState = []string {"OPEN" , "CLOSED" , "MERGED" }
139+ default :
140+ return fmt .Errorf ("invalid state: %s" , state )
141+ }
142+
143+ params := map [string ]interface {}{
144+ "owner" : baseRepo .RepoOwner (),
145+ "repo" : baseRepo .RepoName (),
146+ "state" : graphqlState ,
147+ }
148+ if len (labels ) > 0 {
149+ params ["labels" ] = labels
150+ }
151+ if baseBranch != "" {
152+ params ["baseBranch" ] = baseBranch
153+ }
154+
155+ prs , err := api .PullRequestList (apiClient , params , limit )
156+ if err != nil {
157+ return err
158+ }
159+
160+ tty := false
161+ ttyWidth := 80
162+ out := cmd .OutOrStdout ()
163+ if outFile , isFile := out .(* os.File ); isFile {
164+ fd := int (outFile .Fd ())
165+ tty = terminal .IsTerminal (fd )
166+ if w , _ , err := terminal .GetSize (fd ); err == nil {
167+ ttyWidth = w
168+ }
169+ }
170+
171+ numWidth := 0
172+ maxTitleWidth := 0
173+ for _ , pr := range prs {
174+ numLen := len (strconv .Itoa (pr .Number )) + 1
175+ if numLen > numWidth {
176+ numWidth = numLen
177+ }
178+ if len (pr .Title ) > maxTitleWidth {
179+ maxTitleWidth = len (pr .Title )
180+ }
181+ }
182+
183+ branchWidth := 40
184+ titleWidth := ttyWidth - branchWidth - 2 - numWidth - 2
185+
186+ if maxTitleWidth < titleWidth {
187+ branchWidth += titleWidth - maxTitleWidth
188+ titleWidth = maxTitleWidth
189+ }
190+
191+ for _ , pr := range prs {
192+ if tty {
193+ prNum := fmt .Sprintf ("% *s" , numWidth , fmt .Sprintf ("#%d" , pr .Number ))
194+ switch pr .State {
195+ case "OPEN" :
196+ prNum = utils .Green (prNum )
197+ case "CLOSED" :
198+ prNum = utils .Red (prNum )
199+ case "MERGED" :
200+ prNum = utils .Magenta (prNum )
201+ }
202+ prBranch := utils .Cyan (truncate (branchWidth , pr .HeadRefName ))
203+ fmt .Fprintf (out , "%s %-*s %s\n " , prNum , titleWidth , truncate (titleWidth , pr .Title ), prBranch )
204+ } else {
205+ fmt .Fprintf (out , "%d\t %s\t %s\n " , pr .Number , pr .Title , pr .HeadRefName )
206+ }
207+ }
208+ return nil
209+ }
210+
92211func prView (cmd * cobra.Command , args []string ) error {
93212 ctx := contextForCommand (cmd )
94213 baseRepo , err := ctx .BaseRepo ()
@@ -129,7 +248,7 @@ func prView(cmd *cobra.Command, args []string) error {
129248
130249func printPrs (prs ... api.PullRequest ) {
131250 for _ , pr := range prs {
132- fmt .Printf (" #%d %s %s\n " , pr .Number , truncateTitle ( pr .Title , 50 ), utils .Cyan ("[" + pr .HeadRefName + "]" ))
251+ fmt .Printf (" #%d %s %s\n " , pr .Number , truncate ( 50 , pr .Title ), utils .Cyan ("[" + pr .HeadRefName + "]" ))
133252 }
134253}
135254
@@ -141,7 +260,7 @@ func printMessage(s string) {
141260 fmt .Println (utils .Gray (s ))
142261}
143262
144- func truncateTitle ( title string , maxLength int ) string {
263+ func truncate ( maxLength int , title string ) string {
145264 if len (title ) > maxLength {
146265 return title [0 :maxLength - 3 ] + "..."
147266 }
0 commit comments