Merge pull request #7850 from cli/noch-prompts

update more prompts
This commit is contained in:
Nate Smith 2023-08-17 17:38:17 -05:00 committed by GitHub
commit a51aba0d22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 90 additions and 89 deletions

View file

@ -258,7 +258,7 @@ func (m *MockPrompter) RegisterInputHostname(stub func() (string, error)) {
}
func (m *MockPrompter) RegisterPassword(prompt string, stub func(string) (string, error)) {
m.PasswordStubs = append(m.PasswordStubs, PasswordStub{Fn: stub})
m.PasswordStubs = append(m.PasswordStubs, PasswordStub{Prompt: prompt, Fn: stub})
}
func (m *MockPrompter) RegisterConfirmDeletion(prompt string, stub func(string) error) {

View file

@ -3,16 +3,13 @@ package delete
import (
"fmt"
"net/http"
"strconv"
"github.com/AlecAivazis/survey/v2"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/cmd/issue/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/cli/cli/v2/pkg/prompt"
"github.com/shurcooL/githubv4"
"github.com/spf13/cobra"
)
@ -22,16 +19,22 @@ type DeleteOptions struct {
Config func() (config.Config, error)
IO *iostreams.IOStreams
BaseRepo func() (ghrepo.Interface, error)
Prompter iprompter
SelectorArg string
Confirmed bool
}
type iprompter interface {
ConfirmDeletion(string) error
}
func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command {
opts := &DeleteOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
Config: f.Config,
Prompter: f.Prompter,
}
cmd := &cobra.Command{
@ -79,22 +82,12 @@ func deleteRun(opts *DeleteOptions) error {
// When executed in an interactive shell, require confirmation, unless
// already provided. Otherwise skip confirmation.
if opts.IO.CanPrompt() && !opts.Confirmed {
answer := ""
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
err = prompt.SurveyAskOne(
&survey.Input{
Message: fmt.Sprintf("You're going to delete issue #%d. This action cannot be reversed. To confirm, type the issue number:", issue.Number),
},
&answer,
)
cs := opts.IO.ColorScheme()
fmt.Printf("%s Deleted issues cannot be recovered.\n", cs.WarningIcon())
err := opts.Prompter.ConfirmDeletion(fmt.Sprintf("%d", issue.Number))
if err != nil {
return err
}
answerInt, err := strconv.Atoi(answer)
if err != nil || answerInt != issue.Number {
fmt.Fprintf(opts.IO.Out, "Issue #%d was not deleted.\n", issue.Number)
return nil
}
}
if err := apiDelete(httpClient, baseRepo, issue.ID); err != nil {

View file

@ -2,6 +2,7 @@ package delete
import (
"bytes"
"errors"
"io"
"net/http"
"regexp"
@ -9,16 +10,16 @@ import (
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/prompter"
"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/cli/cli/v2/test"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
)
func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
func runCommand(rt http.RoundTripper, pm *prompter.MockPrompter, isTTY bool, cli string) (*test.CmdOut, error) {
ios, _, stdout, stderr := iostreams.Test()
ios.SetStdoutTTY(isTTY)
ios.SetStdinTTY(isTTY)
@ -26,6 +27,7 @@ func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, err
factory := &cmdutil.Factory{
IOStreams: ios,
Prompter: pm,
HttpClient: func() (*http.Client, error) {
return &http.Client{Transport: rt}, nil
},
@ -76,11 +78,10 @@ func TestIssueDelete(t *testing.T) {
}),
)
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
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")
pm := prompter.NewMockPrompter(t)
pm.RegisterConfirmDeletion("13", func(_ string) error { return nil })
output, err := runCommand(httpRegistry, true, "13")
output, err := runCommand(httpRegistry, pm, true, "13")
if err != nil {
t.Fatalf("error running command `issue delete`: %v", err)
}
@ -112,7 +113,7 @@ func TestIssueDelete_confirm(t *testing.T) {
}),
)
output, err := runCommand(httpRegistry, true, "13 --confirm")
output, err := runCommand(httpRegistry, nil, true, "13 --confirm")
if err != nil {
t.Fatalf("error running command `issue delete`: %v", err)
}
@ -137,19 +138,17 @@ func TestIssueDelete_cancel(t *testing.T) {
} } }`),
)
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
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")
pm := prompter.NewMockPrompter(t)
pm.RegisterConfirmDeletion("13", func(_ string) error {
return errors.New("You entered 14")
})
output, err := runCommand(httpRegistry, true, "13")
if err != nil {
t.Fatalf("error running command `issue delete`: %v", err)
_, err := runCommand(httpRegistry, pm, true, "13")
if err == nil {
t.Fatalf("expected error")
}
r := regexp.MustCompile(`Issue #13 was not deleted`)
if !r.MatchString(output.String()) {
t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.String())
if err.Error() != "You entered 14" {
t.Fatalf("got unexpected error '%s'", err)
}
}
@ -166,7 +165,7 @@ func TestIssueDelete_doesNotExist(t *testing.T) {
`),
)
_, err := runCommand(httpRegistry, true, "13")
_, err := runCommand(httpRegistry, nil, true, "13")
if err == nil || err.Error() != "GraphQL: Could not resolve to an Issue with the number of 13." {
t.Errorf("error running command `issue delete`: %v", err)
}
@ -199,7 +198,7 @@ func TestIssueDelete_issuesDisabled(t *testing.T) {
}`),
)
_, err := runCommand(httpRegistry, true, "13")
_, err := runCommand(httpRegistry, nil, true, "13")
if err == nil || err.Error() != "the 'OWNER/REPO' repository has disabled issues" {
t.Fatalf("got error: %v", err)
}

View file

@ -19,13 +19,16 @@ import (
"github.com/cli/cli/v2/pkg/cmd/repo/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/cli/cli/v2/pkg/prompt"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const defaultRemoteName = "origin"
type iprompter interface {
Confirm(string, bool) (bool, error)
}
type ForkOptions struct {
HttpClient func() (*http.Client, error)
GitClient *git.Client
@ -35,6 +38,7 @@ type ForkOptions struct {
Remotes func() (ghContext.Remotes, error)
Since func(time.Time) time.Duration
BackOff backoff.BackOff
Prompter iprompter
GitArgs []string
Repository string
@ -65,6 +69,7 @@ func NewCmdFork(f *cmdutil.Factory, runF func(*ForkOptions) error) *cobra.Comman
Config: f.Config,
BaseRepo: f.BaseRepo,
Remotes: f.Remotes,
Prompter: f.Prompter,
Since: time.Since,
}
@ -273,10 +278,9 @@ func forkRun(opts *ForkOptions) error {
remoteDesired := opts.Remote
if opts.PromptRemote {
//nolint:staticcheck // SA1019: prompt.Confirm is deprecated: use Prompter
err = prompt.Confirm("Would you like to add a remote for the fork?", &remoteDesired)
remoteDesired, err = opts.Prompter.Confirm("Would you like to add a remote for the fork?", false)
if err != nil {
return fmt.Errorf("failed to prompt: %w", err)
return err
}
}
@ -317,10 +321,9 @@ func forkRun(opts *ForkOptions) error {
} else {
cloneDesired := opts.Clone
if opts.PromptClone {
//nolint:staticcheck // SA1019: prompt.Confirm is deprecated: use Prompter
err = prompt.Confirm("Would you like to clone the fork?", &cloneDesired)
cloneDesired, err = opts.Prompter.Confirm("Would you like to clone the fork?", false)
if err != nil {
return fmt.Errorf("failed to prompt: %w", err)
return err
}
}
if cloneDesired {

View file

@ -14,11 +14,11 @@ import (
"github.com/cli/cli/v2/git"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/prompter"
"github.com/cli/cli/v2/internal/run"
"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"
)
@ -205,18 +205,18 @@ func TestRepoFork(t *testing.T) {
}
tests := []struct {
name string
opts *ForkOptions
tty bool
httpStubs func(*httpmock.Registry)
execStubs func(*run.CommandStubber)
askStubs func(*prompt.AskStubber)
cfgStubs func(*config.ConfigMock)
remotes []*context.Remote
wantOut string
wantErrOut string
wantErr bool
errMsg string
name string
opts *ForkOptions
tty bool
httpStubs func(*httpmock.Registry)
execStubs func(*run.CommandStubber)
promptStubs func(*prompter.MockPrompter)
cfgStubs func(*config.ConfigMock)
remotes []*context.Remote
wantOut string
wantErrOut string
wantErr bool
errMsg string
}{
{
name: "implicit match, configured protocol overrides provided",
@ -272,9 +272,10 @@ func TestRepoFork(t *testing.T) {
RemoteName: defaultRemoteName,
},
httpStubs: forkPost,
askStubs: func(as *prompt.AskStubber) {
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
as.StubOne(false)
promptStubs: func(pm *prompter.MockPrompter) {
pm.RegisterConfirm("Would you like to add a remote for the fork?", func(_ string, _ bool) (bool, error) {
return false, nil
})
},
wantErrOut: "✓ Created fork someone/REPO\n",
},
@ -291,9 +292,10 @@ func TestRepoFork(t *testing.T) {
cs.Register("git remote rename origin upstream", 0, "")
cs.Register(`git remote add 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)
promptStubs: func(pm *prompter.MockPrompter) {
pm.RegisterConfirm("Would you like to add a remote for the fork?", func(_ string, _ bool) (bool, error) {
return true, nil
})
},
wantErrOut: "✓ Created fork someone/REPO\n✓ Added remote origin\n",
},
@ -497,9 +499,10 @@ func TestRepoFork(t *testing.T) {
PromptClone: true,
},
httpStubs: forkPost,
askStubs: func(as *prompt.AskStubber) {
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
as.StubOne(false)
promptStubs: func(pm *prompter.MockPrompter) {
pm.RegisterConfirm("Would you like to clone the fork?", func(_ string, _ bool) (bool, error) {
return false, nil
})
},
wantErrOut: "✓ Created fork someone/REPO\n",
},
@ -511,9 +514,10 @@ func TestRepoFork(t *testing.T) {
PromptClone: true,
},
httpStubs: forkPost,
askStubs: func(as *prompt.AskStubber) {
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
as.StubOne(true)
promptStubs: func(pm *prompter.MockPrompter) {
pm.RegisterConfirm("Would you like to clone the fork?", func(_ string, _ bool) (bool, error) {
return true, nil
})
},
execStubs: func(cs *run.CommandStubber) {
cs.Register(`git clone https://github.com/someone/REPO\.git`, 0, "")
@ -533,9 +537,10 @@ func TestRepoFork(t *testing.T) {
},
},
httpStubs: forkPost,
askStubs: func(as *prompt.AskStubber) {
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
as.StubOne(true)
promptStubs: func(pm *prompter.MockPrompter) {
pm.RegisterConfirm("Would you like to clone the fork?", func(_ string, _ bool) (bool, error) {
return true, nil
})
},
execStubs: func(cs *run.CommandStubber) {
cs.Register(`git clone https://github.com/someone/REPO\.git`, 0, "")
@ -746,11 +751,10 @@ func TestRepoFork(t *testing.T) {
GitPath: "some/path/git",
}
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
as, teardown := prompt.InitAskStubber()
defer teardown()
if tt.askStubs != nil {
tt.askStubs(as)
pm := prompter.NewMockPrompter(t)
tt.opts.Prompter = pm
if tt.promptStubs != nil {
tt.promptStubs(pm)
}
cs, restoreRun := run.Stub()

View file

@ -9,7 +9,6 @@ import (
"os"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/config"
@ -17,7 +16,6 @@ import (
"github.com/cli/cli/v2/pkg/cmd/secret/shared"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/cli/cli/v2/pkg/prompt"
"github.com/hashicorp/go-multierror"
"github.com/joho/godotenv"
"github.com/spf13/cobra"
@ -29,6 +27,7 @@ type SetOptions struct {
IO *iostreams.IOStreams
Config func() (config.Config, error)
BaseRepo func() (ghrepo.Interface, error)
Prompter iprompter
RandomOverride func() io.Reader
@ -44,11 +43,16 @@ type SetOptions struct {
Application string
}
type iprompter interface {
Password(string) (string, error)
}
func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command {
opts := &SetOptions{
IO: f.IOStreams,
Config: f.Config,
HttpClient: f.HttpClient,
Prompter: f.Prompter,
}
cmd := &cobra.Command{
@ -375,11 +379,7 @@ func getBody(opts *SetOptions) ([]byte, error) {
}
if opts.IO.CanPrompt() {
var bodyInput string
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
err := prompt.SurveyAskOne(&survey.Password{
Message: "Paste your secret",
}, &bodyInput)
bodyInput, err := opts.Prompter.Password("Paste your secret")
if err != nil {
return nil, err
}

View file

@ -12,11 +12,11 @@ import (
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/internal/config"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/prompter"
"github.com/cli/cli/v2/pkg/cmd/secret/shared"
"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"
)
@ -595,12 +595,14 @@ func Test_getBodyPrompt(t *testing.T) {
ios.SetStdinTTY(true)
ios.SetStdoutTTY(true)
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
as := prompt.NewAskStubber(t)
as.StubPrompt("Paste your secret").AnswerWith("cool secret")
pm := prompter.NewMockPrompter(t)
pm.RegisterPassword("Paste your secret", func(_ string) (string, error) {
return "cool secret", nil
})
body, err := getBody(&SetOptions{
IO: ios,
IO: ios,
Prompter: pm,
})
assert.NoError(t, err)
assert.Equal(t, string(body), "cool secret")