Skip to content

Commit

Permalink
Do not allow input prompts in Git Bash terminal (#1069)
Browse files Browse the repository at this point in the history
## Changes

Likely due to fact that Git Bash does not correctly support ANSI escape
sequences, we cannot use `promptui` package there. See known issues:

- manifoldco/promptui#208
- chzyer/readline#191
  • Loading branch information
andrewnester authored Dec 18, 2023
1 parent 4765493 commit 6dd6899
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 10 deletions.
2 changes: 1 addition & 1 deletion cmd/bundle/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ See https://docs.databricks.com/en/dev-tools/bundles/templates.html for more inf
templatePath = args[0]
} else {
var err error
if !cmdio.IsOutTTY(ctx) || !cmdio.IsInTTY(ctx) {
if !cmdio.IsPromptSupported(ctx) {
return errors.New("please specify a template")
}
templatePath, err = cmdio.AskSelect(ctx, "Template to use", nativeTemplateOptions())
Expand Down
2 changes: 1 addition & 1 deletion cmd/bundle/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func newRunCommand() *cobra.Command {
}

// If no arguments are specified, prompt the user to select something to run.
if len(args) == 0 && cmdio.IsInteractive(ctx) {
if len(args) == 0 && cmdio.IsPromptSupported(ctx) {
// Invert completions from KEY -> NAME, to NAME -> KEY.
inv := make(map[string]string)
for k, v := range run.ResourceCompletionMap(b) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/labs/project/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (i *installer) recordVersion(ctx context.Context) error {
}

func (i *installer) login(ctx context.Context) (*databricks.WorkspaceClient, error) {
if !cmdio.IsInteractive(ctx) {
if !cmdio.IsPromptSupported(ctx) {
log.Debugf(ctx, "Skipping workspace profile prompts in non-interactive mode")
return nil, nil
}
Expand Down
8 changes: 4 additions & 4 deletions cmd/labs/project/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (lc *loginConfig) askWorkspaceProfile(ctx context.Context, cfg *config.Conf
lc.WorkspaceProfile = cfg.Profile
return
}
if !cmdio.IsInteractive(ctx) {
if !cmdio.IsPromptSupported(ctx) {
return ErrNotInTTY
}
lc.WorkspaceProfile, err = root.AskForWorkspaceProfile(ctx)
Expand All @@ -66,7 +66,7 @@ func (lc *loginConfig) askCluster(ctx context.Context, w *databricks.WorkspaceCl
lc.ClusterID = w.Config.ClusterID
return
}
if !cmdio.IsInteractive(ctx) {
if !cmdio.IsPromptSupported(ctx) {
return ErrNotInTTY
}
clusterID, err := cfgpickers.AskForCluster(ctx, w,
Expand All @@ -87,7 +87,7 @@ func (lc *loginConfig) askWarehouse(ctx context.Context, w *databricks.Workspace
lc.WarehouseID = w.Config.WarehouseID
return
}
if !cmdio.IsInteractive(ctx) {
if !cmdio.IsPromptSupported(ctx) {
return ErrNotInTTY
}
lc.WarehouseID, err = cfgpickers.AskForWarehouse(ctx, w,
Expand All @@ -99,7 +99,7 @@ func (lc *loginConfig) askAccountProfile(ctx context.Context, cfg *config.Config
if !lc.HasAccountLevelCommands() {
return nil
}
if !cmdio.IsInteractive(ctx) {
if !cmdio.IsPromptSupported(ctx) {
return ErrNotInTTY
}
lc.AccountProfile, err = root.AskForAccountProfile(ctx)
Expand Down
4 changes: 2 additions & 2 deletions cmd/root/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func accountClientOrPrompt(ctx context.Context, cfg *config.Config, allowPrompt
}

prompt := false
if allowPrompt && err != nil && cmdio.IsInteractive(ctx) {
if allowPrompt && err != nil && cmdio.IsPromptSupported(ctx) {
// Prompt to select a profile if the current configuration is not an account client.
prompt = prompt || errors.Is(err, databricks.ErrNotAccountClient)
// Prompt to select a profile if the current configuration doesn't resolve to a credential provider.
Expand Down Expand Up @@ -109,7 +109,7 @@ func workspaceClientOrPrompt(ctx context.Context, cfg *config.Config, allowPromp
}

prompt := false
if allowPrompt && err != nil && cmdio.IsInteractive(ctx) {
if allowPrompt && err != nil && cmdio.IsPromptSupported(ctx) {
// Prompt to select a profile if the current configuration is not a workspace client.
prompt = prompt || errors.Is(err, databricks.ErrNotWorkspaceClient)
// Prompt to select a profile if the current configuration doesn't resolve to a credential provider.
Expand Down
25 changes: 25 additions & 0 deletions libs/cmdio/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/briandowns/spinner"
"github.com/databricks/cli/libs/env"
"github.com/databricks/cli/libs/flags"
"github.com/manifoldco/promptui"
"github.com/mattn/go-isatty"
Expand Down Expand Up @@ -88,6 +89,30 @@ func (c *cmdIO) IsTTY() bool {
return isatty.IsTerminal(fd) || isatty.IsCygwinTerminal(fd)
}

func IsPromptSupported(ctx context.Context) bool {
// We do not allow prompting in non-interactive mode and in Git Bash on Windows.
// Likely due to fact that Git Bash does not (correctly support ANSI escape sequences,
// we cannot use promptui package there.
// See known issues:
// - https://github.com/manifoldco/promptui/issues/208
// - https://github.com/chzyer/readline/issues/191
// We also do not allow prompting in non-interactive mode,
// because it's not possible to read from stdin in non-interactive mode.
return (IsInteractive(ctx) || (IsOutTTY(ctx) && IsInTTY(ctx))) && !IsGitBash(ctx)
}

func IsGitBash(ctx context.Context) bool {
// Check if the MSYSTEM environment variable is set to "MINGW64"
msystem := env.Get(ctx, "MSYSTEM")
if strings.EqualFold(msystem, "MINGW64") {
// Check for typical Git Bash env variable for prompts
ps1 := env.Get(ctx, "PS1")
return strings.Contains(ps1, "MINGW") || strings.Contains(ps1, "MSYSTEM")
}

return false
}

func Render(ctx context.Context, v any) error {
c := fromContext(ctx)
return RenderWithTemplate(ctx, v, c.template)
Expand Down
21 changes: 21 additions & 0 deletions libs/cmdio/io_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cmdio

import (
"context"
"testing"

"github.com/databricks/cli/libs/env"
"github.com/stretchr/testify/assert"
)

func TestIsPromptSupportedFalseForGitBash(t *testing.T) {
ctx := context.Background()
ctx, _ = SetupTest(ctx)

assert.True(t, IsPromptSupported(ctx))

ctx = env.Set(ctx, "MSYSTEM", "MINGW64")
ctx = env.Set(ctx, "TERM", "xterm")
ctx = env.Set(ctx, "PS1", "\\[\033]0;$TITLEPREFIX:$PWD\007\\]\n\\[\033[32m\\]\\u@\\h \\[\033[35m\\]$MSYSTEM \\[\033[33m\\]\\w\\[\033[36m\\]`__git_ps1`\\[\033[0m\\]\n$")
assert.False(t, IsPromptSupported(ctx))
}
2 changes: 1 addition & 1 deletion libs/template/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func (c *config) promptForValues(r *renderer) error {
// Prompt user for any missing config values. Assign default values if
// terminal is not TTY
func (c *config) promptOrAssignDefaultValues(r *renderer) error {
if cmdio.IsOutTTY(c.ctx) && cmdio.IsInTTY(c.ctx) {
if cmdio.IsPromptSupported(c.ctx) {
return c.promptForValues(r)
}
return c.assignDefaultValues(r)
Expand Down

0 comments on commit 6dd6899

Please sign in to comment.