diff --git a/pkg/cmd/auth/login/login_test.go b/pkg/cmd/auth/login/login_test.go index 4c20e2ed5..b7c8438cb 100644 --- a/pkg/cmd/auth/login/login_test.go +++ b/pkg/cmd/auth/login/login_test.go @@ -5,6 +5,7 @@ import ( "net/http" "os" "regexp" + "runtime" "testing" "github.com/MakeNowJust/heredoc" @@ -18,6 +19,21 @@ import ( "github.com/stretchr/testify/assert" ) +func stubHomeDir(t *testing.T, dir string) { + homeEnv := "HOME" + switch runtime.GOOS { + case "windows": + homeEnv = "USERPROFILE" + case "plan9": + homeEnv = "home" + } + oldHomeDir := os.Getenv(homeEnv) + os.Setenv(homeEnv, dir) + t.Cleanup(func() { + os.Setenv(homeEnv, oldHomeDir) + }) +} + func Test_NewCmdLogin(t *testing.T) { tests := []struct { name string @@ -352,6 +368,8 @@ func Test_loginRun_nontty(t *testing.T) { } func Test_loginRun_Survey(t *testing.T) { + stubHomeDir(t, t.TempDir()) + tests := []struct { name string opts *LoginOptions @@ -377,8 +395,8 @@ func Test_loginRun_Survey(t *testing.T) { // httpmock.StringResponse(`{"data":{"viewer":{"login":"jillv"}}}`)) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) // host type github.com - as.StubOne(false) // do not continue + as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub.com") + as.StubPrompt("You're already logged into github.com. Do you want to re-authenticate?").AnswerWith(false) }, wantHosts: "", // nothing should have been written to hosts wantErrOut: nil, @@ -396,10 +414,10 @@ func Test_loginRun_Survey(t *testing.T) { git_protocol: https `), askStubs: func(as *prompt.AskStubber) { - as.StubOne("HTTPS") // git_protocol - as.StubOne(false) // cache credentials - as.StubOne(1) // auth mode: token - as.StubOne("def456") // auth token + as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("HTTPS") + as.StubPrompt("Authenticate Git with your GitHub credentials?").AnswerWith(false) + as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token") + as.StubPrompt("Paste your authentication token:").AnswerWith("def456") }, runStubs: func(rs *run.CommandStubber) { rs.Register(`git config credential\.https:/`, 1, "") @@ -425,12 +443,12 @@ func Test_loginRun_Survey(t *testing.T) { Interactive: true, }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) // host type enterprise - as.StubOne("brad.vickers") // hostname - as.StubOne("HTTPS") // git_protocol - as.StubOne(false) // cache credentials - as.StubOne(1) // auth mode: token - as.StubOne("def456") // auth token + as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub Enterprise Server") + as.StubPrompt("GHE hostname:").AnswerWith("brad.vickers") + as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("HTTPS") + as.StubPrompt("Authenticate Git with your GitHub credentials?").AnswerWith(false) + as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token") + as.StubPrompt("Paste your authentication token:").AnswerWith("def456") }, runStubs: func(rs *run.CommandStubber) { rs.Register(`git config credential\.https:/`, 1, "") @@ -456,11 +474,11 @@ func Test_loginRun_Survey(t *testing.T) { Interactive: true, }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) // host type github.com - as.StubOne("HTTPS") // git_protocol - as.StubOne(false) // cache credentials - as.StubOne(1) // auth mode: token - as.StubOne("def456") // auth token + as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub.com") + as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("HTTPS") + as.StubPrompt("Authenticate Git with your GitHub credentials?").AnswerWith(false) + as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token") + as.StubPrompt("Paste your authentication token:").AnswerWith("def456") }, runStubs: func(rs *run.CommandStubber) { rs.Register(`git config credential\.https:/`, 1, "") @@ -480,11 +498,11 @@ func Test_loginRun_Survey(t *testing.T) { Interactive: true, }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) // host type github.com - as.StubOne("SSH") // git_protocol - as.StubOne(10) // TODO: SSH key selection - as.StubOne(1) // auth mode: token - as.StubOne("def456") // auth token + as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub.com") + as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("SSH") + as.StubPrompt("Generate a new SSH key to add to your GitHub account?").AnswerWith(false) + as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token") + as.StubPrompt("Paste your authentication token:").AnswerWith("def456") }, wantErrOut: regexp.MustCompile("Tip: you can generate a Personal Access Token here https://github.com/settings/tokens"), }, @@ -530,8 +548,7 @@ func Test_loginRun_Survey(t *testing.T) { hostsBuf := bytes.Buffer{} defer config.StubWriteConfig(&mainBuf, &hostsBuf)() - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) if tt.askStubs != nil { tt.askStubs(as) } diff --git a/pkg/cmd/auth/logout/logout_test.go b/pkg/cmd/auth/logout/logout_test.go index a5d46ef09..4d74caaf5 100644 --- a/pkg/cmd/auth/logout/logout_test.go +++ b/pkg/cmd/auth/logout/logout_test.go @@ -106,8 +106,8 @@ func Test_logoutRun_tty(t *testing.T) { cfgHosts: []string{"cheryl.mason", "github.com"}, wantHosts: "cheryl.mason:\n oauth_token: abc123\n", askStubs: func(as *prompt.AskStubber) { - as.StubOne("github.com") - as.StubOne(true) + as.StubPrompt("What account do you want to log out of?").AnswerWith("github.com") + as.StubPrompt("Are you sure you want to log out of github.com account 'cybilb'?").AnswerWith(true) }, wantErrOut: regexp.MustCompile(`Logged out of github.com account 'cybilb'`), }, @@ -116,7 +116,7 @@ func Test_logoutRun_tty(t *testing.T) { opts: &LogoutOptions{}, cfgHosts: []string{"github.com"}, askStubs: func(as *prompt.AskStubber) { - as.StubOne(true) + as.StubPrompt("Are you sure you want to log out of github.com account 'cybilb'?").AnswerWith(true) }, wantErrOut: regexp.MustCompile(`Logged out of github.com account 'cybilb'`), }, @@ -133,7 +133,7 @@ func Test_logoutRun_tty(t *testing.T) { cfgHosts: []string{"cheryl.mason", "github.com"}, wantHosts: "github.com:\n oauth_token: abc123\n", askStubs: func(as *prompt.AskStubber) { - as.StubOne(true) + as.StubPrompt("Are you sure you want to log out of cheryl.mason account 'cybilb'?").AnswerWith(true) }, wantErrOut: regexp.MustCompile(`Logged out of cheryl.mason account 'cybilb'`), }, @@ -169,8 +169,7 @@ func Test_logoutRun_tty(t *testing.T) { hostsBuf := bytes.Buffer{} defer config.StubWriteConfig(&mainBuf, &hostsBuf)() - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) if tt.askStubs != nil { tt.askStubs(as) } diff --git a/pkg/cmd/auth/refresh/refresh_test.go b/pkg/cmd/auth/refresh/refresh_test.go index 800913b1a..1bee8435d 100644 --- a/pkg/cmd/auth/refresh/refresh_test.go +++ b/pkg/cmd/auth/refresh/refresh_test.go @@ -194,7 +194,7 @@ func Test_refreshRun(t *testing.T) { Hostname: "", }, askStubs: func(as *prompt.AskStubber) { - as.StubOne("github.com") + as.StubPrompt("What account do you want to refresh auth for?").AnswerWith("github.com") }, wantAuthArgs: authArgs{ hostname: "github.com", @@ -276,8 +276,7 @@ func Test_refreshRun(t *testing.T) { hostsBuf := bytes.Buffer{} defer config.StubWriteConfig(&mainBuf, &hostsBuf)() - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) if tt.askStubs != nil { tt.askStubs(as) } diff --git a/pkg/cmd/auth/shared/login_flow_test.go b/pkg/cmd/auth/shared/login_flow_test.go index 530e34045..6f1b35ebe 100644 --- a/pkg/cmd/auth/shared/login_flow_test.go +++ b/pkg/cmd/auth/shared/login_flow_test.go @@ -47,14 +47,13 @@ func TestLogin_ssh(t *testing.T) { httpmock.REST("POST", "api/v3/user/keys"), httpmock.StringResponse(`{}`)) - ask, askRestore := prompt.InitAskStubber() - defer askRestore() + ask := prompt.NewAskStubber(t) - ask.StubOne("SSH") // preferred protocol - ask.StubOne(true) // generate a new key - ask.StubOne("monkey") // enter a passphrase - ask.StubOne(1) // paste a token - ask.StubOne("ATOKEN") // token + ask.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("SSH") + ask.StubPrompt("Generate a new SSH key to add to your GitHub account?").AnswerWith(true) + ask.StubPrompt("Enter a passphrase for your new SSH key (Optional)").AnswerWith("monkey") + ask.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token") + ask.StubPrompt("Paste your authentication token:").AnswerWith("ATOKEN") rs, runRestore := run.Stub() defer runRestore(t) diff --git a/pkg/cmd/extension/command_test.go b/pkg/cmd/extension/command_test.go index 5a46592f9..8f896eab0 100644 --- a/pkg/cmd/extension/command_test.go +++ b/pkg/cmd/extension/command_test.go @@ -316,8 +316,10 @@ func TestNewCmdExtension(t *testing.T) { }, isTTY: true, askStubs: func(as *prompt.AskStubber) { - as.StubOne("test") - as.StubOne(0) + as.StubPrompt("Extension name:").AnswerWith("test") + as.StubPrompt("What kind of extension?"). + AssertOptions([]string{"Script (Bash, Ruby, Python, etc)", "Go", "Other Precompiled (C++, Rust, etc)"}). + AnswerDefault() }, wantStdout: heredoc.Doc(` ✓ Created directory gh-test @@ -456,8 +458,7 @@ func TestNewCmdExtension(t *testing.T) { assertFunc = tt.managerStubs(em) } - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) if tt.askStubs != nil { tt.askStubs(as) } diff --git a/pkg/cmd/gist/delete/delete_test.go b/pkg/cmd/gist/delete/delete_test.go index 0d98a44c2..9d6574911 100644 --- a/pkg/cmd/gist/delete/delete_test.go +++ b/pkg/cmd/gist/delete/delete_test.go @@ -10,7 +10,6 @@ import ( "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" "github.com/cli/cli/v2/pkg/iostreams" - "github.com/cli/cli/v2/pkg/prompt" "github.com/google/shlex" "github.com/stretchr/testify/assert" ) @@ -61,7 +60,6 @@ func Test_deleteRun(t *testing.T) { opts *DeleteOptions gist *shared.Gist httpStubs func(*httpmock.Registry) - askStubs func(*prompt.AskStubber) nontty bool wantErr bool wantStderr string @@ -122,12 +120,6 @@ func Test_deleteRun(t *testing.T) { tt.httpStubs(reg) } - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - if tt.opts == nil { tt.opts = &DeleteOptions{} } diff --git a/pkg/cmd/gist/edit/edit_test.go b/pkg/cmd/gist/edit/edit_test.go index cac99b923..74c4f3502 100644 --- a/pkg/cmd/gist/edit/edit_test.go +++ b/pkg/cmd/gist/edit/edit_test.go @@ -146,8 +146,8 @@ func Test_editRun(t *testing.T) { { name: "multiple files, submit", askStubs: func(as *prompt.AskStubber) { - as.StubOne("unix.md") - as.StubOne("Submit") + as.StubPrompt("Edit which file?").AnswerWith("unix.md") + as.StubPrompt("What next?").AnswerWith("Submit") }, gist: &shared.Gist{ ID: "1234", @@ -191,8 +191,8 @@ func Test_editRun(t *testing.T) { { name: "multiple files, cancel", askStubs: func(as *prompt.AskStubber) { - as.StubOne("unix.md") - as.StubOne("Cancel") + as.StubPrompt("Edit which file?").AnswerWith("unix.md") + as.StubPrompt("What next?").AnswerWith("Cancel") }, wantErr: "CancelError", gist: &shared.Gist{ @@ -280,12 +280,6 @@ func Test_editRun(t *testing.T) { tt.httpStubs(reg) } - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - if tt.opts == nil { tt.opts = &EditOptions{} } @@ -308,6 +302,11 @@ func Test_editRun(t *testing.T) { } t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + err := editRun(tt.opts) reg.Verify(t) if tt.wantErr != "" { diff --git a/pkg/cmd/gist/view/view_test.go b/pkg/cmd/gist/view/view_test.go index cc58867cf..952490d7d 100644 --- a/pkg/cmd/gist/view/view_test.go +++ b/pkg/cmd/gist/view/view_test.go @@ -355,9 +355,8 @@ func Test_viewRun(t *testing.T) { )), ) - as, surveyteardown := prompt.InitAskStubber() - defer surveyteardown() - as.StubOne(0) + as := prompt.NewAskStubber(t) + as.StubPrompt("Select a gist").AnswerDefault() } if tt.opts == nil { @@ -392,16 +391,18 @@ func Test_viewRun(t *testing.T) { func Test_promptGists(t *testing.T) { tests := []struct { - name string - gistIndex int - response string - wantOut string - gist *shared.Gist - wantErr bool + name string + askStubs func(as *prompt.AskStubber) + response string + wantOut string + gist *shared.Gist + wantErr bool }{ { - name: "multiple files, select first gist", - gistIndex: 0, + name: "multiple files, select first gist", + askStubs: func(as *prompt.AskStubber) { + as.StubPrompt("Select a gist").AnswerWith("cool.txt about 6 hours ago") + }, response: `{ "data": { "viewer": { "gists": { "nodes": [ { "name": "gistid1", @@ -421,8 +422,10 @@ func Test_promptGists(t *testing.T) { wantOut: "gistid1", }, { - name: "multiple files, select second gist", - gistIndex: 1, + name: "multiple files, select second gist", + askStubs: func(as *prompt.AskStubber) { + as.StubPrompt("Select a gist").AnswerWith("gistfile0.txt about 6 hours ago") + }, response: `{ "data": { "viewer": { "gists": { "nodes": [ { "name": "gistid1", @@ -465,11 +468,12 @@ func Test_promptGists(t *testing.T) { ) client := &http.Client{Transport: reg} - as, surveyteardown := prompt.InitAskStubber() - defer surveyteardown() - as.StubOne(tt.gistIndex) - t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + gistID, err := promptGists(client, "github.com", io.ColorScheme()) assert.NoError(t, err) assert.Equal(t, tt.wantOut, gistID) diff --git a/pkg/cmd/issue/create/create_test.go b/pkg/cmd/issue/create/create_test.go index f8d948999..4eaea333a 100644 --- a/pkg/cmd/issue/create/create_test.go +++ b/pkg/cmd/issue/create/create_test.go @@ -401,27 +401,11 @@ func TestIssueCreate_recover(t *testing.T) { assert.Equal(t, []interface{}{"BUGID", "TODOID"}, inputs["labelIds"]) })) - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) - as.Stub([]*prompt.QuestionStub{ - { - Name: "Title", - Default: true, - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "Body", - Default: true, - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "confirmation", - Value: 0, - }, - }) + as.StubPrompt("Title").AnswerDefault() + as.StubPrompt("Body").AnswerDefault() + as.StubPrompt("What's next?").AnswerWith("Submit") tmpfile, err := ioutil.TempFile(t.TempDir(), "testrecover*") assert.NoError(t, err) @@ -484,25 +468,11 @@ func TestIssueCreate_nonLegacyTemplate(t *testing.T) { }), ) - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) - // template - as.StubOne(1) - // body - as.Stub([]*prompt.QuestionStub{ - { - Name: "Body", - Default: true, - }, - }) // body - // confirm - as.Stub([]*prompt.QuestionStub{ - { - Name: "confirmation", - Value: 0, - }, - }) + as.StubPrompt("Choose a template").AnswerWith("Submit a request") + as.StubPrompt("Body").AnswerDefault() + as.StubPrompt("What's next?").AnswerWith("Submit") output, err := runCommandWithRootDirOverridden(http, true, `-t hello`, "./fixtures/repoWithNonLegacyIssueTemplates") if err != nil { @@ -526,23 +496,10 @@ func TestIssueCreate_continueInBrowser(t *testing.T) { } } }`), ) - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) - // title - as.Stub([]*prompt.QuestionStub{ - { - Name: "Title", - Value: "hello", - }, - }) - // confirm - as.Stub([]*prompt.QuestionStub{ - { - Name: "confirmation", - Value: 1, - }, - }) + as.StubPrompt("Title").AnswerWith("hello") + as.StubPrompt("What's next?").AnswerWith("Continue in browser") _, cmdTeardown := run.Stub() defer cmdTeardown(t) diff --git a/pkg/cmd/issue/delete/delete_test.go b/pkg/cmd/issue/delete/delete_test.go index 3d5fd1761..d9cf089c3 100644 --- a/pkg/cmd/issue/delete/delete_test.go +++ b/pkg/cmd/issue/delete/delete_test.go @@ -75,9 +75,9 @@ func TestIssueDelete(t *testing.T) { assert.Equal(t, inputs["issueId"], "THE-ID") }), ) - as, teardown := prompt.InitAskStubber() - defer teardown() - as.StubOne("13") + + as := prompt.NewAskStubber(t) + as.StubPrompt("You're going to delete issue #13. This action cannot be reversed. To confirm, type the issue number:").AnswerWith("13") output, err := runCommand(httpRegistry, true, "13") if err != nil { @@ -103,9 +103,9 @@ func TestIssueDelete_cancel(t *testing.T) { "issue": { "id": "THE-ID", "number": 13, "title": "The title of the issue"} } } }`), ) - as, teardown := prompt.InitAskStubber() - defer teardown() - as.StubOne("14") + + as := prompt.NewAskStubber(t) + as.StubPrompt("You're going to delete issue #13. This action cannot be reversed. To confirm, type the issue number:").AnswerWith("14") output, err := runCommand(httpRegistry, true, "13") if err != nil { diff --git a/pkg/cmd/pr/create/create_test.go b/pkg/cmd/pr/create/create_test.go index 2b2d19e46..a6c785fdc 100644 --- a/pkg/cmd/pr/create/create_test.go +++ b/pkg/cmd/pr/create/create_test.go @@ -283,26 +283,13 @@ func TestPRCreate_recover(t *testing.T) { cs.Register(`git status --porcelain`, 0, "") cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() - as.Stub([]*prompt.QuestionStub{ - { - Name: "Title", - Default: true, - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "Body", - Default: true, - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "confirmation", - Value: 0, - }, - }) + + as.StubPrompt("Title").AnswerDefault() + as.StubPrompt("Body").AnswerDefault() + as.StubPrompt("What's next?").AnswerDefault() tmpfile, err := ioutil.TempFile(t.TempDir(), "testrecover*") assert.NoError(t, err) @@ -393,9 +380,11 @@ func TestPRCreate(t *testing.T) { cs.Register(`git show-ref --verify -- HEAD refs/remotes/origin/feature`, 0, "") cs.Register(`git push --set-upstream origin HEAD:feature`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber ask, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() - ask.StubOne(0) + + ask.StubPrompt("Where should we push the 'feature' branch?").AnswerDefault() output, err := runCommand(http, nil, "feature", true, `-t "my title" -b "my body"`) require.NoError(t, err) @@ -438,9 +427,11 @@ func TestPRCreate_NoMaintainerModify(t *testing.T) { cs.Register(`git show-ref --verify -- HEAD refs/remotes/origin/feature`, 0, "") cs.Register(`git push --set-upstream origin HEAD:feature`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber ask, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() - ask.StubOne(0) + + ask.StubPrompt("Where should we push the 'feature' branch?").AnswerDefault() output, err := runCommand(http, nil, "feature", true, `-t "my title" -b "my body" --no-maintainer-edit`) require.NoError(t, err) @@ -488,9 +479,13 @@ func TestPRCreate_createFork(t *testing.T) { cs.Register(`git remote add -f fork https://github.com/monalisa/REPO.git`, 0, "") cs.Register(`git push --set-upstream fork HEAD:feature`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber ask, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() - ask.StubOne(1) + + ask.StubPrompt("Where should we push the 'feature' branch?"). + AssertOptions([]string{"OWNER/REPO", "Create a fork of OWNER/REPO", "Skip pushing the branch", "Cancel"}). + AnswerWith("Create a fork of OWNER/REPO") output, err := runCommand(http, nil, "feature", true, `-t title -b body`) require.NoError(t, err) @@ -544,6 +539,7 @@ func TestPRCreate_pushedToNonBaseRepo(t *testing.T) { deadbeef refs/remotes/origin/feature `)) // determineTrackingBranch + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber _, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() @@ -585,6 +581,7 @@ func TestPRCreate_pushedToDifferentBranchName(t *testing.T) { deadbeef refs/remotes/origin/my-feat2 `)) // determineTrackingBranch + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber _, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() @@ -618,21 +615,17 @@ func TestPRCreate_nonLegacyTemplate(t *testing.T) { cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "1234567890,commit 0\n2345678901,commit 1") cs.Register(`git status --porcelain`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() - as.StubOne(0) // template - as.Stub([]*prompt.QuestionStub{ - { - Name: "Body", - Default: true, - }, - }) // body - as.Stub([]*prompt.QuestionStub{ - { - Name: "confirmation", - Value: 0, - }, - }) // confirm + + as.StubPrompt("Choose a template"). + AssertOptions([]string{"Bug fix", "Open a blank pull request"}). + AnswerWith("Bug fix") + as.StubPrompt("Body").AnswerDefault() + as.StubPrompt("What's next?"). + AssertOptions([]string{"Submit", "Continue in browser", "Add metadata", "Cancel"}). + AnswerDefault() output, err := runCommandWithRootDirOverridden(http, nil, "feature", true, `-t "my title" -H feature`, "./fixtures/repoWithNonLegacyPRTemplates") require.NoError(t, err) @@ -771,9 +764,13 @@ func TestPRCreate_web(t *testing.T) { cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "") cs.Register(`git push --set-upstream origin HEAD:feature`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber ask, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() - ask.StubOne(0) + + ask.StubPrompt("Where should we push the 'feature' branch?"). + AssertOptions([]string{"OWNER/REPO", "Skip pushing the branch", "Cancel"}). + AnswerDefault() output, err := runCommand(http, nil, "feature", true, `--web`) require.NoError(t, err) @@ -842,9 +839,11 @@ func TestPRCreate_webProject(t *testing.T) { cs.Register(`git( .+)? log( .+)? origin/master\.\.\.feature`, 0, "") cs.Register(`git push --set-upstream origin HEAD:feature`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber ask, cleanupAsk := prompt.InitAskStubber() defer cleanupAsk() - ask.StubOne(0) + + ask.StubPrompt("Where should we push the 'feature' branch?").AnswerDefault() output, err := runCommand(http, nil, "feature", true, `--web -p Triage`) require.NoError(t, err) diff --git a/pkg/cmd/pr/merge/merge_test.go b/pkg/cmd/pr/merge/merge_test.go index 679142b82..d692b0a08 100644 --- a/pkg/cmd/pr/merge/merge_test.go +++ b/pkg/cmd/pr/merge/merge_test.go @@ -769,8 +769,10 @@ func TestPrMerge_alreadyMerged(t *testing.T) { cs.Register(`git branch -D blueberries`, 0, "") cs.Register(`git pull --ff-only`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, surveyTeardown := prompt.InitAskStubber() defer surveyTeardown() + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(true) output, err := runCommand(http, "blueberries", true, "pr merge 4") @@ -846,11 +848,15 @@ func TestPRMerge_interactive(t *testing.T) { cs.Register(`git rev-parse --verify refs/heads/blueberries`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, surveyTeardown := prompt.InitAskStubber() defer surveyTeardown() - as.StubOne(0) // Merge method survey - as.StubOne(false) // Delete branch survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(0) // Merge method survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(false) // Delete branch survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Submit") // Confirm submit survey output, err := runCommand(http, "blueberries", true, "") @@ -905,10 +911,13 @@ func TestPRMerge_interactiveWithDeleteBranch(t *testing.T) { cs.Register(`git branch -D blueberries`, 0, "") cs.Register(`git pull --ff-only`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, surveyTeardown := prompt.InitAskStubber() defer surveyTeardown() - as.StubOne(0) // Merge method survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(0) // Merge method survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Submit") // Confirm submit survey output, err := runCommand(http, "blueberries", true, "-d") @@ -964,14 +973,20 @@ func TestPRMerge_interactiveSquashEditCommitMsgAndSubject(t *testing.T) { _, cmdTeardown := run.Stub() defer cmdTeardown(t) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, surveyTeardown := prompt.InitAskStubber() defer surveyTeardown() - as.StubOne(2) // Merge method survey - as.StubOne(false) // Delete branch survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(2) // Merge method survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(false) // Delete branch survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Edit commit subject") // Confirm submit survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Edit commit message") // Confirm submit survey - as.StubOne("Submit") // Confirm submit survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne("Submit") // Confirm submit survey err := mergeRun(&MergeOptions{ IO: io, @@ -1017,11 +1032,15 @@ func TestPRMerge_interactiveCancelled(t *testing.T) { cs.Register(`git rev-parse --verify refs/heads/`, 0, "") + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, surveyTeardown := prompt.InitAskStubber() defer surveyTeardown() - as.StubOne(0) // Merge method survey - as.StubOne(true) // Delete branch survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(0) // Merge method survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(true) // Delete branch survey + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Cancel") // Confirm submit survey output, err := runCommand(http, "blueberries", true, "") @@ -1038,8 +1057,10 @@ func Test_mergeMethodSurvey(t *testing.T) { RebaseMergeAllowed: true, SquashMergeAllowed: true, } + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, surveyTeardown := prompt.InitAskStubber() defer surveyTeardown() + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(0) // Select first option which is rebase merge method, err := mergeMethodSurvey(repo) assert.Nil(t, err) diff --git a/pkg/cmd/pr/review/review_test.go b/pkg/cmd/pr/review/review_test.go index 75ae8c200..e0ee7b071 100644 --- a/pkg/cmd/pr/review/review_test.go +++ b/pkg/cmd/pr/review/review_test.go @@ -270,21 +270,25 @@ func TestPRReview_interactive(t *testing.T) { }), ) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { Name: "reviewType", Value: "Approve", }, }) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { Name: "body", Value: "cool story", }, }) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { Name: "confirm", @@ -309,27 +313,10 @@ func TestPRReview_interactive_no_body(t *testing.T) { shared.RunCommandFinder("", &api.PullRequest{ID: "THE-ID", Number: 123}, ghrepo.New("OWNER", "REPO")) - as, teardown := prompt.InitAskStubber() - defer teardown() + as := prompt.NewAskStubber(t) - as.Stub([]*prompt.QuestionStub{ - { - Name: "reviewType", - Value: "Request changes", - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "body", - Default: true, - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "confirm", - Value: true, - }, - }) + as.StubPrompt("What kind of review do you want to give?").AnswerWith("Request changes") + as.StubPrompt("Review body").AnswerWith("") _, err := runCommand(http, nil, true, "") assert.EqualError(t, err, "this type of review cannot be blank") @@ -350,21 +337,25 @@ func TestPRReview_interactive_blank_approve(t *testing.T) { }), ) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { Name: "reviewType", Value: "Approve", }, }) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { Name: "body", Default: true, }, }) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ { Name: "confirm", diff --git a/pkg/cmd/pr/shared/survey_test.go b/pkg/cmd/pr/shared/survey_test.go index a28d96198..52d20d505 100644 --- a/pkg/cmd/pr/shared/survey_test.go +++ b/pkg/cmd/pr/shared/survey_test.go @@ -43,15 +43,18 @@ func TestMetadataSurvey_selectAll(t *testing.T) { }, } + //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{ { Name: "reviewers", @@ -71,7 +74,7 @@ func TestMetadataSurvey_selectAll(t *testing.T) { }, { Name: "milestone", - Value: []string{"(none)"}, + Value: "(none)", }, }) @@ -109,15 +112,18 @@ func TestMetadataSurvey_keepExisting(t *testing.T) { }, } + //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{ { Name: "labels", diff --git a/pkg/cmd/pr/shared/templates_test.go b/pkg/cmd/pr/shared/templates_test.go index 5ef0d7f72..03d522be6 100644 --- a/pkg/cmd/pr/shared/templates_test.go +++ b/pkg/cmd/pr/shared/templates_test.go @@ -63,9 +63,11 @@ func TestTemplateManager_hasAPI(t *testing.T) { assert.Equal(t, "LEGACY", string(m.LegacyBody())) + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, askRestore := prompt.InitAskStubber() defer askRestore() + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(1) // choose "Feature Request" tpl, err := m.Choose() assert.NoError(t, err) diff --git a/pkg/cmd/release/create/create_test.go b/pkg/cmd/release/create/create_test.go index f13150002..a6f6a2d7a 100644 --- a/pkg/cmd/release/create/create_test.go +++ b/pkg/cmd/release/create/create_test.go @@ -515,27 +515,16 @@ func Test_createRun_interactive(t *testing.T) { name: "create a release from existing tag", opts: &CreateOptions{}, askStubs: func(as *prompt.AskStubber) { - as.StubOne("v1.2.3") // Tag prompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "name", - Value: "title", - }, - { - Name: "releaseNotesAction", - Value: "Leave blank", - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "prerelease", - Value: false, - }, - { - Name: "submitAction", - Value: "Publish release", - }, - }) + as.StubPrompt("Choose a tag"). + AssertOptions([]string{"v1.2.3", "v1.2.2", "v1.0.0", "v0.1.2", "Create a new tag"}). + AnswerWith("v1.2.3") + as.StubPrompt("Title (optional)").AnswerWith("") + as.StubPrompt("Release notes"). + AssertOptions([]string{"Write my own", "Write using generated notes as template", "Leave blank"}). + AnswerWith("Leave blank") + as.StubPrompt("Is this a prerelease?").AnswerWith(false) + as.StubPrompt("Submit?"). + AssertOptions([]string{"Publish release", "Save as draft", "Cancel"}).AnswerWith("Publish release") }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[ @@ -558,28 +547,12 @@ func Test_createRun_interactive(t *testing.T) { name: "create a release from new tag", opts: &CreateOptions{}, askStubs: func(as *prompt.AskStubber) { - as.StubOne("Create a new tag") // Tag prompt - as.StubOne("v1.2.3") // New tag prompt - as.Stub([]*prompt.QuestionStub{ - { - Name: "name", - Value: "title", - }, - { - Name: "releaseNotesAction", - Value: "Leave blank", - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "prerelease", - Value: false, - }, - { - Name: "submitAction", - Value: "Publish release", - }, - }) + as.StubPrompt("Choose a tag").AnswerWith("Create a new tag") + as.StubPrompt("Tag name").AnswerWith("v1.2.3") + as.StubPrompt("Title (optional)").AnswerWith("") + as.StubPrompt("Release notes").AnswerWith("Leave blank") + as.StubPrompt("Is this a prerelease?").AnswerWith(false) + as.StubPrompt("Submit?").AnswerWith("Publish release") }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("GET", "repos/OWNER/REPO/tags"), httpmock.StatusStringResponse(200, `[ @@ -604,26 +577,10 @@ func Test_createRun_interactive(t *testing.T) { TagName: "v1.2.3", }, askStubs: func(as *prompt.AskStubber) { - as.Stub([]*prompt.QuestionStub{ - { - Name: "name", - Value: "title", - }, - { - Name: "releaseNotesAction", - Value: "Write using generated notes as template", - }, - }) - as.Stub([]*prompt.QuestionStub{ - { - Name: "prerelease", - Value: false, - }, - { - Name: "submitAction", - Value: "Publish release", - }, - }) + as.StubPrompt("Title (optional)").AnswerDefault() + as.StubPrompt("Release notes").AnswerWith("Write using generated notes as template") + as.StubPrompt("Is this a prerelease?").AnswerWith(false) + as.StubPrompt("Submit?").AnswerWith("Publish release") }, httpStubs: func(reg *httpmock.Registry) { reg.Register(httpmock.REST("POST", "repos/OWNER/REPO/releases/generate-notes"), @@ -641,7 +598,7 @@ func Test_createRun_interactive(t *testing.T) { wantParams: map[string]interface{}{ "body": "generated body", "draft": false, - "name": "title", + "name": "generated name", "prerelease": false, "tag_name": "v1.2.3", }, @@ -674,6 +631,7 @@ func Test_createRun_interactive(t *testing.T) { return val, nil } + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/repo/archive/archive_test.go b/pkg/cmd/repo/archive/archive_test.go index b3feff532..a60f15765 100644 --- a/pkg/cmd/repo/archive/archive_test.go +++ b/pkg/cmd/repo/archive/archive_test.go @@ -80,6 +80,7 @@ func Test_ArchiveRun(t *testing.T) { name: "unarchived repo tty", wantStdout: "✓ Archived repository OWNER/REPO\n", askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne(true) }, isTTY: true, @@ -98,6 +99,7 @@ func Test_ArchiveRun(t *testing.T) { wantStdout: "✓ Archived repository OWNER/REPO\n", opts: ArchiveOptions{}, askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne(true) }, isTTY: true, @@ -138,6 +140,7 @@ func Test_ArchiveRun(t *testing.T) { io, _, stdout, stderr := iostreams.Test() tt.opts.IO = io + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber q, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/repo/create/create_test.go b/pkg/cmd/repo/create/create_test.go index 9048845fd..7c50dba46 100644 --- a/pkg/cmd/repo/create/create_test.go +++ b/pkg/cmd/repo/create/create_test.go @@ -171,22 +171,30 @@ func Test_createRun(t *testing.T) { tty: true, wantStdout: "✓ Created repository OWNER/REPO on GitHub\n", askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Create a new repository on GitHub from scratch") + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "repoName", Value: "REPO"}, {Name: "repoDescription", Value: "my new repo"}, - {Name: "repoVisibility", Value: "PRIVATE"}, + {Name: "repoVisibility", Value: "Private"}, }) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "addGitIgnore", Value: true}}) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "chooseGitIgnore", Value: "Go"}}) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "addLicense", Value: true}}) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "chooseLicense", Value: "GNU Lesser General Public License v3.0"}}) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "confirmSubmit", Value: true}}) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(true) //clone locally? }, httpStubs: func(reg *httpmock.Registry) { @@ -210,16 +218,21 @@ func Test_createRun(t *testing.T) { opts: &CreateOptions{Interactive: true}, tty: true, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Create a new repository on GitHub from scratch") + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "repoName", Value: "REPO"}, {Name: "repoDescription", Value: "my new repo"}, - {Name: "repoVisibility", Value: "PRIVATE"}, + {Name: "repoVisibility", Value: "Private"}, }) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "addGitIgnore", Value: false}}) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "addLicense", Value: false}}) + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "confirmSubmit", Value: false}}) }, @@ -232,13 +245,17 @@ func Test_createRun(t *testing.T) { opts: &CreateOptions{Interactive: true}, tty: true, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Push an existing local repository to GitHub") + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(".") + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "repoName", Value: "REPO"}, {Name: "repoDescription", Value: "my new repo"}, - {Name: "repoVisibility", Value: "PRIVATE"}, + {Name: "repoVisibility", Value: "Private"}, }) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(false) }, httpStubs: func(reg *httpmock.Registry) { @@ -269,16 +286,22 @@ func Test_createRun(t *testing.T) { opts: &CreateOptions{Interactive: true}, tty: true, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Push an existing local repository to GitHub") + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(".") + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "repoName", Value: "REPO"}, {Name: "repoDescription", Value: "my new repo"}, - {Name: "repoVisibility", Value: "PRIVATE"}, + {Name: "repoVisibility", Value: "Private"}, }) - as.StubOne(true) //ask for adding a remote + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(true) //ask for adding a remote + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("origin") //ask for remote name - as.StubOne(false) //ask to push to remote + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(false) //ask to push to remote }, httpStubs: func(reg *httpmock.Registry) { reg.Register( @@ -309,16 +332,22 @@ func Test_createRun(t *testing.T) { opts: &CreateOptions{Interactive: true}, tty: true, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("Push an existing local repository to GitHub") + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(".") + //nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt as.Stub([]*prompt.QuestionStub{ {Name: "repoName", Value: "REPO"}, {Name: "repoDescription", Value: "my new repo"}, - {Name: "repoVisibility", Value: "PRIVATE"}, + {Name: "repoVisibility", Value: "Private"}, }) - as.StubOne(true) //ask for adding a remote + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(true) //ask for adding a remote + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne("origin") //ask for remote name - as.StubOne(true) //ask to push to remote + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt + as.StubOne(true) //ask to push to remote }, httpStubs: func(reg *httpmock.Registry) { reg.Register( @@ -407,6 +436,7 @@ func Test_createRun(t *testing.T) { }, } for _, tt := range tests { + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber q, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/repo/delete/delete_test.go b/pkg/cmd/repo/delete/delete_test.go index da9c04223..3bd3e5d22 100644 --- a/pkg/cmd/repo/delete/delete_test.go +++ b/pkg/cmd/repo/delete/delete_test.go @@ -94,6 +94,7 @@ func Test_deleteRun(t *testing.T) { askStubs: func(q *prompt.AskStubber) { // TODO: survey stubber doesn't have WithValidator support // so this always passes regardless of prompt input + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne("OWNER/REPO") }, httpStubs: func(reg *httpmock.Registry) { @@ -108,6 +109,7 @@ func Test_deleteRun(t *testing.T) { opts: &DeleteOptions{}, wantStdout: "✓ Deleted repository OWNER/REPO\n", askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne("OWNER/REPO") }, httpStubs: func(reg *httpmock.Registry) { @@ -134,6 +136,7 @@ func Test_deleteRun(t *testing.T) { wantStdout: "✓ Deleted repository OWNER/REPO\n", tty: true, askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne("OWNER/REPO") }, httpStubs: func(reg *httpmock.Registry) { @@ -147,6 +150,7 @@ func Test_deleteRun(t *testing.T) { }, } for _, tt := range tests { + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber q, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/repo/fork/fork_test.go b/pkg/cmd/repo/fork/fork_test.go index 775152440..5fb458b93 100644 --- a/pkg/cmd/repo/fork/fork_test.go +++ b/pkg/cmd/repo/fork/fork_test.go @@ -236,6 +236,7 @@ func TestRepoFork(t *testing.T) { }, httpStubs: forkPost, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(false) }, wantErrOut: "✓ Created fork someone/REPO\n", @@ -254,6 +255,7 @@ func TestRepoFork(t *testing.T) { cs.Register(`git remote add -f origin https://github.com/someone/REPO.git`, 0, "") }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(true) }, wantErrOut: "✓ Created fork someone/REPO\n✓ Added remote origin\n", @@ -442,6 +444,7 @@ func TestRepoFork(t *testing.T) { }, httpStubs: forkPost, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(false) }, wantErrOut: "✓ Created fork someone/REPO\n", @@ -455,6 +458,7 @@ func TestRepoFork(t *testing.T) { }, httpStubs: forkPost, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(true) }, execStubs: func(cs *run.CommandStubber) { @@ -475,6 +479,7 @@ func TestRepoFork(t *testing.T) { }, httpStubs: forkPost, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(true) }, execStubs: func(cs *run.CommandStubber) { @@ -570,6 +575,7 @@ func TestRepoFork(t *testing.T) { return tt.remotes, nil } + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/repo/rename/rename_test.go b/pkg/cmd/repo/rename/rename_test.go index 042579613..a886befaa 100644 --- a/pkg/cmd/repo/rename/rename_test.go +++ b/pkg/cmd/repo/rename/rename_test.go @@ -117,6 +117,7 @@ func TestRenameRun(t *testing.T) { name: "none argument", wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote\n", askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne("NEW_REPO") }, httpStubs: func(reg *httpmock.Registry) { @@ -136,6 +137,7 @@ func TestRenameRun(t *testing.T) { }, wantOut: "✓ Renamed repository OWNER/NEW_REPO\n", askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne("NEW_REPO") }, httpStubs: func(reg *httpmock.Registry) { @@ -184,6 +186,7 @@ func TestRenameRun(t *testing.T) { }, wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote\n", askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne(true) }, httpStubs: func(reg *httpmock.Registry) { @@ -204,6 +207,7 @@ func TestRenameRun(t *testing.T) { DoConfirm: true, }, askStubs: func(q *prompt.AskStubber) { + //nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt q.StubOne(false) }, wantOut: "", @@ -211,6 +215,7 @@ func TestRenameRun(t *testing.T) { } for _, tt := range testCases { + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber q, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/run/cancel/cancel_test.go b/pkg/cmd/run/cancel/cancel_test.go index 9304ee8fb..99a286137 100644 --- a/pkg/cmd/run/cancel/cancel_test.go +++ b/pkg/cmd/run/cancel/cancel_test.go @@ -174,6 +174,7 @@ func TestRunCancel(t *testing.T) { httpmock.StatusStringResponse(202, "{}")) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(0) }, wantOut: "✓ Request to cancel workflow submitted.\n", @@ -195,6 +196,7 @@ func TestRunCancel(t *testing.T) { return ghrepo.FromFullName("OWNER/REPO") } + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/run/rerun/rerun_test.go b/pkg/cmd/run/rerun/rerun_test.go index 11c5ff983..11362ce4b 100644 --- a/pkg/cmd/run/rerun/rerun_test.go +++ b/pkg/cmd/run/rerun/rerun_test.go @@ -137,6 +137,7 @@ func TestRerun(t *testing.T) { httpmock.StringResponse("{}")) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) }, wantOut: "✓ Requested rerun of run 1234\n", @@ -193,6 +194,7 @@ func TestRerun(t *testing.T) { return ghrepo.FromFullName("OWNER/REPO") } + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/run/view/view_test.go b/pkg/cmd/run/view/view_test.go index 7b61d3b2f..2a0540985 100644 --- a/pkg/cmd/run/view/view_test.go +++ b/pkg/cmd/run/view/view_test.go @@ -375,6 +375,7 @@ func TestViewRun(t *testing.T) { httpmock.JSONResponse([]shared.Annotation{})) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) }, opts: &ViewOptions{ @@ -411,7 +412,9 @@ func TestViewRun(t *testing.T) { httpmock.FileResponse("./fixtures/run_log.zip")) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(1) }, wantOut: coolJobRunLogOutput, @@ -464,7 +467,9 @@ func TestViewRun(t *testing.T) { httpmock.FileResponse("./fixtures/run_log.zip")) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(0) }, wantOut: expectedRunLogOutput, @@ -523,7 +528,9 @@ func TestViewRun(t *testing.T) { httpmock.FileResponse("./fixtures/run_log.zip")) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(4) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) }, wantOut: quuxTheBarfLogOutput, @@ -576,7 +583,9 @@ func TestViewRun(t *testing.T) { httpmock.FileResponse("./fixtures/run_log.zip")) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(4) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(0) }, wantOut: quuxTheBarfLogOutput, @@ -700,7 +709,9 @@ func TestViewRun(t *testing.T) { httpmock.JSONResponse(shared.FailedJobAnnotations)) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(0) }, wantOut: "\n✓ trunk successful · 3\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\nX sad job in 4m34s (ID 20)\n ✓ barf the quux\n X quux the barf\n\nANNOTATIONS\nX the job is sad\nsad job: blaze.py#420\n\n\nFor more information about a job, try: gh run view --job=\nView this run on GitHub: https://github.com/runs/3\n", @@ -733,7 +744,9 @@ func TestViewRun(t *testing.T) { httpmock.JSONResponse([]shared.Annotation{})) }, askStubs: func(as *prompt.AskStubber) { + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(2) + //nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt as.StubOne(1) }, wantOut: "\n✓ trunk successful · 3\nTriggered via push about 59 minutes ago\n\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\nTo see the full job log, try: gh run view --log --job=10\nView this run on GitHub: https://github.com/runs/3\n", @@ -830,6 +843,7 @@ func TestViewRun(t *testing.T) { return ghrepo.FromFullName("OWNER/REPO") } + //nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber as, teardown := prompt.InitAskStubber() defer teardown() if tt.askStubs != nil { diff --git a/pkg/cmd/run/watch/watch_test.go b/pkg/cmd/run/watch/watch_test.go index a96f826f4..a21df2217 100644 --- a/pkg/cmd/run/watch/watch_test.go +++ b/pkg/cmd/run/watch/watch_test.go @@ -234,7 +234,9 @@ func TestWatchRun(t *testing.T) { }, httpStubs: successfulRunStubs, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Select a workflow run"). + AssertOptions([]string{"* cool commit, run (trunk) Feb 23, 2021", "* cool commit, more runs (trunk) Feb 23, 2021"}). + AnswerWith("* cool commit, more runs (trunk) Feb 23, 2021") }, wantOut: "\x1b[2J\x1b[0;0H\x1b[JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n* trunk more runs · 2\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\x1b[0;0H\x1b[JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n✓ trunk more runs · 2\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\n✓ Run more runs (2) completed with 'success'\n", }, @@ -247,7 +249,9 @@ func TestWatchRun(t *testing.T) { }, httpStubs: successfulRunStubs, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Select a workflow run"). + AssertOptions([]string{"* cool commit, run (trunk) Feb 23, 2021", "* cool commit, more runs (trunk) Feb 23, 2021"}). + AnswerWith("* cool commit, more runs (trunk) Feb 23, 2021") }, wantOut: "\x1b[2J\x1b[2JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n* trunk more runs · 2\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\x1b[2JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n✓ trunk more runs · 2\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n", }, @@ -262,7 +266,9 @@ func TestWatchRun(t *testing.T) { }, httpStubs: failedRunStubs, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Select a workflow run"). + AssertOptions([]string{"* cool commit, run (trunk) Feb 23, 2021", "* cool commit, more runs (trunk) Feb 23, 2021"}). + AnswerWith("* cool commit, more runs (trunk) Feb 23, 2021") }, wantOut: "\x1b[2J\x1b[0;0H\x1b[JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n* trunk more runs · 2\nTriggered via push about 59 minutes ago\n\n\x1b[0;0H\x1b[JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\nX trunk more runs · 2\nTriggered via push about 59 minutes ago\n\nJOBS\nX sad job in 4m34s (ID 20)\n ✓ barf the quux\n X quux the barf\n\nANNOTATIONS\nX the job is sad\nsad job: blaze.py#420\n\n\nX Run more runs (2) completed with 'failure'\n", wantErr: true, @@ -278,7 +284,9 @@ func TestWatchRun(t *testing.T) { }, httpStubs: failedRunStubs, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Select a workflow run"). + AssertOptions([]string{"* cool commit, run (trunk) Feb 23, 2021", "* cool commit, more runs (trunk) Feb 23, 2021"}). + AnswerWith("* cool commit, more runs (trunk) Feb 23, 2021") }, wantOut: "\x1b[2J\x1b[2JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n* trunk more runs · 2\nTriggered via push about 59 minutes ago\n\n\x1b[2JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\nX trunk more runs · 2\nTriggered via push about 59 minutes ago\n\nJOBS\nX sad job in 4m34s (ID 20)\n ✓ barf the quux\n X quux the barf\n\nANNOTATIONS\nX the job is sad\nsad job: blaze.py#420\n\n", wantErr: true, @@ -313,13 +321,12 @@ func TestWatchRun(t *testing.T) { return ghrepo.FromFullName("OWNER/REPO") } - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + err := watchRun(tt.opts) if tt.wantErr { assert.EqualError(t, err, tt.errMsg) diff --git a/pkg/cmd/secret/set/set_test.go b/pkg/cmd/secret/set/set_test.go index d65ed1cae..29a2c4758 100644 --- a/pkg/cmd/secret/set/set_test.go +++ b/pkg/cmd/secret/set/set_test.go @@ -487,10 +487,8 @@ func Test_getBodyPrompt(t *testing.T) { io.SetStdinTTY(true) io.SetStdoutTTY(true) - as, teardown := prompt.InitAskStubber() - defer teardown() - - as.StubOne("cool secret") + as := prompt.NewAskStubber(t) + as.StubPrompt("Paste your secret").AnswerWith("cool secret") body, err := getBody(&SetOptions{ IO: io, diff --git a/pkg/cmd/workflow/disable/disable_test.go b/pkg/cmd/workflow/disable/disable_test.go index 1057da6a9..a1adbdd45 100644 --- a/pkg/cmd/workflow/disable/disable_test.go +++ b/pkg/cmd/workflow/disable/disable_test.go @@ -121,7 +121,7 @@ func TestDisableRun(t *testing.T) { httpmock.StatusStringResponse(204, "{}")) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Select a workflow").AnswerWith("another workflow (another.yml)") }, wantOut: "✓ Disabled another workflow\n", }, @@ -176,7 +176,7 @@ func TestDisableRun(t *testing.T) { httpmock.StatusStringResponse(204, "{}")) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Which workflow do you mean?").AnswerWith("another workflow (yetanother.yml)") }, wantOut: "✓ Disabled another workflow\n", }, @@ -277,13 +277,12 @@ func TestDisableRun(t *testing.T) { return ghrepo.FromFullName("OWNER/REPO") } - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + err := runDisable(tt.opts) if tt.wantErr { assert.Error(t, err) diff --git a/pkg/cmd/workflow/enable/enable_test.go b/pkg/cmd/workflow/enable/enable_test.go index fb0e703bb..cfc9ea79c 100644 --- a/pkg/cmd/workflow/enable/enable_test.go +++ b/pkg/cmd/workflow/enable/enable_test.go @@ -121,7 +121,7 @@ func TestEnableRun(t *testing.T) { httpmock.StatusStringResponse(204, "{}")) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) + as.StubPrompt("Select a workflow").AnswerWith("a disabled workflow (disabled.yml)") }, wantOut: "✓ Enabled a disabled workflow\n", }, @@ -176,7 +176,7 @@ func TestEnableRun(t *testing.T) { httpmock.StatusStringResponse(204, "{}")) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(1) + as.StubPrompt("Which workflow do you mean?").AnswerWith("a disabled workflow (anotherDisabled.yml)") }, wantOut: "✓ Enabled a disabled workflow\n", }, @@ -194,9 +194,6 @@ func TestEnableRun(t *testing.T) { httpmock.REST("PUT", "repos/OWNER/REPO/actions/workflows/456/enable"), httpmock.StatusStringResponse(204, "{}")) }, - askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) - }, wantOut: "✓ Enabled a disabled workflow\n", }, { @@ -279,13 +276,12 @@ func TestEnableRun(t *testing.T) { return ghrepo.FromFullName("OWNER/REPO") } - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + err := runEnable(tt.opts) if tt.wantErr { assert.Error(t, err) diff --git a/pkg/cmd/workflow/run/run_test.go b/pkg/cmd/workflow/run/run_test.go index 196f1850d..1f42164ff 100644 --- a/pkg/cmd/workflow/run/run_test.go +++ b/pkg/cmd/workflow/run/run_test.go @@ -557,7 +557,7 @@ jobs: httpmock.StatusStringResponse(204, "cool")) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) + as.StubPrompt("Select a workflow").AnswerDefault() }, wantBody: map[string]interface{}{ "inputs": map[string]interface{}{}, @@ -594,17 +594,9 @@ jobs: httpmock.StatusStringResponse(204, "cool")) }, askStubs: func(as *prompt.AskStubber) { - as.StubOne(0) - as.Stub([]*prompt.QuestionStub{ - { - Name: "greeting", - Default: true, - }, - { - Name: "name", - Value: "scully", - }, - }) + as.StubPrompt("Select a workflow").AnswerDefault() + as.StubPrompt("greeting").AnswerWith("hi") + as.StubPrompt("name").AnswerWith("scully") }, wantBody: map[string]interface{}{ "inputs": map[string]interface{}{ @@ -638,12 +630,12 @@ jobs: }, "github.com"), nil } - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } t.Run(tt.name, func(t *testing.T) { + as := prompt.NewAskStubber(t) + if tt.askStubs != nil { + tt.askStubs(as) + } + err := runRun(tt.opts) if tt.wantErr { assert.Error(t, err) diff --git a/pkg/cmd/workflow/view/view_test.go b/pkg/cmd/workflow/view/view_test.go index b035070bf..dd89cf83e 100644 --- a/pkg/cmd/workflow/view/view_test.go +++ b/pkg/cmd/workflow/view/view_test.go @@ -13,7 +13,6 @@ import ( "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" "github.com/cli/cli/v2/pkg/iostreams" - "github.com/cli/cli/v2/pkg/prompt" "github.com/google/shlex" "github.com/stretchr/testify/assert" ) @@ -189,7 +188,6 @@ func TestViewRun(t *testing.T) { name string opts *ViewOptions httpStubs func(*httpmock.Registry) - askStubs func(*prompt.AskStubber) tty bool wantOut string wantErrOut string @@ -417,12 +415,6 @@ func TestViewRun(t *testing.T) { browser := &cmdutil.TestBrowser{} tt.opts.Browser = browser - as, teardown := prompt.InitAskStubber() - defer teardown() - if tt.askStubs != nil { - tt.askStubs(as) - } - t.Run(tt.name, func(t *testing.T) { err := runView(tt.opts) if tt.wantErr { diff --git a/pkg/prompt/stubber.go b/pkg/prompt/stubber.go index be920cd25..8d9e22520 100644 --- a/pkg/prompt/stubber.go +++ b/pkg/prompt/stubber.go @@ -2,73 +2,143 @@ package prompt import ( "fmt" - "reflect" + "strings" "github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2/core" + "github.com/cli/cli/v2/pkg/surveyext" ) type AskStubber struct { - Asks [][]*survey.Question - AskOnes []*survey.Prompt - Count int - OneCount int - Stubs [][]*QuestionStub - StubOnes []*PromptStub + stubs []*QuestionStub } +type testing interface { + Errorf(format string, args ...interface{}) + Cleanup(func()) +} + +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{} - SurveyAskOne = func(p survey.Prompt, response interface{}, opts ...survey.AskOpt) error { - as.AskOnes = append(as.AskOnes, &p) - count := as.OneCount - as.OneCount += 1 - if count >= len(as.StubOnes) { - panic(fmt.Sprintf("more asks than stubs. most recent call: %v", p)) - } - stubbedPrompt := as.StubOnes[count] - if stubbedPrompt.Default { - // TODO this is failing for basic AskOne invocations with a string result. - defaultValue := reflect.ValueOf(p).Elem().FieldByName("Default") - _ = core.WriteAnswer(response, "", defaultValue) - } else { - _ = core.WriteAnswer(response, "", stubbedPrompt.Value) + 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 { - as.Asks = append(as.Asks, qs) - count := as.Count - as.Count += 1 - if count >= len(as.Stubs) { - panic(fmt.Sprintf("more asks than stubs. most recent call: %#v", qs)) - } - - // actually set response - stubbedQuestions := as.Stubs[count] - if len(stubbedQuestions) != len(qs) { - panic(fmt.Sprintf("asked questions: %d; stubbed questions: %d", len(qs), len(stubbedQuestions))) - } - for i, sq := range stubbedQuestions { - q := qs[i] - if q.Name != sq.Name { - panic(fmt.Sprintf("stubbed question mismatch: %s != %s", q.Name, sq.Name)) - } - if sq.Default { - defaultValue := reflect.ValueOf(q.Prompt).Elem().FieldByName("Default") - _ = core.WriteAnswer(response, q.Name, defaultValue) - } else { - _ = core.WriteAnswer(response, q.Name, sq.Value) + for _, q := range qs { + if err := answerFromStub(q.Prompt, q.Name, response); err != nil { + return err } } - return nil } + teardown := func() { SurveyAsk = origSurveyAsk SurveyAskOne = origSurveyAskOne @@ -76,30 +146,59 @@ func InitAskStubber() (*AskStubber, func()) { return &as, teardown } -type PromptStub struct { - Value interface{} - Default bool -} - 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.StubOnes = append(as.StubOnes, &PromptStub{ - Value: value, - }) -} - -func (as *AskStubber) StubOneDefault() { - as.StubOnes = append(as.StubOnes, &PromptStub{ - Default: true, - }) + as.Stub([]*QuestionStub{{Value: value}}) } +// Deprecated: use StubPrompt func (as *AskStubber) Stub(stubbedQuestions []*QuestionStub) { - // A call to .Ask takes a list of questions; a stub is then a list of questions in the same order. - as.Stubs = append(as.Stubs, stubbedQuestions) + 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 }