diff --git a/pkg/cmd/issue/comment/comment.go b/pkg/cmd/issue/comment/comment.go index 5e73531fc..82099862a 100644 --- a/pkg/cmd/issue/comment/comment.go +++ b/pkg/cmd/issue/comment/comment.go @@ -13,18 +13,19 @@ import ( "github.com/cli/cli/pkg/cmd/issue/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" - "github.com/cli/cli/pkg/prompt" "github.com/cli/cli/pkg/surveyext" "github.com/cli/cli/utils" "github.com/spf13/cobra" ) type CommentOptions struct { - HttpClient func() (*http.Client, error) - Config func() (config.Config, error) - IO *iostreams.IOStreams - BaseRepo func() (ghrepo.Interface, error) - Edit func(string) (string, error) + HttpClient func() (*http.Client, error) + IO *iostreams.IOStreams + BaseRepo func() (ghrepo.Interface, error) + EditSurvey func() (string, error) + InputTypeSurvey func() (int, error) + ConfirmSubmitSurvey func() (bool, error) + OpenInBrowser func(string) error SelectorArg string Interactive bool @@ -40,12 +41,12 @@ const ( func NewCmdComment(f *cmdutil.Factory, runF func(*CommentOptions) error) *cobra.Command { opts := &CommentOptions{ - IO: f.IOStreams, - HttpClient: f.HttpClient, - Config: f.Config, - Edit: func(editorCommand string) (string, error) { - return surveyext.Edit(editorCommand, "*.md", "", f.IOStreams.In, f.IOStreams.Out, f.IOStreams.ErrOut, nil) - }, + IO: f.IOStreams, + HttpClient: f.HttpClient, + EditSurvey: editSurvey(f.Config, f.IOStreams), + InputTypeSurvey: inputTypeSurvey, + ConfirmSubmitSurvey: confirmSubmitSurvey, + OpenInBrowser: utils.OpenInBrowser, } var webMode bool @@ -96,6 +97,7 @@ func NewCmdComment(f *cmdutil.Factory, runF func(*CommentOptions) error) *cobra. return commentRun(opts) }, } + cmd.Flags().StringVarP(&opts.Body, "body", "b", "", "Supply a body. Will prompt for one otherwise.") cmd.Flags().BoolVarP(&editorMode, "editor", "e", false, "Add body using editor") cmd.Flags().BoolVarP(&webMode, "web", "w", false, "Add body in browser") @@ -116,7 +118,7 @@ func commentRun(opts *CommentOptions) error { } if opts.Interactive { - inputType, err := inputTypeSurvey() + inputType, err := opts.InputTypeSurvey() if err != nil { return err } @@ -129,13 +131,9 @@ func commentRun(opts *CommentOptions) error { if opts.IO.IsStdoutTTY() { fmt.Fprintf(opts.IO.ErrOut, "Opening %s in your browser.\n", utils.DisplayURL(openURL)) } - return utils.OpenInBrowser(openURL) + return opts.OpenInBrowser(openURL) case editor: - editorCommand, err := cmdutil.DetermineEditor(opts.Config) - if err != nil { - return err - } - body, err := opts.Edit(editorCommand) + body, err := opts.EditSurvey() if err != nil { return err } @@ -149,7 +147,7 @@ func commentRun(opts *CommentOptions) error { } if opts.Interactive { - cont, err := confirmSubmitSurvey() + cont, err := opts.ConfirmSubmitSurvey() if err != nil { return err } @@ -170,22 +168,32 @@ func commentRun(opts *CommentOptions) error { return nil } -func inputTypeSurvey() (int, error) { +var inputTypeSurvey = func() (int, error) { var inputType int inputTypeQuestion := &survey.Select{ Message: "Where do you want to draft your comment?", Options: []string{"Editor", "Web"}, } - err := prompt.SurveyAskOne(inputTypeQuestion, &inputType) + err := survey.AskOne(inputTypeQuestion, &inputType) return inputType, err } -func confirmSubmitSurvey() (bool, error) { +var confirmSubmitSurvey = func() (bool, error) { var confirm bool submit := &survey.Confirm{ Message: "Submit?", Default: true, } - err := prompt.SurveyAskOne(submit, &confirm) + err := survey.AskOne(submit, &confirm) return confirm, err } + +var editSurvey = func(cf func() (config.Config, error), io *iostreams.IOStreams) func() (string, error) { + return func() (string, error) { + editorCommand, err := cmdutil.DetermineEditor(cf) + if err != nil { + return "", err + } + return surveyext.Edit(editorCommand, "*.md", "", io.In, io.Out, io.ErrOut, nil) + } +} diff --git a/pkg/cmd/issue/comment/comment_test.go b/pkg/cmd/issue/comment/comment_test.go index cbca6eaab..442f99298 100644 --- a/pkg/cmd/issue/comment/comment_test.go +++ b/pkg/cmd/issue/comment/comment_test.go @@ -3,17 +3,12 @@ package comment import ( "bytes" "net/http" - "os/exec" "testing" - "github.com/cli/cli/internal/config" "github.com/cli/cli/internal/ghrepo" - "github.com/cli/cli/internal/run" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/httpmock" "github.com/cli/cli/pkg/iostreams" - "github.com/cli/cli/pkg/prompt" - "github.com/cli/cli/test" "github.com/google/shlex" "github.com/stretchr/testify/assert" ) @@ -155,69 +150,89 @@ func TestNewCmdComment(t *testing.T) { func Test_commentRun(t *testing.T) { tests := []struct { - name string - input *CommentOptions - testInputType int - stdout string - stderr string - wantsErr bool - errMsg string + name string + input *CommentOptions + httpStubs func(*testing.T, *httpmock.Registry) + stdout string + stderr string }{ { - name: "interactive web", - testInputType: web, + name: "interactive web", input: &CommentOptions{ SelectorArg: "123", Interactive: true, InputType: 0, Body: "", + + InputTypeSurvey: func() (int, error) { return web, nil }, + OpenInBrowser: func(string) error { return nil }, + }, + httpStubs: func(t *testing.T, reg *httpmock.Registry) { + mockIssueFromNumber(t, reg) }, stderr: "Opening github.com/OWNER/REPO/issues/123 in your browser.\n", }, { - name: "interactive editor", - testInputType: editor, + name: "interactive editor", input: &CommentOptions{ SelectorArg: "123", Interactive: true, InputType: 0, Body: "", - Edit: func(string) (string, error) { return "comment body", nil }, + + EditSurvey: func() (string, error) { return "comment body", nil }, + InputTypeSurvey: func() (int, error) { return editor, nil }, + ConfirmSubmitSurvey: func() (bool, error) { return true, nil }, + }, + httpStubs: func(t *testing.T, reg *httpmock.Registry) { + mockIssueFromNumber(t, reg) + mockCommentCreate(t, reg) }, stdout: "? Body \nhttps://github.com/OWNER/REPO/issues/123#issuecomment-456\n", }, { - name: "non-interactive web", - testInputType: web, + name: "non-interactive web", input: &CommentOptions{ SelectorArg: "123", Interactive: false, InputType: web, Body: "", + + OpenInBrowser: func(string) error { return nil }, + }, + httpStubs: func(t *testing.T, reg *httpmock.Registry) { + mockIssueFromNumber(t, reg) }, stderr: "Opening github.com/OWNER/REPO/issues/123 in your browser.\n", }, { - name: "non-interactive editor", - testInputType: editor, + name: "non-interactive editor", input: &CommentOptions{ SelectorArg: "123", Interactive: false, InputType: editor, Body: "", - Edit: func(string) (string, error) { return "comment body", nil }, + + EditSurvey: func() (string, error) { return "comment body", nil }, + }, + httpStubs: func(t *testing.T, reg *httpmock.Registry) { + mockIssueFromNumber(t, reg) + mockCommentCreate(t, reg) }, stdout: "https://github.com/OWNER/REPO/issues/123#issuecomment-456\n", }, { - name: "non-interactive inline", - testInputType: inline, + name: "non-interactive inline", input: &CommentOptions{ SelectorArg: "123", Interactive: false, InputType: inline, Body: "comment body", }, + httpStubs: func(t *testing.T, reg *httpmock.Registry) { + mockIssueFromNumber(t, reg) + mockCommentCreate(t, reg) + }, stdout: "https://github.com/OWNER/REPO/issues/123#issuecomment-456\n", }, } @@ -227,49 +242,20 @@ func Test_commentRun(t *testing.T) { io.SetStdinTTY(true) io.SetStderrTTY(true) - client := &httpmock.Registry{} - defer client.Verify(t) - mockIssueFromNumber(client) - if tt.testInputType != web { - mockCommentCreate(t, client) - } + reg := &httpmock.Registry{} + defer reg.Verify(t) + tt.httpStubs(t, reg) tt.input.IO = io tt.input.HttpClient = func() (*http.Client, error) { - return &http.Client{Transport: client}, nil - } - tt.input.Config = func() (config.Config, error) { - return config.NewBlankConfig(), nil + return &http.Client{Transport: reg}, nil } tt.input.BaseRepo = func() (ghrepo.Interface, error) { return ghrepo.New("OWNER", "REPO"), nil } - if tt.input.Interactive { - as, teardown := prompt.InitAskStubber() - defer teardown() - // Input type select - as.StubOne(tt.testInputType) - if tt.testInputType == editor { - // Confirm submit - as.StubOne(true) - } - } - - if tt.testInputType == web { - // Stub browser open - restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable { - return &test.OutputStub{} - }) - defer restoreCmd() - } - t.Run(tt.name, func(t *testing.T) { err := commentRun(tt.input) - if tt.wantsErr { - assert.EqualError(t, err, tt.errMsg) - return - } assert.NoError(t, err) assert.Equal(t, tt.stdout, stdout.String()) assert.Equal(t, tt.stderr, stderr.String()) @@ -277,7 +263,7 @@ func Test_commentRun(t *testing.T) { } } -func mockIssueFromNumber(reg *httpmock.Registry) { +func mockIssueFromNumber(_ *testing.T, reg *httpmock.Registry) { reg.Register( httpmock.GraphQL(`query IssueByNumber\b`), httpmock.StringResponse(`