From f04e3398ed3a8623e2842b62e3953309fc93f107 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Wed, 16 Aug 2023 22:45:06 -0500 Subject: [PATCH 01/18] use prompter in shared editable code --- pkg/cmd/issue/edit/edit.go | 10 +-- pkg/cmd/issue/edit/edit_test.go | 4 +- pkg/cmd/pr/edit/edit.go | 12 ++-- pkg/cmd/pr/shared/editable.go | 109 ++++++++++++-------------------- 4 files changed, 57 insertions(+), 78 deletions(-) diff --git a/pkg/cmd/issue/edit/edit.go b/pkg/cmd/issue/edit/edit.go index 2fe4c62b7..53400fb63 100644 --- a/pkg/cmd/issue/edit/edit.go +++ b/pkg/cmd/issue/edit/edit.go @@ -21,10 +21,11 @@ type EditOptions struct { HttpClient func() (*http.Client, error) IO *iostreams.IOStreams BaseRepo func() (ghrepo.Interface, error) + Prompter prShared.EditPrompter DetermineEditor func() (string, error) - FieldsToEditSurvey func(*prShared.Editable) error - EditFieldsSurvey func(*prShared.Editable, string) error + FieldsToEditSurvey func(prShared.EditPrompter, *prShared.Editable) error + EditFieldsSurvey func(prShared.EditPrompter, *prShared.Editable, string) error FetchOptions func(*api.Client, ghrepo.Interface, *prShared.Editable) error SelectorArgs []string @@ -41,6 +42,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman FieldsToEditSurvey: prShared.FieldsToEditSurvey, EditFieldsSurvey: prShared.EditFieldsSurvey, FetchOptions: prShared.FetchOptions, + Prompter: f.Prompter, } var bodyFile string @@ -152,7 +154,7 @@ func editRun(opts *EditOptions) error { // Prompt the user which fields they'd like to edit. editable := opts.Editable if opts.Interactive { - err = opts.FieldsToEditSurvey(&editable) + err = opts.FieldsToEditSurvey(opts.Prompter, &editable) if err != nil { return err } @@ -222,7 +224,7 @@ func editRun(opts *EditOptions) error { if err != nil { return err } - err = opts.EditFieldsSurvey(&editable, editorCommand) + err = opts.EditFieldsSurvey(opts.Prompter, &editable, editorCommand) if err != nil { return err } diff --git a/pkg/cmd/issue/edit/edit_test.go b/pkg/cmd/issue/edit/edit_test.go index d73132f35..db0b09d2d 100644 --- a/pkg/cmd/issue/edit/edit_test.go +++ b/pkg/cmd/issue/edit/edit_test.go @@ -511,7 +511,7 @@ func Test_editRun(t *testing.T) { input: &EditOptions{ SelectorArgs: []string{"123"}, Interactive: true, - FieldsToEditSurvey: func(eo *prShared.Editable) error { + FieldsToEditSurvey: func(p prShared.EditPrompter, eo *prShared.Editable) error { eo.Title.Edited = true eo.Body.Edited = true eo.Assignees.Edited = true @@ -520,7 +520,7 @@ func Test_editRun(t *testing.T) { eo.Milestone.Edited = true return nil }, - EditFieldsSurvey: func(eo *prShared.Editable, _ string) error { + EditFieldsSurvey: func(p prShared.EditPrompter, eo *prShared.Editable, _ string) error { eo.Title.Value = "new title" eo.Body.Value = "new body" eo.Assignees.Value = []string{"monalisa", "hubot"} diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index bab7a26d4..c606ae6bb 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -24,6 +24,7 @@ type EditOptions struct { Surveyor Surveyor Fetcher EditableOptionsFetcher EditorRetriever EditorRetriever + Prompter shared.EditPrompter SelectorArg string Interactive bool @@ -35,9 +36,10 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman opts := &EditOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, - Surveyor: surveyor{}, + Surveyor: surveyor{P: f.Prompter}, Fetcher: fetcher{}, EditorRetriever: editorRetriever{config: f.Config}, + Prompter: f.Prompter, } var bodyFile string @@ -280,14 +282,16 @@ type Surveyor interface { EditFields(*shared.Editable, string) error } -type surveyor struct{} +type surveyor struct { + P shared.EditPrompter +} func (s surveyor) FieldsToEdit(editable *shared.Editable) error { - return shared.FieldsToEditSurvey(editable) + return shared.FieldsToEditSurvey(s.P, editable) } func (s surveyor) EditFields(editable *shared.Editable, editorCmd string) error { - return shared.EditFieldsSurvey(editable, editorCmd) + return shared.EditFieldsSurvey(s.P, editable, editorCmd) } type EditableOptionsFetcher interface { diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index 0fbe689fc..decd6456c 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -4,12 +4,9 @@ import ( "fmt" "strings" - "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" - "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/set" - "github.com/cli/cli/v2/pkg/surveyext" ) type Editable struct { @@ -255,34 +252,42 @@ func (ep *EditableProjects) clone() EditableProjects { } } -func EditFieldsSurvey(editable *Editable, editorCommand string) error { +type EditPrompter interface { + Select(string, string, []string) (int, error) + Input(string, string) (string, error) + MarkdownEditor(string, string, bool) (string, error) + MultiSelect(string, []string, []string) ([]int, error) + Confirm(string, bool) (bool, error) +} + +func EditFieldsSurvey(p EditPrompter, editable *Editable, editorCommand string) error { var err error if editable.Title.Edited { - editable.Title.Value, err = titleSurvey(editable.Title.Default) + editable.Title.Value, err = p.Input("Title", editable.Title.Default) if err != nil { return err } } if editable.Body.Edited { - editable.Body.Value, err = bodySurvey(editable.Body.Default, editorCommand) + editable.Body.Value, err = p.MarkdownEditor("Body", editable.Body.Default, false) if err != nil { return err } } if editable.Reviewers.Edited { - editable.Reviewers.Value, err = multiSelectSurvey("Reviewers", editable.Reviewers.Default, editable.Reviewers.Options) - if err != nil { - return err - } + editable.Reviewers.Value, err = multiSelectSurvey( + p, "Reviewers", editable.Reviewers.Default, editable.Reviewers.Options) } if editable.Assignees.Edited { - editable.Assignees.Value, err = multiSelectSurvey("Assignees", editable.Assignees.Default, editable.Assignees.Options) + editable.Assignees.Value, err = multiSelectSurvey( + p, "Assignees", editable.Assignees.Default, editable.Assignees.Options) if err != nil { return err } } if editable.Labels.Edited { - editable.Labels.Add, err = multiSelectSurvey("Labels", editable.Labels.Default, editable.Labels.Options) + editable.Labels.Add, err = multiSelectSurvey( + p, "Labels", editable.Labels.Default, editable.Labels.Options) if err != nil { return err } @@ -300,18 +305,19 @@ func EditFieldsSurvey(editable *Editable, editorCommand string) error { } } if editable.Projects.Edited { - editable.Projects.Value, err = multiSelectSurvey("Projects", editable.Projects.Default, editable.Projects.Options) + editable.Projects.Value, err = multiSelectSurvey( + p, "Projects", editable.Projects.Default, editable.Projects.Options) if err != nil { return err } } if editable.Milestone.Edited { - editable.Milestone.Value, err = milestoneSurvey(editable.Milestone.Default, editable.Milestone.Options) + editable.Milestone.Value, err = milestoneSurvey(p, editable.Milestone.Default, editable.Milestone.Options) if err != nil { return err } } - confirm, err := confirmSurvey() + confirm, err := p.Confirm("Submit?", true) if err != nil { return err } @@ -322,7 +328,7 @@ func EditFieldsSurvey(editable *Editable, editorCommand string) error { return nil } -func FieldsToEditSurvey(editable *Editable) error { +func FieldsToEditSurvey(p EditPrompter, editable *Editable) error { contains := func(s []string, str string) bool { for _, v := range s { if v == str { @@ -337,7 +343,7 @@ func FieldsToEditSurvey(editable *Editable) error { opts = append(opts, "Reviewers") } opts = append(opts, "Assignees", "Labels", "Projects", "Milestone") - results, err := multiSelectSurvey("What would you like to edit?", []string{}, opts) + results, err := multiSelectSurvey(p, "What would you like to edit?", []string{}, opts) if err != nil { return err } @@ -414,67 +420,34 @@ func FetchOptions(client *api.Client, repo ghrepo.Interface, editable *Editable) return nil } -func titleSurvey(title string) (string, error) { - var result string - q := &survey.Input{ - Message: "Title", - Default: title, - } - err := survey.AskOne(q, &result) - return result, err -} - -func bodySurvey(body, editorCommand string) (string, error) { - var result string - q := &surveyext.GhEditor{ - EditorCommand: editorCommand, - Editor: &survey.Editor{ - Message: "Body", - FileName: "*.md", - Default: body, - HideDefault: true, - AppendDefault: true, - }, - } - err := survey.AskOne(q, &result) - return result, err -} - -func multiSelectSurvey(message string, defaults, options []string) ([]string, error) { +func multiSelectSurvey(p EditPrompter, message string, defaults, options []string) (results []string, err error) { if len(options) == 0 { return nil, nil } - var results []string - q := &survey.MultiSelect{ - Message: message, - Options: options, - Default: defaults, - Filter: prompter.LatinMatchingFilter, + + var selected []int + selected, err = p.MultiSelect(message, defaults, options) + if err != nil { + return } - err := survey.AskOne(q, &results) + + for _, i := range selected { + results = append(results, options[i]) + } + return results, err } -func milestoneSurvey(title string, opts []string) (string, error) { +func milestoneSurvey(p EditPrompter, title string, opts []string) (result string, err error) { if len(opts) == 0 { return "", nil } - var result string - q := &survey.Select{ - Message: "Milestone", - Options: opts, - Default: title, + var selected int + selected, err = p.Select("Milestone", title, opts) + if err != nil { + return } - err := survey.AskOne(q, &result) - return result, err -} -func confirmSurvey() (bool, error) { - var result bool - q := &survey.Confirm{ - Message: "Submit?", - Default: true, - } - err := survey.AskOne(q, &result) - return result, err + result = opts[selected] + return } From a3539d4f24b17ff97dff383e0e9c115d1838d14f Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 14:43:08 -0500 Subject: [PATCH 02/18] use MultiSelect for metadata survey in pr, issue create --- pkg/cmd/issue/create/create.go | 2 +- pkg/cmd/pr/create/create.go | 2 +- pkg/cmd/pr/shared/survey.go | 19 +++++++----------- pkg/cmd/pr/shared/survey_test.go | 34 +++++++++++++++++--------------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/pkg/cmd/issue/create/create.go b/pkg/cmd/issue/create/create.go index a4db9d3a1..577f08728 100644 --- a/pkg/cmd/issue/create/create.go +++ b/pkg/cmd/issue/create/create.go @@ -268,7 +268,7 @@ func createRun(opts *CreateOptions) (err error) { Repo: baseRepo, State: &tb, } - err = prShared.MetadataSurvey(opts.IO, baseRepo, fetcher, &tb) + err = prShared.MetadataSurvey(opts.Prompter, opts.IO, baseRepo, fetcher, &tb) if err != nil { return } diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index 6809528b3..7321d4f38 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -361,7 +361,7 @@ func createRun(opts *CreateOptions) (err error) { Repo: ctx.BaseRepo, State: state, } - err = shared.MetadataSurvey(opts.IO, ctx.BaseRepo, fetcher, state) + err = shared.MetadataSurvey(opts.Prompter, opts.IO, ctx.BaseRepo, fetcher, state) if err != nil { return } diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 4e1d1a421..60a93d812 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -37,6 +37,7 @@ type Prompt interface { Select(string, string, []string) (int, error) MarkdownEditor(string, string, bool) (string, error) Confirm(string, bool) (bool, error) + MultiSelect(string, []string, []string) ([]int, error) } func ConfirmIssueSubmission(p Prompt, allowPreview bool, allowMetadata bool) (Action, error) { @@ -142,7 +143,7 @@ type RepoMetadataFetcher interface { RepoMetadataFetch(api.RepoMetadataInput) (*api.RepoMetadataResult, error) } -func MetadataSurvey(io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher RepoMetadataFetcher, state *IssueMetadataState) error { +func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher RepoMetadataFetcher, state *IssueMetadataState) error { isChosen := func(m string) bool { for _, c := range state.Metadata { if m == c { @@ -160,18 +161,12 @@ func MetadataSurvey(io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher } extraFieldsOptions = append(extraFieldsOptions, "Assignees", "Labels", "Projects", "Milestone") - //nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter - err := prompt.SurveyAsk([]*survey.Question{ - { - Name: "metadata", - Prompt: &survey.MultiSelect{ - Message: "What would you like to add?", - Options: extraFieldsOptions, - }, - }, - }, state) + selected, err := p.MultiSelect("What would you like to add?", nil, extraFieldsOptions) if err != nil { - return fmt.Errorf("could not prompt: %w", err) + return err + } + for _, i := range selected { + state.Metadata = append(state.Metadata, extraFieldsOptions[i]) } metadataInput := api.RepoMetadataInput{ diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 0bc27e8d6..88ca4d510 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -5,6 +5,7 @@ import ( "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/prompt" "github.com/stretchr/testify/assert" @@ -43,17 +44,17 @@ func TestMetadataSurvey_selectAll(t *testing.T) { }, } + pm := prompter.NewMockPrompter(t) + pm.RegisterMultiSelect("What would you like to add?", + []string{}, []string{"Reviewers", "Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { + // []string{"Labels", "Projects", "Assignees", "Reviewers", "Milestone"}, + return []int{0, 1, 2, 3, 4}, nil + }) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() defer restoreAsk() - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "metadata", - Value: []string{"Labels", "Projects", "Assignees", "Reviewers", "Milestone"}, - }, - }) //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { @@ -80,8 +81,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { state := &IssueMetadataState{ Assignees: []string{"hubot"}, + Type: PRMetadata, } - err := MetadataSurvey(ios, repo, fetcher, state) + err := MetadataSurvey(pm, ios, repo, fetcher, state) assert.NoError(t, err) assert.Equal(t, "", stdout.String()) @@ -112,17 +114,17 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { }, } + pm := prompter.NewMockPrompter(t) + + pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1, 2}, nil + + }) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() defer restoreAsk() - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "metadata", - Value: []string{"Labels", "Projects"}, - }, - }) //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { @@ -138,7 +140,7 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { state := &IssueMetadataState{ Assignees: []string{"hubot"}, } - err := MetadataSurvey(ios, repo, fetcher, state) + err := MetadataSurvey(pm, ios, repo, fetcher, state) assert.NoError(t, err) assert.Equal(t, "", stdout.String()) From f867eff04ddffe261cd4c653d24c2960812ba7d1 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:41:12 -0500 Subject: [PATCH 03/18] prompter for reviewers --- pkg/cmd/pr/shared/survey.go | 35 +++++++++++++++----------------- pkg/cmd/pr/shared/survey_test.go | 14 ++++++------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 60a93d812..374d99f55 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -210,22 +210,28 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface milestones = append(milestones, m.Title) } - var mqs []*survey.Question + values := struct { + Reviewers []string + Assignees []string + Labels []string + Projects []string + Milestone string + }{} + if isChosen("Reviewers") { if len(reviewers) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "reviewers", - Prompt: &survey.MultiSelect{ - Message: "Reviewers", - Options: reviewers, - Default: state.Reviewers, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Reviewers", state.Reviewers, reviewers) + if err != nil { + return err + } + for _, i := range selected { + values.Reviewers = append(values.Reviewers, reviewers[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no available reviewers") } } + var mqs []*survey.Question if isChosen("Assignees") { if len(assignees) > 0 { mqs = append(mqs, &survey.Question{ @@ -291,15 +297,6 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no milestones in the repository") } } - - values := struct { - Reviewers []string - Assignees []string - Labels []string - Projects []string - Milestone string - }{} - //nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter err = prompt.SurveyAsk(mqs, &values) if err != nil { diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 88ca4d510..8f19540fc 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -47,9 +47,11 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm := prompter.NewMockPrompter(t) pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Reviewers", "Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { - // []string{"Labels", "Projects", "Assignees", "Reviewers", "Milestone"}, return []int{0, 1, 2, 3, 4}, nil }) + pm.RegisterMultiSelect("Reviewers", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -57,10 +59,10 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "reviewers", - Value: []string{"monalisa"}, - }, + //{ + // Name: "reviewers", + // Value: []string{"monalisa"}, + //}, { Name: "assignees", Value: []string{"hubot"}, @@ -115,10 +117,8 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { } pm := prompter.NewMockPrompter(t) - pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { return []int{1, 2}, nil - }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber From 542c154d077d25ec13703045d62576c7adb877c5 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:45:04 -0500 Subject: [PATCH 04/18] prompter for assignees --- pkg/cmd/pr/shared/survey.go | 18 ++++++++---------- pkg/cmd/pr/shared/survey_test.go | 11 +++-------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 374d99f55..86b8f9021 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -231,22 +231,20 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no available reviewers") } } - var mqs []*survey.Question if isChosen("Assignees") { if len(assignees) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "assignees", - Prompt: &survey.MultiSelect{ - Message: "Assignees", - Options: assignees, - Default: state.Assignees, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Assignees", state.Assignees, assignees) + if err != nil { + return err + } + for _, i := range selected { + values.Assignees = append(values.Assignees, assignees[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no assignable users") } } + var mqs []*survey.Question if isChosen("Labels") { if len(labels) > 0 { mqs = append(mqs, &survey.Question{ diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 8f19540fc..790bbcd2e 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -52,6 +52,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Reviewers", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) + pm.RegisterMultiSelect("Assignees", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { + return []int{0}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -59,14 +62,6 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - //{ - // Name: "reviewers", - // Value: []string{"monalisa"}, - //}, - { - Name: "assignees", - Value: []string{"hubot"}, - }, { Name: "labels", Value: []string{"good first issue"}, From abf49d13225a62c10eac606502d4633223c286b7 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:50:55 -0500 Subject: [PATCH 05/18] use prompter for labels --- pkg/cmd/pr/shared/survey.go | 18 ++++++++---------- pkg/cmd/pr/shared/survey_test.go | 14 ++++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 86b8f9021..48f621619 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -244,22 +244,20 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no assignable users") } } - var mqs []*survey.Question if isChosen("Labels") { if len(labels) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "labels", - Prompt: &survey.MultiSelect{ - Message: "Labels", - Options: labels, - Default: state.Labels, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Labels", state.Labels, labels) + if err != nil { + return err + } + for _, i := range selected { + values.Labels = append(values.Labels, labels[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no labels in the repository") } } + var mqs []*survey.Question if isChosen("Projects") { if len(projects) > 0 { mqs = append(mqs, &survey.Question{ diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 790bbcd2e..91fbed6ee 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -55,6 +55,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Assignees", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { return []int{0}, nil }) + pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -62,10 +65,6 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "labels", - Value: []string{"good first issue"}, - }, { Name: "projects", Value: []string{"The road to 1.0"}, @@ -115,6 +114,9 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { return []int{1, 2}, nil }) + pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -122,10 +124,6 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "labels", - Value: []string{"good first issue"}, - }, { Name: "projects", Value: []string{"The road to 1.0"}, From 6a4dbf9db3b387ad84da1e2a5ab81b223adc9864 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:54:46 -0500 Subject: [PATCH 06/18] prompter for projects --- pkg/cmd/pr/shared/survey.go | 17 +++++++---------- pkg/cmd/pr/shared/survey_test.go | 20 +++++--------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 48f621619..7d56c9caf 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -7,7 +7,6 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" - "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/prompt" ) @@ -260,15 +259,13 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface var mqs []*survey.Question if isChosen("Projects") { if len(projects) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "projects", - Prompt: &survey.MultiSelect{ - Message: "Projects", - Options: projects, - Default: state.Projects, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Projects", state.Projects, projects) + if err != nil { + return err + } + for _, i := range selected { + values.Projects = append(values.Projects, projects[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no projects to choose from") } diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 91fbed6ee..ffc2bc55b 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -58,6 +58,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) + pm.RegisterMultiSelect("Projects", []string{}, []string{"Huge Refactoring", "The road to 1.0"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -65,10 +68,6 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "projects", - Value: []string{"The road to 1.0"}, - }, { Name: "milestone", Value: "(none)", @@ -117,17 +116,8 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) - - //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber - as, restoreAsk := prompt.InitAskStubber() - defer restoreAsk() - - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "projects", - Value: []string{"The road to 1.0"}, - }, + pm.RegisterMultiSelect("Projects", []string{}, []string{"Huge Refactoring", "The road to 1.0"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil }) state := &IssueMetadataState{ From 4382efdf69ddd858d5a4e3c6eb208e195e2b1232 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:58:38 -0500 Subject: [PATCH 07/18] prompter for milestone --- pkg/cmd/pr/shared/survey.go | 21 +++++---------------- pkg/cmd/pr/shared/survey_test.go | 14 ++------------ 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 7d56c9caf..393b87757 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -4,11 +4,9 @@ import ( "fmt" "strings" - "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/pkg/iostreams" - "github.com/cli/cli/v2/pkg/prompt" ) type Action int @@ -256,7 +254,6 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no labels in the repository") } } - var mqs []*survey.Question if isChosen("Projects") { if len(projects) > 0 { selected, err := p.MultiSelect("Projects", state.Projects, projects) @@ -278,23 +275,15 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface } else { milestoneDefault = milestones[1] } - mqs = append(mqs, &survey.Question{ - Name: "milestone", - Prompt: &survey.Select{ - Message: "Milestone", - Options: milestones, - Default: milestoneDefault, - }, - }) + selected, err := p.Select("Milestone", milestoneDefault, milestones) + if err != nil { + return err + } + values.Milestone = milestones[selected] } else { fmt.Fprintln(io.ErrOut, "warning: no milestones in the repository") } } - //nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter - err = prompt.SurveyAsk(mqs, &values) - if err != nil { - return fmt.Errorf("could not prompt: %w", err) - } if isChosen("Reviewers") { var logins []string diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index ffc2bc55b..4653ce08b 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -7,7 +7,6 @@ import ( "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/iostreams" - "github.com/cli/cli/v2/pkg/prompt" "github.com/stretchr/testify/assert" ) @@ -61,17 +60,8 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Projects", []string{}, []string{"Huge Refactoring", "The road to 1.0"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) - - //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber - as, restoreAsk := prompt.InitAskStubber() - defer restoreAsk() - - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "milestone", - Value: "(none)", - }, + pm.RegisterSelect("Milestone", []string{"(none)", "1.2 patch release"}, func(_, _ string, _ []string) (int, error) { + return 0, nil }) state := &IssueMetadataState{ From bff47273315daf57ea047fb49024e000149b54b2 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 17:17:26 -0500 Subject: [PATCH 08/18] linter appeasement --- pkg/cmd/pr/shared/editable.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index decd6456c..cec3bfe8c 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -277,6 +277,9 @@ func EditFieldsSurvey(p EditPrompter, editable *Editable, editorCommand string) if editable.Reviewers.Edited { editable.Reviewers.Value, err = multiSelectSurvey( p, "Reviewers", editable.Reviewers.Default, editable.Reviewers.Options) + if err != nil { + return err + } } if editable.Assignees.Edited { editable.Assignees.Value, err = multiSelectSurvey( From 7860198dd7ffdc35e1afe263d65fd659fca71fbb Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Wed, 16 Aug 2023 22:45:06 -0500 Subject: [PATCH 09/18] use prompter in shared editable code --- pkg/cmd/issue/edit/edit.go | 10 +-- pkg/cmd/issue/edit/edit_test.go | 4 +- pkg/cmd/pr/edit/edit.go | 12 ++-- pkg/cmd/pr/shared/editable.go | 109 ++++++++++++-------------------- 4 files changed, 57 insertions(+), 78 deletions(-) diff --git a/pkg/cmd/issue/edit/edit.go b/pkg/cmd/issue/edit/edit.go index 2fe4c62b7..53400fb63 100644 --- a/pkg/cmd/issue/edit/edit.go +++ b/pkg/cmd/issue/edit/edit.go @@ -21,10 +21,11 @@ type EditOptions struct { HttpClient func() (*http.Client, error) IO *iostreams.IOStreams BaseRepo func() (ghrepo.Interface, error) + Prompter prShared.EditPrompter DetermineEditor func() (string, error) - FieldsToEditSurvey func(*prShared.Editable) error - EditFieldsSurvey func(*prShared.Editable, string) error + FieldsToEditSurvey func(prShared.EditPrompter, *prShared.Editable) error + EditFieldsSurvey func(prShared.EditPrompter, *prShared.Editable, string) error FetchOptions func(*api.Client, ghrepo.Interface, *prShared.Editable) error SelectorArgs []string @@ -41,6 +42,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman FieldsToEditSurvey: prShared.FieldsToEditSurvey, EditFieldsSurvey: prShared.EditFieldsSurvey, FetchOptions: prShared.FetchOptions, + Prompter: f.Prompter, } var bodyFile string @@ -152,7 +154,7 @@ func editRun(opts *EditOptions) error { // Prompt the user which fields they'd like to edit. editable := opts.Editable if opts.Interactive { - err = opts.FieldsToEditSurvey(&editable) + err = opts.FieldsToEditSurvey(opts.Prompter, &editable) if err != nil { return err } @@ -222,7 +224,7 @@ func editRun(opts *EditOptions) error { if err != nil { return err } - err = opts.EditFieldsSurvey(&editable, editorCommand) + err = opts.EditFieldsSurvey(opts.Prompter, &editable, editorCommand) if err != nil { return err } diff --git a/pkg/cmd/issue/edit/edit_test.go b/pkg/cmd/issue/edit/edit_test.go index d73132f35..db0b09d2d 100644 --- a/pkg/cmd/issue/edit/edit_test.go +++ b/pkg/cmd/issue/edit/edit_test.go @@ -511,7 +511,7 @@ func Test_editRun(t *testing.T) { input: &EditOptions{ SelectorArgs: []string{"123"}, Interactive: true, - FieldsToEditSurvey: func(eo *prShared.Editable) error { + FieldsToEditSurvey: func(p prShared.EditPrompter, eo *prShared.Editable) error { eo.Title.Edited = true eo.Body.Edited = true eo.Assignees.Edited = true @@ -520,7 +520,7 @@ func Test_editRun(t *testing.T) { eo.Milestone.Edited = true return nil }, - EditFieldsSurvey: func(eo *prShared.Editable, _ string) error { + EditFieldsSurvey: func(p prShared.EditPrompter, eo *prShared.Editable, _ string) error { eo.Title.Value = "new title" eo.Body.Value = "new body" eo.Assignees.Value = []string{"monalisa", "hubot"} diff --git a/pkg/cmd/pr/edit/edit.go b/pkg/cmd/pr/edit/edit.go index bab7a26d4..c606ae6bb 100644 --- a/pkg/cmd/pr/edit/edit.go +++ b/pkg/cmd/pr/edit/edit.go @@ -24,6 +24,7 @@ type EditOptions struct { Surveyor Surveyor Fetcher EditableOptionsFetcher EditorRetriever EditorRetriever + Prompter shared.EditPrompter SelectorArg string Interactive bool @@ -35,9 +36,10 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman opts := &EditOptions{ IO: f.IOStreams, HttpClient: f.HttpClient, - Surveyor: surveyor{}, + Surveyor: surveyor{P: f.Prompter}, Fetcher: fetcher{}, EditorRetriever: editorRetriever{config: f.Config}, + Prompter: f.Prompter, } var bodyFile string @@ -280,14 +282,16 @@ type Surveyor interface { EditFields(*shared.Editable, string) error } -type surveyor struct{} +type surveyor struct { + P shared.EditPrompter +} func (s surveyor) FieldsToEdit(editable *shared.Editable) error { - return shared.FieldsToEditSurvey(editable) + return shared.FieldsToEditSurvey(s.P, editable) } func (s surveyor) EditFields(editable *shared.Editable, editorCmd string) error { - return shared.EditFieldsSurvey(editable, editorCmd) + return shared.EditFieldsSurvey(s.P, editable, editorCmd) } type EditableOptionsFetcher interface { diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index 0fbe689fc..decd6456c 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -4,12 +4,9 @@ import ( "fmt" "strings" - "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" - "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/set" - "github.com/cli/cli/v2/pkg/surveyext" ) type Editable struct { @@ -255,34 +252,42 @@ func (ep *EditableProjects) clone() EditableProjects { } } -func EditFieldsSurvey(editable *Editable, editorCommand string) error { +type EditPrompter interface { + Select(string, string, []string) (int, error) + Input(string, string) (string, error) + MarkdownEditor(string, string, bool) (string, error) + MultiSelect(string, []string, []string) ([]int, error) + Confirm(string, bool) (bool, error) +} + +func EditFieldsSurvey(p EditPrompter, editable *Editable, editorCommand string) error { var err error if editable.Title.Edited { - editable.Title.Value, err = titleSurvey(editable.Title.Default) + editable.Title.Value, err = p.Input("Title", editable.Title.Default) if err != nil { return err } } if editable.Body.Edited { - editable.Body.Value, err = bodySurvey(editable.Body.Default, editorCommand) + editable.Body.Value, err = p.MarkdownEditor("Body", editable.Body.Default, false) if err != nil { return err } } if editable.Reviewers.Edited { - editable.Reviewers.Value, err = multiSelectSurvey("Reviewers", editable.Reviewers.Default, editable.Reviewers.Options) - if err != nil { - return err - } + editable.Reviewers.Value, err = multiSelectSurvey( + p, "Reviewers", editable.Reviewers.Default, editable.Reviewers.Options) } if editable.Assignees.Edited { - editable.Assignees.Value, err = multiSelectSurvey("Assignees", editable.Assignees.Default, editable.Assignees.Options) + editable.Assignees.Value, err = multiSelectSurvey( + p, "Assignees", editable.Assignees.Default, editable.Assignees.Options) if err != nil { return err } } if editable.Labels.Edited { - editable.Labels.Add, err = multiSelectSurvey("Labels", editable.Labels.Default, editable.Labels.Options) + editable.Labels.Add, err = multiSelectSurvey( + p, "Labels", editable.Labels.Default, editable.Labels.Options) if err != nil { return err } @@ -300,18 +305,19 @@ func EditFieldsSurvey(editable *Editable, editorCommand string) error { } } if editable.Projects.Edited { - editable.Projects.Value, err = multiSelectSurvey("Projects", editable.Projects.Default, editable.Projects.Options) + editable.Projects.Value, err = multiSelectSurvey( + p, "Projects", editable.Projects.Default, editable.Projects.Options) if err != nil { return err } } if editable.Milestone.Edited { - editable.Milestone.Value, err = milestoneSurvey(editable.Milestone.Default, editable.Milestone.Options) + editable.Milestone.Value, err = milestoneSurvey(p, editable.Milestone.Default, editable.Milestone.Options) if err != nil { return err } } - confirm, err := confirmSurvey() + confirm, err := p.Confirm("Submit?", true) if err != nil { return err } @@ -322,7 +328,7 @@ func EditFieldsSurvey(editable *Editable, editorCommand string) error { return nil } -func FieldsToEditSurvey(editable *Editable) error { +func FieldsToEditSurvey(p EditPrompter, editable *Editable) error { contains := func(s []string, str string) bool { for _, v := range s { if v == str { @@ -337,7 +343,7 @@ func FieldsToEditSurvey(editable *Editable) error { opts = append(opts, "Reviewers") } opts = append(opts, "Assignees", "Labels", "Projects", "Milestone") - results, err := multiSelectSurvey("What would you like to edit?", []string{}, opts) + results, err := multiSelectSurvey(p, "What would you like to edit?", []string{}, opts) if err != nil { return err } @@ -414,67 +420,34 @@ func FetchOptions(client *api.Client, repo ghrepo.Interface, editable *Editable) return nil } -func titleSurvey(title string) (string, error) { - var result string - q := &survey.Input{ - Message: "Title", - Default: title, - } - err := survey.AskOne(q, &result) - return result, err -} - -func bodySurvey(body, editorCommand string) (string, error) { - var result string - q := &surveyext.GhEditor{ - EditorCommand: editorCommand, - Editor: &survey.Editor{ - Message: "Body", - FileName: "*.md", - Default: body, - HideDefault: true, - AppendDefault: true, - }, - } - err := survey.AskOne(q, &result) - return result, err -} - -func multiSelectSurvey(message string, defaults, options []string) ([]string, error) { +func multiSelectSurvey(p EditPrompter, message string, defaults, options []string) (results []string, err error) { if len(options) == 0 { return nil, nil } - var results []string - q := &survey.MultiSelect{ - Message: message, - Options: options, - Default: defaults, - Filter: prompter.LatinMatchingFilter, + + var selected []int + selected, err = p.MultiSelect(message, defaults, options) + if err != nil { + return } - err := survey.AskOne(q, &results) + + for _, i := range selected { + results = append(results, options[i]) + } + return results, err } -func milestoneSurvey(title string, opts []string) (string, error) { +func milestoneSurvey(p EditPrompter, title string, opts []string) (result string, err error) { if len(opts) == 0 { return "", nil } - var result string - q := &survey.Select{ - Message: "Milestone", - Options: opts, - Default: title, + var selected int + selected, err = p.Select("Milestone", title, opts) + if err != nil { + return } - err := survey.AskOne(q, &result) - return result, err -} -func confirmSurvey() (bool, error) { - var result bool - q := &survey.Confirm{ - Message: "Submit?", - Default: true, - } - err := survey.AskOne(q, &result) - return result, err + result = opts[selected] + return } From 896a6f39ad98de9698ba2ad0edb44bd169b55ed3 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 14:43:08 -0500 Subject: [PATCH 10/18] use MultiSelect for metadata survey in pr, issue create --- pkg/cmd/issue/create/create.go | 2 +- pkg/cmd/pr/create/create.go | 2 +- pkg/cmd/pr/shared/survey.go | 19 +++++++----------- pkg/cmd/pr/shared/survey_test.go | 34 +++++++++++++++++--------------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/pkg/cmd/issue/create/create.go b/pkg/cmd/issue/create/create.go index a4db9d3a1..577f08728 100644 --- a/pkg/cmd/issue/create/create.go +++ b/pkg/cmd/issue/create/create.go @@ -268,7 +268,7 @@ func createRun(opts *CreateOptions) (err error) { Repo: baseRepo, State: &tb, } - err = prShared.MetadataSurvey(opts.IO, baseRepo, fetcher, &tb) + err = prShared.MetadataSurvey(opts.Prompter, opts.IO, baseRepo, fetcher, &tb) if err != nil { return } diff --git a/pkg/cmd/pr/create/create.go b/pkg/cmd/pr/create/create.go index 6809528b3..7321d4f38 100644 --- a/pkg/cmd/pr/create/create.go +++ b/pkg/cmd/pr/create/create.go @@ -361,7 +361,7 @@ func createRun(opts *CreateOptions) (err error) { Repo: ctx.BaseRepo, State: state, } - err = shared.MetadataSurvey(opts.IO, ctx.BaseRepo, fetcher, state) + err = shared.MetadataSurvey(opts.Prompter, opts.IO, ctx.BaseRepo, fetcher, state) if err != nil { return } diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 4e1d1a421..60a93d812 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -37,6 +37,7 @@ type Prompt interface { Select(string, string, []string) (int, error) MarkdownEditor(string, string, bool) (string, error) Confirm(string, bool) (bool, error) + MultiSelect(string, []string, []string) ([]int, error) } func ConfirmIssueSubmission(p Prompt, allowPreview bool, allowMetadata bool) (Action, error) { @@ -142,7 +143,7 @@ type RepoMetadataFetcher interface { RepoMetadataFetch(api.RepoMetadataInput) (*api.RepoMetadataResult, error) } -func MetadataSurvey(io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher RepoMetadataFetcher, state *IssueMetadataState) error { +func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher RepoMetadataFetcher, state *IssueMetadataState) error { isChosen := func(m string) bool { for _, c := range state.Metadata { if m == c { @@ -160,18 +161,12 @@ func MetadataSurvey(io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher } extraFieldsOptions = append(extraFieldsOptions, "Assignees", "Labels", "Projects", "Milestone") - //nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter - err := prompt.SurveyAsk([]*survey.Question{ - { - Name: "metadata", - Prompt: &survey.MultiSelect{ - Message: "What would you like to add?", - Options: extraFieldsOptions, - }, - }, - }, state) + selected, err := p.MultiSelect("What would you like to add?", nil, extraFieldsOptions) if err != nil { - return fmt.Errorf("could not prompt: %w", err) + return err + } + for _, i := range selected { + state.Metadata = append(state.Metadata, extraFieldsOptions[i]) } metadataInput := api.RepoMetadataInput{ diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 0bc27e8d6..88ca4d510 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -5,6 +5,7 @@ import ( "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" + "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/prompt" "github.com/stretchr/testify/assert" @@ -43,17 +44,17 @@ func TestMetadataSurvey_selectAll(t *testing.T) { }, } + pm := prompter.NewMockPrompter(t) + pm.RegisterMultiSelect("What would you like to add?", + []string{}, []string{"Reviewers", "Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { + // []string{"Labels", "Projects", "Assignees", "Reviewers", "Milestone"}, + return []int{0, 1, 2, 3, 4}, nil + }) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() defer restoreAsk() - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "metadata", - Value: []string{"Labels", "Projects", "Assignees", "Reviewers", "Milestone"}, - }, - }) //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { @@ -80,8 +81,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { state := &IssueMetadataState{ Assignees: []string{"hubot"}, + Type: PRMetadata, } - err := MetadataSurvey(ios, repo, fetcher, state) + err := MetadataSurvey(pm, ios, repo, fetcher, state) assert.NoError(t, err) assert.Equal(t, "", stdout.String()) @@ -112,17 +114,17 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { }, } + pm := prompter.NewMockPrompter(t) + + pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1, 2}, nil + + }) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() defer restoreAsk() - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "metadata", - Value: []string{"Labels", "Projects"}, - }, - }) //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { @@ -138,7 +140,7 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { state := &IssueMetadataState{ Assignees: []string{"hubot"}, } - err := MetadataSurvey(ios, repo, fetcher, state) + err := MetadataSurvey(pm, ios, repo, fetcher, state) assert.NoError(t, err) assert.Equal(t, "", stdout.String()) From a2758d3c28c220fd6905851d662e69b1e66dff6f Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:41:12 -0500 Subject: [PATCH 11/18] prompter for reviewers --- pkg/cmd/pr/shared/survey.go | 35 +++++++++++++++----------------- pkg/cmd/pr/shared/survey_test.go | 14 ++++++------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 60a93d812..374d99f55 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -210,22 +210,28 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface milestones = append(milestones, m.Title) } - var mqs []*survey.Question + values := struct { + Reviewers []string + Assignees []string + Labels []string + Projects []string + Milestone string + }{} + if isChosen("Reviewers") { if len(reviewers) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "reviewers", - Prompt: &survey.MultiSelect{ - Message: "Reviewers", - Options: reviewers, - Default: state.Reviewers, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Reviewers", state.Reviewers, reviewers) + if err != nil { + return err + } + for _, i := range selected { + values.Reviewers = append(values.Reviewers, reviewers[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no available reviewers") } } + var mqs []*survey.Question if isChosen("Assignees") { if len(assignees) > 0 { mqs = append(mqs, &survey.Question{ @@ -291,15 +297,6 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no milestones in the repository") } } - - values := struct { - Reviewers []string - Assignees []string - Labels []string - Projects []string - Milestone string - }{} - //nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter err = prompt.SurveyAsk(mqs, &values) if err != nil { diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 88ca4d510..8f19540fc 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -47,9 +47,11 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm := prompter.NewMockPrompter(t) pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Reviewers", "Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { - // []string{"Labels", "Projects", "Assignees", "Reviewers", "Milestone"}, return []int{0, 1, 2, 3, 4}, nil }) + pm.RegisterMultiSelect("Reviewers", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -57,10 +59,10 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "reviewers", - Value: []string{"monalisa"}, - }, + //{ + // Name: "reviewers", + // Value: []string{"monalisa"}, + //}, { Name: "assignees", Value: []string{"hubot"}, @@ -115,10 +117,8 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { } pm := prompter.NewMockPrompter(t) - pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { return []int{1, 2}, nil - }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber From 9b7cc44c7f450b51d7d480622abe3994afa3dad3 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:45:04 -0500 Subject: [PATCH 12/18] prompter for assignees --- pkg/cmd/pr/shared/survey.go | 18 ++++++++---------- pkg/cmd/pr/shared/survey_test.go | 11 +++-------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 374d99f55..86b8f9021 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -231,22 +231,20 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no available reviewers") } } - var mqs []*survey.Question if isChosen("Assignees") { if len(assignees) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "assignees", - Prompt: &survey.MultiSelect{ - Message: "Assignees", - Options: assignees, - Default: state.Assignees, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Assignees", state.Assignees, assignees) + if err != nil { + return err + } + for _, i := range selected { + values.Assignees = append(values.Assignees, assignees[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no assignable users") } } + var mqs []*survey.Question if isChosen("Labels") { if len(labels) > 0 { mqs = append(mqs, &survey.Question{ diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 8f19540fc..790bbcd2e 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -52,6 +52,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Reviewers", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) + pm.RegisterMultiSelect("Assignees", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { + return []int{0}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -59,14 +62,6 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - //{ - // Name: "reviewers", - // Value: []string{"monalisa"}, - //}, - { - Name: "assignees", - Value: []string{"hubot"}, - }, { Name: "labels", Value: []string{"good first issue"}, From 81cbf5e9b6fcc3ec493e2a1c062ca9265e7aceaa Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:50:55 -0500 Subject: [PATCH 13/18] use prompter for labels --- pkg/cmd/pr/shared/survey.go | 18 ++++++++---------- pkg/cmd/pr/shared/survey_test.go | 14 ++++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 86b8f9021..48f621619 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -244,22 +244,20 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no assignable users") } } - var mqs []*survey.Question if isChosen("Labels") { if len(labels) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "labels", - Prompt: &survey.MultiSelect{ - Message: "Labels", - Options: labels, - Default: state.Labels, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Labels", state.Labels, labels) + if err != nil { + return err + } + for _, i := range selected { + values.Labels = append(values.Labels, labels[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no labels in the repository") } } + var mqs []*survey.Question if isChosen("Projects") { if len(projects) > 0 { mqs = append(mqs, &survey.Question{ diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 790bbcd2e..91fbed6ee 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -55,6 +55,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Assignees", []string{}, []string{"hubot", "monalisa"}, func(_ string, _, _ []string) ([]int, error) { return []int{0}, nil }) + pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -62,10 +65,6 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "labels", - Value: []string{"good first issue"}, - }, { Name: "projects", Value: []string{"The road to 1.0"}, @@ -115,6 +114,9 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { pm.RegisterMultiSelect("What would you like to add?", []string{}, []string{"Assignees", "Labels", "Projects", "Milestone"}, func(_ string, _, _ []string) ([]int, error) { return []int{1, 2}, nil }) + pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -122,10 +124,6 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "labels", - Value: []string{"good first issue"}, - }, { Name: "projects", Value: []string{"The road to 1.0"}, From 00c25a8d626f983fd663a0175ac2a6b19ecf3e5b Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:54:46 -0500 Subject: [PATCH 14/18] prompter for projects --- pkg/cmd/pr/shared/survey.go | 17 +++++++---------- pkg/cmd/pr/shared/survey_test.go | 20 +++++--------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 48f621619..7d56c9caf 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -7,7 +7,6 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" - "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/iostreams" "github.com/cli/cli/v2/pkg/prompt" ) @@ -260,15 +259,13 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface var mqs []*survey.Question if isChosen("Projects") { if len(projects) > 0 { - mqs = append(mqs, &survey.Question{ - Name: "projects", - Prompt: &survey.MultiSelect{ - Message: "Projects", - Options: projects, - Default: state.Projects, - Filter: prompter.LatinMatchingFilter, - }, - }) + selected, err := p.MultiSelect("Projects", state.Projects, projects) + if err != nil { + return err + } + for _, i := range selected { + values.Projects = append(values.Projects, projects[i]) + } } else { fmt.Fprintln(io.ErrOut, "warning: no projects to choose from") } diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index 91fbed6ee..ffc2bc55b 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -58,6 +58,9 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) + pm.RegisterMultiSelect("Projects", []string{}, []string{"Huge Refactoring", "The road to 1.0"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil + }) //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, restoreAsk := prompt.InitAskStubber() @@ -65,10 +68,6 @@ func TestMetadataSurvey_selectAll(t *testing.T) { //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ - { - Name: "projects", - Value: []string{"The road to 1.0"}, - }, { Name: "milestone", Value: "(none)", @@ -117,17 +116,8 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { pm.RegisterMultiSelect("Labels", []string{}, []string{"help wanted", "good first issue"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) - - //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber - as, restoreAsk := prompt.InitAskStubber() - defer restoreAsk() - - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "projects", - Value: []string{"The road to 1.0"}, - }, + pm.RegisterMultiSelect("Projects", []string{}, []string{"Huge Refactoring", "The road to 1.0"}, func(_ string, _, _ []string) ([]int, error) { + return []int{1}, nil }) state := &IssueMetadataState{ From 13a4ebf4dbd6b6cbb7698b469b83e1264a41d209 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 15:58:38 -0500 Subject: [PATCH 15/18] prompter for milestone --- pkg/cmd/pr/shared/survey.go | 21 +++++---------------- pkg/cmd/pr/shared/survey_test.go | 14 ++------------ 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/pkg/cmd/pr/shared/survey.go b/pkg/cmd/pr/shared/survey.go index 7d56c9caf..393b87757 100644 --- a/pkg/cmd/pr/shared/survey.go +++ b/pkg/cmd/pr/shared/survey.go @@ -4,11 +4,9 @@ import ( "fmt" "strings" - "github.com/AlecAivazis/survey/v2" "github.com/cli/cli/v2/api" "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/pkg/iostreams" - "github.com/cli/cli/v2/pkg/prompt" ) type Action int @@ -256,7 +254,6 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface fmt.Fprintln(io.ErrOut, "warning: no labels in the repository") } } - var mqs []*survey.Question if isChosen("Projects") { if len(projects) > 0 { selected, err := p.MultiSelect("Projects", state.Projects, projects) @@ -278,23 +275,15 @@ func MetadataSurvey(p Prompt, io *iostreams.IOStreams, baseRepo ghrepo.Interface } else { milestoneDefault = milestones[1] } - mqs = append(mqs, &survey.Question{ - Name: "milestone", - Prompt: &survey.Select{ - Message: "Milestone", - Options: milestones, - Default: milestoneDefault, - }, - }) + selected, err := p.Select("Milestone", milestoneDefault, milestones) + if err != nil { + return err + } + values.Milestone = milestones[selected] } else { fmt.Fprintln(io.ErrOut, "warning: no milestones in the repository") } } - //nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter - err = prompt.SurveyAsk(mqs, &values) - if err != nil { - return fmt.Errorf("could not prompt: %w", err) - } if isChosen("Reviewers") { var logins []string diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index ffc2bc55b..4653ce08b 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -7,7 +7,6 @@ import ( "github.com/cli/cli/v2/internal/ghrepo" "github.com/cli/cli/v2/internal/prompter" "github.com/cli/cli/v2/pkg/iostreams" - "github.com/cli/cli/v2/pkg/prompt" "github.com/stretchr/testify/assert" ) @@ -61,17 +60,8 @@ func TestMetadataSurvey_selectAll(t *testing.T) { pm.RegisterMultiSelect("Projects", []string{}, []string{"Huge Refactoring", "The road to 1.0"}, func(_ string, _, _ []string) ([]int, error) { return []int{1}, nil }) - - //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber - as, restoreAsk := prompt.InitAskStubber() - defer restoreAsk() - - //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "milestone", - Value: "(none)", - }, + pm.RegisterSelect("Milestone", []string{"(none)", "1.2 patch release"}, func(_, _ string, _ []string) (int, error) { + return 0, nil }) state := &IssueMetadataState{ From 79f789b2094c4df418b38dff7460f40188d5823e Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 16:04:57 -0500 Subject: [PATCH 16/18] delete prompt package --- pkg/prompt/prompt.go | 34 ------- pkg/prompt/stubber.go | 205 ------------------------------------------ 2 files changed, 239 deletions(-) delete mode 100644 pkg/prompt/prompt.go delete mode 100644 pkg/prompt/stubber.go diff --git a/pkg/prompt/prompt.go b/pkg/prompt/prompt.go deleted file mode 100644 index 683fad913..000000000 --- a/pkg/prompt/prompt.go +++ /dev/null @@ -1,34 +0,0 @@ -package prompt - -import "github.com/AlecAivazis/survey/v2" - -// Deprecated: use PrompterMock -func StubConfirm(result bool) func() { - orig := Confirm - Confirm = func(_ string, r *bool) error { - *r = result - return nil - } - return func() { - Confirm = orig - } -} - -// Deprecated: use Prompter -var Confirm = func(prompt string, result *bool) error { - p := &survey.Confirm{ - Message: prompt, - Default: true, - } - return SurveyAskOne(p, result) -} - -// Deprecated: use Prompter -var SurveyAskOne = func(p survey.Prompt, response interface{}, opts ...survey.AskOpt) error { - return survey.AskOne(p, response, opts...) -} - -// Deprecated: use Prompter -var SurveyAsk = func(qs []*survey.Question, response interface{}, opts ...survey.AskOpt) error { - return survey.Ask(qs, response, opts...) -} diff --git a/pkg/prompt/stubber.go b/pkg/prompt/stubber.go deleted file mode 100644 index 8011c5924..000000000 --- a/pkg/prompt/stubber.go +++ /dev/null @@ -1,205 +0,0 @@ -package prompt - -import ( - "fmt" - "strings" - - "github.com/AlecAivazis/survey/v2" - "github.com/AlecAivazis/survey/v2/core" - "github.com/cli/cli/v2/pkg/surveyext" -) - -type AskStubber struct { - stubs []*QuestionStub -} - -type testing interface { - Errorf(format string, args ...interface{}) - Cleanup(func()) -} - -// Deprecated: use PrompterMock -func NewAskStubber(t testing) *AskStubber { - as, teardown := InitAskStubber() - t.Cleanup(func() { - teardown() - for _, s := range as.stubs { - if !s.matched { - t.Errorf("unmatched prompt stub: %+v", s) - } - } - }) - return as -} - -// Deprecated: use NewAskStubber -func InitAskStubber() (*AskStubber, func()) { - origSurveyAsk := SurveyAsk - origSurveyAskOne := SurveyAskOne - as := AskStubber{} - - answerFromStub := func(p survey.Prompt, fieldName string, response interface{}) error { - var message string - var defaultValue interface{} - var options []string - switch pt := p.(type) { - case *survey.Confirm: - message = pt.Message - defaultValue = pt.Default - case *survey.Input: - message = pt.Message - defaultValue = pt.Default - case *survey.Select: - message = pt.Message - options = pt.Options - case *survey.MultiSelect: - message = pt.Message - options = pt.Options - case *survey.Password: - message = pt.Message - case *surveyext.GhEditor: - message = pt.Message - defaultValue = pt.Default - default: - return fmt.Errorf("prompt type %T is not supported by the stubber", pt) - } - - var stub *QuestionStub - for _, s := range as.stubs { - if !s.matched && (s.message == "" && strings.EqualFold(s.Name, fieldName) || s.message == message) { - stub = s - stub.matched = true - break - } - } - if stub == nil { - return fmt.Errorf("no prompt stub for %q", message) - } - - if len(stub.options) > 0 { - if err := compareOptions(stub.options, options); err != nil { - return fmt.Errorf("stubbed options mismatch for %q: %v", message, err) - } - } - - userValue := stub.Value - - if stringValue, ok := stub.Value.(string); ok && len(options) > 0 { - foundIndex := -1 - for i, o := range options { - if o == stringValue { - foundIndex = i - break - } - } - if foundIndex < 0 { - return fmt.Errorf("answer %q not found in options for %q: %v", stringValue, message, options) - } - userValue = core.OptionAnswer{ - Value: stringValue, - Index: foundIndex, - } - } - - if stub.Default { - if defaultIndex, ok := defaultValue.(int); ok && len(options) > 0 { - userValue = core.OptionAnswer{ - Value: options[defaultIndex], - Index: defaultIndex, - } - } else if defaultValue == nil && len(options) > 0 { - userValue = core.OptionAnswer{ - Value: options[0], - Index: 0, - } - } else { - userValue = defaultValue - } - } - - if err := core.WriteAnswer(response, fieldName, userValue); err != nil { - topic := fmt.Sprintf("field %q", fieldName) - if fieldName == "" { - topic = fmt.Sprintf("%q", message) - } - return fmt.Errorf("AskStubber failed writing the answer for %s: %w", topic, err) - } - return nil - } - - SurveyAskOne = func(p survey.Prompt, response interface{}, opts ...survey.AskOpt) error { - return answerFromStub(p, "", response) - } - - SurveyAsk = func(qs []*survey.Question, response interface{}, opts ...survey.AskOpt) error { - for _, q := range qs { - if err := answerFromStub(q.Prompt, q.Name, response); err != nil { - return err - } - } - return nil - } - - teardown := func() { - SurveyAsk = origSurveyAsk - SurveyAskOne = origSurveyAskOne - } - return &as, teardown -} - -type QuestionStub struct { - Name string - Value interface{} - Default bool - - matched bool - message string - options []string -} - -// AssertOptions asserts the options presented to the user in Selects and MultiSelects. -func (s *QuestionStub) AssertOptions(opts []string) *QuestionStub { - s.options = opts - return s -} - -// AnswerWith defines an answer for the given stub. -func (s *QuestionStub) AnswerWith(v interface{}) *QuestionStub { - s.Value = v - return s -} - -// AnswerDefault marks the current stub to be answered with the default value for the prompt question. -func (s *QuestionStub) AnswerDefault() *QuestionStub { - s.Default = true - return s -} - -// Deprecated: use StubPrompt -func (as *AskStubber) StubOne(value interface{}) { - as.Stub([]*QuestionStub{{Value: value}}) -} - -// Deprecated: use StubPrompt -func (as *AskStubber) Stub(stubbedQuestions []*QuestionStub) { - as.stubs = append(as.stubs, stubbedQuestions...) -} - -// StubPrompt records a stub for an interactive prompt matched by its message. -func (as *AskStubber) StubPrompt(msg string) *QuestionStub { - stub := &QuestionStub{message: msg} - as.stubs = append(as.stubs, stub) - return stub -} - -func compareOptions(expected, got []string) error { - if len(expected) != len(got) { - return fmt.Errorf("expected %v, got %v (length mismatch)", expected, got) - } - for i, v := range expected { - if v != got[i] { - return fmt.Errorf("expected %v, got %v", expected, got) - } - } - return nil -} From 3a5d47b88e3dd34472b8fd74ffcbf82643020ce3 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 17 Aug 2023 17:17:26 -0500 Subject: [PATCH 17/18] linter appeasement --- pkg/cmd/pr/shared/editable.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/cmd/pr/shared/editable.go b/pkg/cmd/pr/shared/editable.go index decd6456c..cec3bfe8c 100644 --- a/pkg/cmd/pr/shared/editable.go +++ b/pkg/cmd/pr/shared/editable.go @@ -277,6 +277,9 @@ func EditFieldsSurvey(p EditPrompter, editable *Editable, editorCommand string) if editable.Reviewers.Edited { editable.Reviewers.Value, err = multiSelectSurvey( p, "Reviewers", editable.Reviewers.Default, editable.Reviewers.Options) + if err != nil { + return err + } } if editable.Assignees.Edited { editable.Assignees.Value, err = multiSelectSurvey( From bb42fa07aa7fd6044a875a82061ec3fe073a4962 Mon Sep 17 00:00:00 2001 From: azarashi Date: Fri, 18 Aug 2023 23:16:06 +0900 Subject: [PATCH 18/18] codespace: Handle HTTP request retry interruption (#7846) * codespace: Handle HTTP request retry interruption * codespace: Make the error message more detailed --- internal/codespaces/api/api.go | 2 +- internal/codespaces/codespaces.go | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/internal/codespaces/api/api.go b/internal/codespaces/api/api.go index c55b92400..d6b21c304 100644 --- a/internal/codespaces/api/api.go +++ b/internal/codespaces/api/api.go @@ -1159,6 +1159,6 @@ func (a *API) withRetry(f func() (*http.Response, error)) (*http.Response, error if resp.StatusCode < 500 { return resp, nil } - return nil, errors.New("retry") + return nil, fmt.Errorf("received response with status code %d", resp.StatusCode) }, backoff.WithMaxRetries(bo, 3)) } diff --git a/internal/codespaces/codespaces.go b/internal/codespaces/codespaces.go index 9db12f01e..8834f0e6c 100644 --- a/internal/codespaces/codespaces.go +++ b/internal/codespaces/codespaces.go @@ -35,6 +35,14 @@ type logger interface { Printf(f string, v ...interface{}) } +type TimeoutError struct { + message string +} + +func (e *TimeoutError) Error() string { + return e.message +} + // ConnectToLiveshare waits for a Codespace to become running, // and connects to it using a Live Share session. func ConnectToLiveshare(ctx context.Context, progress progressIndicator, sessionLogger logger, apiClient apiClient, codespace *api.Codespace) (*liveshare.Session, error) { @@ -63,15 +71,15 @@ func ConnectToLiveshare(ctx context.Context, progress progressIndicator, session return nil } - return errors.New("codespace not ready yet") + return &TimeoutError{message: "codespace not ready yet"} }, backoff.WithContext(expBackoff, ctx)) if err != nil { - var permErr *backoff.PermanentError - if errors.As(err, &permErr) { - return nil, err + var timeoutErr *TimeoutError + if errors.As(err, &timeoutErr) { + return nil, errors.New("timed out while waiting for the codespace to start") } - return nil, errors.New("timed out while waiting for the codespace to start") + return nil, err } }