diff --git a/cmd/auth/token.go b/cmd/auth/token.go index 06d5f2c2ac..299b732f6a 100644 --- a/cmd/auth/token.go +++ b/cmd/auth/token.go @@ -5,14 +5,17 @@ import ( "encoding/json" "errors" "fmt" + "io" "strings" "time" + "github.com/databricks/cli/cmd/root" "github.com/databricks/cli/libs/auth" "github.com/databricks/cli/libs/cmdio" "github.com/databricks/cli/libs/databrickscfg" "github.com/databricks/cli/libs/databrickscfg/profile" "github.com/databricks/cli/libs/env" + "github.com/databricks/cli/libs/flags" "github.com/databricks/databricks-sdk-go/config" "github.com/databricks/databricks-sdk-go/credentials/u2m" "github.com/databricks/databricks-sdk-go/credentials/u2m/cache" @@ -88,17 +91,30 @@ and secret is not supported.`, if err != nil { return err } - raw, err := json.MarshalIndent(t, "", " ") - if err != nil { - return err - } - _, _ = cmd.OutOrStdout().Write(raw) - return nil + // Only honor the explicit --output text flag, not implicit text mode + // (e.g. from DATABRICKS_OUTPUT_FORMAT). auth token defaults to JSON, + // and changing that implicitly would break scripts that parse JSON output. + textMode := cmd.Flag("output").Changed && root.OutputType(cmd) == flags.OutputText + return writeTokenOutput(cmd.OutOrStdout(), t, textMode) } return cmd } +func writeTokenOutput(w io.Writer, t *oauth2.Token, textMode bool) error { + if textMode { + _, err := fmt.Fprintln(w, t.AccessToken) + return err + } + + raw, err := json.MarshalIndent(t, "", " ") + if err != nil { + return err + } + _, err = w.Write(raw) + return err +} + type loadTokenArgs struct { // authArguments is the parsed auth arguments, including the host and optionally the account ID. authArguments *auth.AuthArguments diff --git a/cmd/auth/token_test.go b/cmd/auth/token_test.go index f36909c9b2..e9dc74eca0 100644 --- a/cmd/auth/token_test.go +++ b/cmd/auth/token_test.go @@ -1,7 +1,9 @@ package auth import ( + "bytes" "context" + "encoding/json" "errors" "net/http" "testing" @@ -798,3 +800,27 @@ func (e errProfiler) LoadProfiles(context.Context, profile.ProfileMatchFunction) func (e errProfiler) GetPath(context.Context) (string, error) { return "", nil } + +func TestWriteTokenOutput(t *testing.T) { + token := &oauth2.Token{ + AccessToken: "my-access-token", + TokenType: "Bearer", + } + + t.Run("json mode", func(t *testing.T) { + var buf bytes.Buffer + err := writeTokenOutput(&buf, token, false) + assert.NoError(t, err) + + raw, err := json.MarshalIndent(token, "", " ") + assert.NoError(t, err) + assert.Equal(t, string(raw), buf.String()) + }) + + t.Run("text mode", func(t *testing.T) { + var buf bytes.Buffer + err := writeTokenOutput(&buf, token, true) + assert.NoError(t, err) + assert.Equal(t, "my-access-token\n", buf.String()) + }) +}