@@ -2,17 +2,33 @@ package command
22
33import (
44 "fmt"
5+ "net/url"
6+ "os"
7+ "os/exec"
8+ "strconv"
59 "strings"
610
711 "github.com/github/gh-cli/api"
812 "github.com/github/gh-cli/git"
13+ "github.com/github/gh-cli/github"
914 "github.com/github/gh-cli/utils"
1015 "github.com/spf13/cobra"
1116)
1217
1318func init () {
1419 RootCmd .AddCommand (prCmd )
15- prCmd .AddCommand (prListCmd )
20+ prCmd .AddCommand (
21+ & cobra.Command {
22+ Use : "list" ,
23+ Short : "List pull requests" ,
24+ RunE : prList ,
25+ },
26+ & cobra.Command {
27+ Use : "view [pr-number]" ,
28+ Short : "Open a pull request in the browser" ,
29+ RunE : prView ,
30+ },
31+ )
1632}
1733
1834var prCmd = & cobra.Command {
@@ -21,20 +37,12 @@ var prCmd = &cobra.Command{
2137 Long : `This command allows you to
2238work with pull requests.` ,
2339 Args : cobra .MinimumNArgs (1 ),
24- Run : func (cmd * cobra.Command , args []string ) {
25- fmt .Println ("pr" )
26- },
27- }
28-
29- var prListCmd = & cobra.Command {
30- Use : "list" ,
31- Short : "List pull requests" ,
3240 RunE : func (cmd * cobra.Command , args []string ) error {
33- return ExecutePr ( )
41+ return fmt . Errorf ( "%+v is not a valid PR command" , args )
3442 },
3543}
3644
37- func ExecutePr ( ) error {
45+ func prList ( cmd * cobra. Command , args [] string ) error {
3846 prPayload , err := api .PullRequests ()
3947 if err != nil {
4048 return err
@@ -68,6 +76,29 @@ func ExecutePr() error {
6876 return nil
6977}
7078
79+ func prView (cmd * cobra.Command , args []string ) error {
80+ project := project ()
81+
82+ var openURL string
83+ if len (args ) > 0 {
84+ if prNumber , err := strconv .Atoi (args [0 ]); err == nil {
85+ openURL = project .WebURL ("" , "" , fmt .Sprintf ("pull/%d" , prNumber ))
86+ } else {
87+ return fmt .Errorf ("invalid pull request number: '%s'" , args [0 ])
88+ }
89+ } else {
90+ prPayload , err := api .PullRequests ()
91+ if err != nil || prPayload .CurrentPR == nil {
92+ branch := currentBranch ()
93+ return fmt .Errorf ("The [%s] branch has no open PRs" , branch )
94+ }
95+ openURL = prPayload .CurrentPR .URL
96+ }
97+
98+ fmt .Printf ("Opening %s in your browser.\n " , openURL )
99+ return openInBrowser (openURL )
100+ }
101+
71102func printPrs (prs ... api.PullRequest ) {
72103 for _ , pr := range prs {
73104 fmt .Printf (" #%d %s %s\n " , pr .Number , truncateTitle (pr .Title ), utils .Cyan ("[" + pr .HeadRefName + "]" ))
@@ -91,6 +122,17 @@ func truncateTitle(title string) string {
91122 return title
92123}
93124
125+ func openInBrowser (url string ) error {
126+ launcher , err := utils .BrowserLauncher ()
127+ if err != nil {
128+ return err
129+ }
130+ endingArgs := append (launcher [1 :], url )
131+ return exec .Command (launcher [0 ], endingArgs ... ).Run ()
132+ }
133+
134+ // The functions below should be replaced at some point by the context package
135+ // 🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨🧨
94136func currentBranch () string {
95137 currentBranch , err := git .Head ()
96138 if err != nil {
@@ -99,3 +141,30 @@ func currentBranch() string {
99141
100142 return strings .Replace (currentBranch , "refs/heads/" , "" , 1 )
101143}
144+
145+ func project () github.Project {
146+ if repoFromEnv := os .Getenv ("GH_REPO" ); repoFromEnv != "" {
147+ repoURL , err := url .Parse (fmt .Sprintf ("https://github.com/%s.git" , repoFromEnv ))
148+ if err != nil {
149+ panic (err )
150+ }
151+ project , err := github .NewProjectFromURL (repoURL )
152+ if err != nil {
153+ panic (err )
154+ }
155+ return * project
156+ }
157+
158+ remotes , err := github .Remotes ()
159+ if err != nil {
160+ panic (err )
161+ }
162+
163+ for _ , remote := range remotes {
164+ if project , err := remote .Project (); err == nil {
165+ return * project
166+ }
167+ }
168+
169+ panic ("Could not get the project. What is a project? I don't know, it's kind of like a git repository I think?" )
170+ }
0 commit comments