From 633c8c070b4e09eeb719600b4e1df51d3ec79772 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Wed, 20 Nov 2019 11:39:42 -0600 Subject: [PATCH 1/4] factor out title body prompting --- command/pr_create.go | 88 +++++------------------------- command/title_body_survey.go | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 75 deletions(-) create mode 100644 command/title_body_survey.go diff --git a/command/pr_create.go b/command/pr_create.go index c8d86f53a..8f635e306 100644 --- a/command/pr_create.go +++ b/command/pr_create.go @@ -5,7 +5,6 @@ import ( "os" "runtime" - "github.com/AlecAivazis/survey/v2" "github.com/github/gh-cli/api" "github.com/github/gh-cli/context" "github.com/github/gh-cli/git" @@ -55,86 +54,25 @@ func prCreate(cmd *cobra.Command, _ []string) error { interactive := title == "" || body == "" - inProgress := struct { - Body string - Title string - }{} - if interactive { - confirmed := false - editor := determineEditor() + tb, err := titleBodySurvey(cmd, title, body) + if err != nil { + return errors.Wrap(err, "could not collect title and/or body") + } - for !confirmed { - titleQuestion := &survey.Question{ - Name: "title", - Prompt: &survey.Input{ - Message: "PR Title", - Default: inProgress.Title, - }, - } - bodyQuestion := &survey.Question{ - Name: "body", - Prompt: &survey.Editor{ - Message: fmt.Sprintf("PR Body (%s)", editor), - FileName: "*.md", - Default: inProgress.Body, - AppendDefault: true, - Editor: editor, - }, - } + if tb == nil { + // editing was canceled, we can just leave + return nil + } - qs := []*survey.Question{} - if title == "" { - qs = append(qs, titleQuestion) - } - if body == "" { - qs = append(qs, bodyQuestion) - } - - err := survey.Ask(qs, &inProgress) - if err != nil { - return errors.Wrap(err, "could not prompt") - } - confirmAnswers := struct { - Confirmation string - }{} - confirmQs := []*survey.Question{ - { - Name: "confirmation", - Prompt: &survey.Select{ - Message: "Submit?", - Options: []string{ - "Yes", - "Edit", - "Cancel", - }, - }, - }, - } - - err = survey.Ask(confirmQs, &confirmAnswers) - if err != nil { - return errors.Wrap(err, "could not prompt") - } - - switch confirmAnswers.Confirmation { - case "Yes": - confirmed = true - case "Edit": - continue - case "Cancel": - cmd.Println("Discarding pull request") - return nil - } + if title == "" { + title = tb.Title + } + if body == "" { + body = tb.Body } } - if title == "" { - title = inProgress.Title - } - if body == "" { - body = inProgress.Body - } base, err := cmd.Flags().GetString("base") if err != nil { return errors.Wrap(err, "could not parse base") diff --git a/command/title_body_survey.go b/command/title_body_survey.go new file mode 100644 index 000000000..c1d62ed4a --- /dev/null +++ b/command/title_body_survey.go @@ -0,0 +1,102 @@ +package command + +import ( + "fmt" + "github.com/AlecAivazis/survey/v2" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +type titleBody struct { + Body string + Title string +} + +const _confirmed = 0 +const _unconfirmed = 1 +const _cancel = 2 + +func confirm() (int, error) { + confirmAnswers := struct { + Confirmation int + }{} + confirmQs := []*survey.Question{ + { + Name: "confirmation", + Prompt: &survey.Select{ + Message: "Submit?", + Options: []string{ + "Yes", + "Edit", + "Cancel", + }, + }, + }, + } + + err := survey.Ask(confirmQs, &confirmAnswers) + if err != nil { + return -1, errors.Wrap(err, "could not prompt") + } + + return confirmAnswers.Confirmation, nil +} + +func titleBodySurvey(cmd *cobra.Command, providedTitle string, providedBody string) (*titleBody, error) { + inProgress := titleBody{} + + confirmed := false + editor := determineEditor() + + for !confirmed { + titleQuestion := &survey.Question{ + Name: "title", + Prompt: &survey.Input{ + Message: "Title", + Default: inProgress.Title, + }, + } + bodyQuestion := &survey.Question{ + Name: "body", + Prompt: &survey.Editor{ + Message: fmt.Sprintf("Body (%s)", editor), + FileName: "*.md", + Default: inProgress.Body, + AppendDefault: true, + Editor: editor, + }, + } + + qs := []*survey.Question{} + if providedTitle == "" { + qs = append(qs, titleQuestion) + } + if providedBody == "" { + qs = append(qs, bodyQuestion) + } + + err := survey.Ask(qs, &inProgress) + if err != nil { + return nil, errors.Wrap(err, "could not prompt") + } + + confirmA, err := confirm() + if err != nil { + return nil, errors.Wrap(err, "unable to confirm") + } + switch confirmA { + case _confirmed: + confirmed = true + case _unconfirmed: + continue + case _cancel: + cmd.Println("Discarding.") + return nil, nil + default: + panic("reached unreachable case") + } + + } + + return &inProgress, nil +} From 88446276e834ff44fa089dbe8a523690bf8dc689 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Wed, 20 Nov 2019 11:54:42 -0600 Subject: [PATCH 2/4] use survey when creating issues --- command/issue.go | 65 +++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/command/issue.go b/command/issue.go index ace7ac2e3..5e84d604c 100644 --- a/command/issue.go +++ b/command/issue.go @@ -2,15 +2,14 @@ package command import ( "fmt" - "io/ioutil" "os" "strconv" "strings" "github.com/github/gh-cli/api" "github.com/github/gh-cli/utils" + "github.com/pkg/errors" "github.com/spf13/cobra" - "golang.org/x/crypto/ssh/terminal" ) func init() { @@ -29,7 +28,10 @@ func init() { }, ) issueCmd.AddCommand(issueCreateCmd) - issueCreateCmd.Flags().StringArrayP("message", "m", nil, "set title and body") + issueCreateCmd.Flags().StringP("title", "t", "", + "Supply a title. Will prompt for one otherwise.") + issueCreateCmd.Flags().StringP("body", "b", "", + "Supply a body. Will prompt for one otherwise.") issueCreateCmd.Flags().BoolP("web", "w", false, "open the web browser to create an issue") issueListCmd := &cobra.Command{ @@ -189,44 +191,39 @@ func issueCreate(cmd *cobra.Command, args []string) error { return utils.OpenInBrowser(openURL) } - var title string - var body string - - message, err := cmd.Flags().GetStringArray("message") - if err != nil { - return err - } - apiClient, err := apiClientForContext(ctx) if err != nil { return err } - if len(message) > 0 { - title = message[0] - body = strings.Join(message[1:], "\n\n") - } else { - // TODO: open the text editor for issue title & body - input := os.Stdin - if terminal.IsTerminal(int(input.Fd())) { - cmd.Println("Enter the issue title and body; press Enter + Ctrl-D when done:") - } - inputBytes, err := ioutil.ReadAll(input) - if err != nil { - return err - } - - parts := strings.SplitN(string(inputBytes), "\n\n", 2) - if len(parts) > 0 { - title = parts[0] - } - if len(parts) > 1 { - body = parts[1] - } + title, err := cmd.Flags().GetString("title") + if err != nil { + return errors.Wrap(err, "could not parse title") + } + body, err := cmd.Flags().GetString("body") + if err != nil { + return errors.Wrap(err, "could not parse body") } - if title == "" { - return fmt.Errorf("aborting due to empty title") + interactive := title == "" || body == "" + + if interactive { + tb, err := titleBodySurvey(cmd, title, body) + if err != nil { + return errors.Wrap(err, "could not collect title and/or body") + } + + if tb == nil { + // editing was canceled, we can just leave + return nil + } + + if title == "" { + title = tb.Title + } + if body == "" { + body = tb.Body + } } params := map[string]interface{}{ "title": title, From 84d393d54381aec04c879aaa0f4c170a529e71b0 Mon Sep 17 00:00:00 2001 From: vilmibm Date: Wed, 20 Nov 2019 11:57:17 -0600 Subject: [PATCH 3/4] fix issue create test --- command/issue_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/command/issue_test.go b/command/issue_test.go index 09a55609f..4c4b7e2f6 100644 --- a/command/issue_test.go +++ b/command/issue_test.go @@ -144,7 +144,7 @@ func TestIssueCreate(t *testing.T) { out := bytes.Buffer{} issueCreateCmd.SetOut(&out) - RootCmd.SetArgs([]string{"issue", "create", "-m", "hello", "-m", "ab", "-m", "cd"}) + RootCmd.SetArgs([]string{"issue", "create", "-t", "hello", "-b", "cash rules everything around me"}) _, err := RootCmd.ExecuteC() if err != nil { t.Errorf("error running command `issue create`: %v", err) @@ -164,7 +164,7 @@ func TestIssueCreate(t *testing.T) { eq(t, reqBody.Variables.Input.RepositoryID, "REPOID") eq(t, reqBody.Variables.Input.Title, "hello") - eq(t, reqBody.Variables.Input.Body, "ab\n\ncd") + eq(t, reqBody.Variables.Input.Body, "cash rules everything around me") eq(t, out.String(), "https://github.com/OWNER/REPO/issues/12\n") } From 619c42fc8701464537cb9e24d272542d1e7d8acc Mon Sep 17 00:00:00 2001 From: vilmibm Date: Mon, 25 Nov 2019 11:33:59 -0600 Subject: [PATCH 4/4] use iota --- command/title_body_survey.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/command/title_body_survey.go b/command/title_body_survey.go index c1d62ed4a..af4dc34e1 100644 --- a/command/title_body_survey.go +++ b/command/title_body_survey.go @@ -12,9 +12,11 @@ type titleBody struct { Title string } -const _confirmed = 0 -const _unconfirmed = 1 -const _cancel = 2 +const ( + _confirmed = iota + _unconfirmed = iota + _cancel = iota +) func confirm() (int, error) { confirmAnswers := struct {