Skip to content

Commit

Permalink
feat: Add support for negative default in confirm prompt, fixes #6103 (
Browse files Browse the repository at this point in the history
…#6118)

Co-authored-by: Randy Fay <randy@randyfay.com>
  • Loading branch information
cballenar and rfay committed May 16, 2024
1 parent 354feef commit cbe6bc4
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 33 deletions.
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

0 comments on commit cbe6bc4

Please sign in to comment.