Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for negative default in confirm prompt, fixes #6103 #6118

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/ddev/cmd/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func apppush(providerType string, app *ddevapp.DdevApp, skipConfirmation bool, s
}

util.Warning("You're about to push your local %s to your upstream production\nand replace it with your local project's %s.\nThis is normally a very dangerous operation.", message, message)
if !util.Confirm("Would you like to continue (not recommended)?") {
if !util.ConfirmTo("Would you like to continue (not recommended)?", false) {
util.Failed("Push cancelled")
}
}
Expand Down
24 changes: 23 additions & 1 deletion pkg/util/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,35 @@ func Prompt(prompt string, defaultValue string) string {
// Confirm handles the asking and interpreting of a basic yes/no question.
// If DDEV_NONINTERACTIVE is set, Confirm() returns true. The prompt will be
// presented at most three times before returning false.
// Defaults to true if left blank.
func Confirm(prompt string) bool {
return ConfirmTo(prompt, true)
}

// ConfirmTo handles the asking and interpreting of a basic yes/no question.
// If DDEV_NONINTERACTIVE is set, Confirm() returns true.
// If response is blank, the defaultTo value is returned.
// If response is invalid, the prompt will be presented at most three times
// before returning false.
func ConfirmTo(prompt string, defaultTo bool) bool {
if len(os.Getenv("DDEV_NONINTERACTIVE")) > 0 {
return true
}

var promptOptions string
var promptDefaultValue string

if defaultTo {
promptOptions = "Y/n"
promptDefaultValue = "yes"
} else {
promptOptions = "y/N"
promptDefaultValue = "no"
}

for i := 0; i < 3; i++ {
resp := strings.ToLower(Prompt(fmt.Sprintf("%s [Y/n]", prompt), "yes"))
resp := strings.ToLower(Prompt(fmt.Sprintf("%s [%s]", prompt, promptOptions), promptDefaultValue))

if resp == "yes" || resp == "y" {
return true
}
Expand Down
58 changes: 27 additions & 31 deletions pkg/util/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ func TestCaptureOutputToFile(t *testing.T) {
assert.Contains(out, "randstring-stderr="+text)
}

// TestConfirm ensures that the confirmation prompt works as expected.
func TestConfirm(t *testing.T) {
// TestConfirmTo ensures that the confirmation prompt works as expected.
func TestConfirmTo(t *testing.T) {
assert := asrt.New(t)

// Unset the env var, then reset after the test
Expand All @@ -117,47 +117,43 @@ func TestConfirm(t *testing.T) {
t.Fatal(err.Error())
}

yesses := []string{"YES", "Yes", "yes", "Y", "y"}
for _, y := range yesses {
// test a given input against a default value
testInput := func(input string, defaultTo bool, expected bool) {
text := util.RandString(32)
scanner := bufio.NewScanner(strings.NewReader(y))
scanner := bufio.NewScanner(strings.NewReader(input))
util.SetInputScanner(scanner)

getOutput := util.CaptureStdOut()
resp := util.Confirm(text)
assert.True(resp)
resp := util.ConfirmTo(text, defaultTo)
if expected {
assert.True(resp)
} else {
assert.False(resp)
}
assert.Contains(getOutput(), text)
}

yesses := []string{"YES", "Yes", "yes", "Y", "y"}
for _, y := range yesses {
testInput(y, true, true)
testInput(y, false, true)
}

nos := []string{"NO", "No", "no", "N", "n"}
for _, n := range nos {
text := util.RandString(32)
scanner := bufio.NewScanner(strings.NewReader(n))
util.SetInputScanner(scanner)

getOutput := util.CaptureStdOut()
resp := util.Confirm(text)
assert.False(resp)
assert.Contains(getOutput(), text)
testInput(n, true, false)
testInput(n, false, false)
}

// Test that junk answers (not yes, no, or <enter>) eventually return a false
scanner := bufio.NewScanner(strings.NewReader("a\nb\na\nb\na\nb\na\nb\na\nb\n"))
util.SetInputScanner(scanner)
getOutput := util.CaptureStdOut()
text := util.RandString(32)
resp := util.Confirm(text)
assert.False(resp)
assert.Contains(getOutput(), text)

// Test that <enter> returns true
scanner = bufio.NewScanner(strings.NewReader("\n"))
util.SetInputScanner(scanner)
getOutput = util.CaptureStdOut()
text = util.RandString(32)
resp = util.Confirm(text)
assert.True(resp)
assert.Contains(getOutput(), text)
junkText := "a\nb\na\nb\na\nb\na\nb\na\nb\n"
testInput(junkText, true, false)
testInput(junkText, false, false)

// Test that <enter> returns the defaultTo value
enter := "\n"
testInput(enter, true, true)
testInput(enter, false, false)
}

// TestSliceToUniqueSlice tests SliceToUniqueSlice
Expand Down