@@ -2,39 +2,46 @@ package command
22
33import (
44 "fmt"
5+ "io/ioutil"
6+ "os"
57 "strconv"
8+ "strings"
69
710 "github.com/github/gh-cli/api"
811 "github.com/github/gh-cli/utils"
912 "github.com/spf13/cobra"
13+ "golang.org/x/crypto/ssh/terminal"
1014)
1115
1216func init () {
13- var issueCmd = & cobra.Command {
14- Use : "issue" ,
15- Short : "Work with GitHub issues" ,
16- Long : `This command allows you to work with issues.` ,
17- Args : cobra .MinimumNArgs (1 ),
18- RunE : func (cmd * cobra.Command , args []string ) error {
19- return fmt .Errorf ("%+v is not a valid issue command" , args )
20- },
21- }
22-
17+ RootCmd .AddCommand (issueCmd )
2318 issueCmd .AddCommand (
2419 & cobra.Command {
2520 Use : "status" ,
26- Short : "Display issue status" ,
21+ Short : "Show status of relevant issues " ,
2722 RunE : issueList ,
2823 },
2924 & cobra.Command {
30- Use : "view [ issue-number] " ,
25+ Use : "view < issue-number> " ,
3126 Args : cobra .MinimumNArgs (1 ),
32- Short : "Open a issue in the browser" ,
27+ Short : "Open an issue in the browser" ,
3328 RunE : issueView ,
3429 },
3530 )
31+ issueCmd .AddCommand (issueCreateCmd )
32+ issueCreateCmd .Flags ().StringArrayP ("message" , "m" , nil , "set title and body" )
33+ issueCreateCmd .Flags ().BoolP ("web" , "w" , false , "open the web browser to create an issue" )
34+ }
3635
37- RootCmd .AddCommand (issueCmd )
36+ var issueCmd = & cobra.Command {
37+ Use : "issue" ,
38+ Short : "Work with GitHub issues" ,
39+ Long : `Helps you work with issues.` ,
40+ }
41+ var issueCreateCmd = & cobra.Command {
42+ Use : "create" ,
43+ Short : "Create a new issue" ,
44+ RunE : issueCreate ,
3845}
3946
4047func issueList (cmd * cobra.Command , args []string ) error {
@@ -107,6 +114,77 @@ func issueView(cmd *cobra.Command, args []string) error {
107114 return utils .OpenInBrowser (openURL )
108115}
109116
117+ func issueCreate (cmd * cobra.Command , args []string ) error {
118+ ctx := contextForCommand (cmd )
119+
120+ baseRepo , err := ctx .BaseRepo ()
121+ if err != nil {
122+ return err
123+ }
124+
125+ if isWeb , err := cmd .Flags ().GetBool ("web" ); err == nil && isWeb {
126+ // TODO: move URL generation into GitHubRepository
127+ openURL := fmt .Sprintf ("https://github.com/%s/%s/issues/new" , baseRepo .RepoOwner (), baseRepo .RepoName ())
128+ // TODO: figure out how to stub this in tests
129+ if stat , err := os .Stat (".github/ISSUE_TEMPLATE" ); err == nil && stat .IsDir () {
130+ openURL += "/choose"
131+ }
132+ return utils .OpenInBrowser (openURL )
133+ }
134+
135+ var title string
136+ var body string
137+
138+ message , err := cmd .Flags ().GetStringArray ("message" )
139+ if err != nil {
140+ return err
141+ }
142+
143+ apiClient , err := apiClientForContext (ctx )
144+ if err != nil {
145+ return err
146+ }
147+
148+ if len (message ) > 0 {
149+ title = message [0 ]
150+ body = strings .Join (message [1 :], "\n \n " )
151+ } else {
152+ // TODO: open the text editor for issue title & body
153+ input := os .Stdin
154+ if terminal .IsTerminal (int (input .Fd ())) {
155+ cmd .Println ("Enter the issue title and body; press Enter + Ctrl-D when done:" )
156+ }
157+ inputBytes , err := ioutil .ReadAll (input )
158+ if err != nil {
159+ return err
160+ }
161+
162+ parts := strings .SplitN (string (inputBytes ), "\n \n " , 2 )
163+ if len (parts ) > 0 {
164+ title = parts [0 ]
165+ }
166+ if len (parts ) > 1 {
167+ body = parts [1 ]
168+ }
169+ }
170+
171+ if title == "" {
172+ return fmt .Errorf ("aborting due to empty title" )
173+ }
174+ params := map [string ]interface {}{
175+ "title" : title ,
176+ "body" : body ,
177+ }
178+
179+ newIssue , err := api .IssueCreate (apiClient , baseRepo , params )
180+ if err != nil {
181+ return err
182+ }
183+
184+ fmt .Fprintln (cmd .OutOrStdout (), newIssue .URL )
185+ return nil
186+ }
187+
110188func printIssues (issues ... api.Issue ) {
111189 for _ , issue := range issues {
112190 fmt .Printf (" #%d %s\n " , issue .Number , truncate (70 , issue .Title ))
0 commit comments