Use custom prompter for bundle template inputs (#663)

## Changes
Prompt UI glitches often. We are switching to a custom implementation of
a simple prompter which is much more stable.
This also allows new lines in prompts which has been an ask by the
mlflow team.

## Tests
Tested manually
This commit is contained in:
shreyas-goenka 2023-08-15 16:50:20 +02:00 committed by GitHub
parent 878bb6deae
commit 61b103318f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 50 additions and 22 deletions

View File

@ -27,7 +27,7 @@ func (m *delete) Apply(ctx context.Context, b *bundle.Bundle) error {
red := color.New(color.FgRed).SprintFunc() red := color.New(color.FgRed).SprintFunc()
if !b.AutoApprove { if !b.AutoApprove {
proceed, err := cmdio.Ask(ctx, fmt.Sprintf("\n%s and all files in it will be %s Proceed?", b.Config.Workspace.RootPath, red("deleted permanently!"))) proceed, err := cmdio.AskYesOrNo(ctx, fmt.Sprintf("\n%s and all files in it will be %s Proceed?", b.Config.Workspace.RootPath, red("deleted permanently!")))
if err != nil { if err != nil {
return err return err
} }

View File

@ -89,7 +89,7 @@ func (w *destroy) Apply(ctx context.Context, b *bundle.Bundle) error {
// Ask for confirmation, if needed // Ask for confirmation, if needed
if !b.Plan.ConfirmApply { if !b.Plan.ConfirmApply {
red := color.New(color.FgRed).SprintFunc() red := color.New(color.FgRed).SprintFunc()
b.Plan.ConfirmApply, err = cmdio.Ask(ctx, fmt.Sprintf("\nThis will permanently %s resources! Proceed?", red("destroy"))) b.Plan.ConfirmApply, err = cmdio.AskYesOrNo(ctx, fmt.Sprintf("\nThis will permanently %s resources! Proceed?", red("destroy")))
if err != nil { if err != nil {
return err return err
} }

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"strings"
"github.com/databricks/cli/libs/flags" "github.com/databricks/cli/libs/flags"
) )
@ -74,33 +75,64 @@ func LogError(ctx context.Context, err error) {
}) })
} }
func Ask(ctx context.Context, question string) (bool, error) { func Ask(ctx context.Context, question, defaultVal string) (string, error) {
logger, ok := FromContext(ctx) logger, ok := FromContext(ctx)
if !ok { if !ok {
logger = Default() logger = Default()
} }
return logger.Ask(question) return logger.Ask(question, defaultVal)
} }
func (l *Logger) Ask(question string) (bool, error) { func AskYesOrNo(ctx context.Context, question string) (bool, error) {
if l.Mode == flags.ModeJson { logger, ok := FromContext(ctx)
return false, fmt.Errorf("question prompts are not supported in json mode") if !ok {
logger = Default()
} }
// Add acceptable answers to the question prompt. // Add acceptable answers to the question prompt.
question += ` [y/n]:` question += ` [y/n]`
l.Writer.Write([]byte(question))
ans, err := l.Reader.ReadString('\n')
// Ask the question
ans, err := logger.Ask(question, "")
if err != nil { if err != nil {
return false, err return false, err
} }
if ans == "y\n" { if ans == "y" {
return true, nil return true, nil
} else {
return false, nil
} }
return false, nil
}
func (l *Logger) Ask(question string, defaultVal string) (string, error) {
if l.Mode == flags.ModeJson {
return "", fmt.Errorf("question prompts are not supported in json mode")
}
// Add default value to question prompt.
if defaultVal != "" {
question += fmt.Sprintf(` [%s]`, defaultVal)
}
question += `: `
// print prompt
_, err := l.Writer.Write([]byte(question))
if err != nil {
return "", err
}
// read user input. Trim new line characters
ans, err := l.Reader.ReadString('\n')
if err != nil {
return "", err
}
ans = strings.Trim(ans, "\n\r")
// Return default value if user just presses enter
if ans == "" {
return defaultVal, nil
}
return ans, nil
} }
func (l *Logger) writeJson(event Event) { func (l *Logger) writeJson(event Event) {

View File

@ -9,6 +9,6 @@ import (
func TestAskFailedInJsonMode(t *testing.T) { func TestAskFailedInJsonMode(t *testing.T) {
l := NewLogger(flags.ModeJson) l := NewLogger(flags.ModeJson)
_, err := l.Ask("What is your spirit animal?") _, err := l.Ask("What is your spirit animal?", "")
assert.ErrorContains(t, err, "question prompts are not supported in json mode") assert.ErrorContains(t, err, "question prompts are not supported in json mode")
} }

View File

@ -123,22 +123,18 @@ func (c *config) promptForValues() error {
continue continue
} }
// Initialize Prompt dialog
var err error
prompt := cmdio.Prompt(c.ctx)
prompt.Label = property.Description
prompt.AllowEdit = true
// Compute default value to display by converting it to a string // Compute default value to display by converting it to a string
var defaultVal string
var err error
if property.Default != nil { if property.Default != nil {
prompt.Default, err = toString(property.Default, property.Type) defaultVal, err = toString(property.Default, property.Type)
if err != nil { if err != nil {
return err return err
} }
} }
// Get user input by running the prompt // Get user input by running the prompt
userInput, err := prompt.Run() userInput, err := cmdio.Ask(c.ctx, property.Description, defaultVal)
if err != nil { if err != nil {
return err return err
} }