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

Do not allow input prompts in Git Bash terminal #1069

Merged
merged 4 commits into from
Dec 18, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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")
}
andrewnester marked this conversation as resolved.
Show resolved Hide resolved

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