Skip to content
Open
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
4 changes: 0 additions & 4 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ charmbracelet/lipgloss - https://github.com/charmbracelet/lipgloss
Copyright (c) 2021-2025 Charmbracelet, Inc
License - https://github.com/charmbracelet/lipgloss/blob/master/LICENSE

fatih/color - https://github.com/fatih/color
Copyright (c) 2013 Fatih Arslan
License - https://github.com/fatih/color/blob/main/LICENSE.md

Masterminds/semver - https://github.com/Masterminds/semver
Copyright (C) 2014-2019, Matt Butcher and Matt Farina
License - https://github.com/Masterminds/semver/blob/master/LICENSE.txt
Expand Down
8 changes: 4 additions & 4 deletions bundle/config/mutator/python/python_mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import (
"github.com/databricks/cli/libs/log"
"github.com/databricks/cli/libs/logdiag"

"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/databricks-sdk-go/logger"
"github.com/fatih/color"

"github.com/databricks/cli/libs/python"

Expand Down Expand Up @@ -386,7 +386,7 @@ func (m *pythonMutator) runPythonMutator(ctx context.Context, root dyn.Value, op
diagnostic := diag.Diagnostic{
Severity: diag.Error,
Summary: fmt.Sprintf("python mutator process failed: %q, use --debug to enable logging", processErr),
Detail: explainProcessErr(stderrBuf.String()),
Detail: explainProcessErr(ctx, stderrBuf.String()),
}

return dyn.InvalidValue, diag.Diagnostics{diagnostic}
Expand Down Expand Up @@ -424,10 +424,10 @@ or activate the environment before running CLI commands:
// explainProcessErr provides additional explanation for common errors.
// It's meant to be the best effort, and not all errors are covered.
// Output should be used only used for error reporting.
func explainProcessErr(stderr string) string {
func explainProcessErr(ctx context.Context, stderr string) string {
// implemented in cpython/Lib/runpy.py and portable across Python 3.x, including pypy
if strings.Contains(stderr, "Error while finding module specification for 'databricks.bundles.build'") {
summary := color.CyanString("Explanation: ") + "'databricks-bundles' library is not installed in the Python environment.\n"
summary := cmdio.Cyan(ctx, "Explanation: ") + "'databricks-bundles' library is not installed in the Python environment.\n"

return stderr + "\n" + summary + "\n" + pythonInstallExplanation
}
Expand Down
3 changes: 2 additions & 1 deletion bundle/config/mutator/python/python_mutator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/config"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/process"
"github.com/stretchr/testify/assert"
)
Expand Down Expand Up @@ -488,7 +489,7 @@ or activate the environment before running CLI commands:
venv_path: .venv
`

out := explainProcessErr(stderr)
out := explainProcessErr(cmdio.MockDiscard(t.Context()), stderr)

assert.Equal(t, expected, out)
}
Expand Down
33 changes: 9 additions & 24 deletions bundle/render/render_text_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,11 @@ import (
"text/template"

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/logdiag"
"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/fatih/color"
)

var renderFuncMap = template.FuncMap{
"red": color.RedString,
"green": color.GreenString,
"blue": color.BlueString,
"yellow": color.YellowString,
"magenta": color.MagentaString,
"cyan": color.CyanString,
"bold": func(format string, a ...any) string {
return color.New(color.Bold).Sprintf(format, a...)
},
"italic": func(format string, a ...any) string {
return color.New(color.Italic).Sprintf(format, a...)
},
}

const summaryHeaderTemplate = `{{- if .Name -}}
Name: {{ .Name | bold }}
{{- if .Target }}
Expand Down Expand Up @@ -82,13 +67,13 @@ func buildTrailer(ctx context.Context) string {
info := logdiag.Copy(ctx)
var parts []string
if info.Errors > 0 {
parts = append(parts, color.RedString(pluralize(info.Errors, "error", "errors")))
parts = append(parts, cmdio.Red(ctx, pluralize(info.Errors, "error", "errors")))
}
if info.Warnings > 0 {
parts = append(parts, color.YellowString(pluralize(info.Warnings, "warning", "warnings")))
parts = append(parts, cmdio.Yellow(ctx, pluralize(info.Warnings, "warning", "warnings")))
}
if info.Recommendations > 0 {
parts = append(parts, color.BlueString(pluralize(info.Recommendations, "recommendation", "recommendations")))
parts = append(parts, cmdio.Blue(ctx, pluralize(info.Recommendations, "recommendation", "recommendations")))
}
switch {
case len(parts) >= 3:
Expand All @@ -101,7 +86,7 @@ func buildTrailer(ctx context.Context) string {
return fmt.Sprintf("Found %s\n", parts[0])
default:
// No diagnostics to print.
return color.GreenString("Validation OK!\n")
return cmdio.Green(ctx, "Validation OK!\n")
}
}

Expand All @@ -118,7 +103,7 @@ func renderSummaryHeaderTemplate(ctx context.Context, out io.Writer, b *bundle.B
}
}

t := template.Must(template.New("summary").Funcs(renderFuncMap).Parse(summaryHeaderTemplate))
t := template.Must(template.New("summary").Funcs(cmdio.RenderFuncMap(ctx)).Parse(summaryHeaderTemplate))
err := t.Execute(out, map[string]any{
"Name": b.Config.Bundle.Name,
"Target": b.Config.Bundle.Target,
Expand Down Expand Up @@ -179,15 +164,15 @@ func RenderSummary(ctx context.Context, out io.Writer, b *bundle.Bundle) error {
}
}

if err := renderResourcesTemplate(out, resourceGroups); err != nil {
if err := renderResourcesTemplate(ctx, out, resourceGroups); err != nil {
return fmt.Errorf("failed to render resources template: %w", err)
}

return nil
}

// Helper function to sort and render resource groups using the template
func renderResourcesTemplate(out io.Writer, resourceGroups []ResourceGroup) error {
func renderResourcesTemplate(ctx context.Context, out io.Writer, resourceGroups []ResourceGroup) error {
// Sort everything to ensure consistent output
slices.SortFunc(resourceGroups, func(a, b ResourceGroup) int {
return cmp.Compare(a.GroupName, b.GroupName)
Expand All @@ -198,7 +183,7 @@ func renderResourcesTemplate(out io.Writer, resourceGroups []ResourceGroup) erro
})
}

t := template.Must(template.New("resources").Funcs(renderFuncMap).Parse(resourcesTemplate))
t := template.Must(template.New("resources").Funcs(cmdio.RenderFuncMap(ctx)).Parse(resourcesTemplate))

return t.Execute(out, resourceGroups)
}
37 changes: 4 additions & 33 deletions bundle/render/render_text_output_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,20 @@ import (
"github.com/databricks/databricks-sdk-go/service/jobs"
"github.com/databricks/databricks-sdk-go/service/pipelines"
"github.com/databricks/databricks-sdk-go/service/serving"
"github.com/fatih/color"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRenderSummaryHeaderTemplate_nilBundle(t *testing.T) {
writer := &bytes.Buffer{}

err := renderSummaryHeaderTemplate(t.Context(), writer, nil)
err := renderSummaryHeaderTemplate(cmdio.MockDiscard(t.Context()), writer, nil)
require.NoError(t, err)

assert.Equal(t, "", writer.String())
}

func TestRenderDiagnosticsSummary(t *testing.T) {
// Disable colors for consistent test output
oldNoColor := color.NoColor
color.NoColor = true
defer func() {
color.NoColor = oldNoColor
}()

testCases := []struct {
name string
bundle *bundle.Bundle
Expand Down Expand Up @@ -114,7 +106,7 @@ func TestRenderDiagnosticsSummary(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ctx := logdiag.InitContext(t.Context())
ctx := logdiag.InitContext(cmdio.MockDiscard(t.Context()))
logdiag.SetCollect(ctx, true) // Collect diagnostics instead of outputting to stderr

// Simulate diagnostic counts by logging fake diagnostics
Expand Down Expand Up @@ -144,13 +136,6 @@ type renderDiagnosticsTestCase struct {
}

func TestRenderDiagnostics(t *testing.T) {
// Disable colors for consistent test output
oldNoColor := color.NoColor
color.NoColor = true
defer func() {
color.NoColor = oldNoColor
}()

testCases := []renderDiagnosticsTestCase{
{
name: "empty diagnostics",
Expand Down Expand Up @@ -286,14 +271,7 @@ func TestRenderDiagnostics(t *testing.T) {
}

func TestRenderSummaryTemplate_nilBundle(t *testing.T) {
// Disable colors for consistent test output
oldNoColor := color.NoColor
color.NoColor = true
defer func() {
color.NoColor = oldNoColor
}()

ctx := logdiag.InitContext(t.Context())
ctx := logdiag.InitContext(cmdio.MockDiscard(t.Context()))
writer := &bytes.Buffer{}

err := renderSummaryHeaderTemplate(ctx, writer, nil)
Expand All @@ -306,14 +284,7 @@ func TestRenderSummaryTemplate_nilBundle(t *testing.T) {
}

func TestRenderSummary(t *testing.T) {
ctx := t.Context()

// Disable colors for consistent test output
oldNoColor := color.NoColor
color.NoColor = true
defer func() {
color.NoColor = oldNoColor
}()
ctx := cmdio.MockDiscard(t.Context())

// Create a mock bundle with various resources
b := &bundle.Bundle{
Expand Down
12 changes: 4 additions & 8 deletions bundle/run/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/log"
"github.com/databricks/databricks-sdk-go/service/jobs"
"github.com/fatih/color"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
)
Expand Down Expand Up @@ -50,9 +49,6 @@ func isSuccess(task jobs.RunTask) bool {

func (r *jobRunner) logFailedTasks(ctx context.Context, runId int64) {
w := r.bundle.WorkspaceClient(ctx)
red := color.New(color.FgRed).SprintFunc()
green := color.New(color.FgGreen).SprintFunc()
yellow := color.New(color.FgYellow).SprintFunc()
run, err := w.Jobs.GetRun(ctx, jobs.GetRunRequest{
RunId: runId,
})
Expand All @@ -65,21 +61,21 @@ func (r *jobRunner) logFailedTasks(ctx context.Context, runId int64) {
}
for _, task := range run.Tasks {
if isSuccess(task) {
log.Infof(ctx, "task %s completed successfully", green(task.TaskKey))
log.Infof(ctx, "task %s completed successfully", cmdio.Green(ctx, task.TaskKey))
} else if isFailed(task) {
taskInfo, err := w.Jobs.GetRunOutput(ctx, jobs.GetRunOutputRequest{
RunId: task.RunId,
})
if err != nil {
log.Errorf(ctx, "task %s failed. Unable to fetch error trace: %s", red(task.TaskKey), err)
log.Errorf(ctx, "task %s failed. Unable to fetch error trace: %s", cmdio.Red(ctx, task.TaskKey), err)
continue
}
cmdio.Log(ctx, progress.NewTaskErrorEvent(task.TaskKey, taskInfo.Error, taskInfo.ErrorTrace))
log.Errorf(ctx, "Task %s failed!\nError:\n%s\nTrace:\n%s",
red(task.TaskKey), taskInfo.Error, taskInfo.ErrorTrace)
cmdio.Red(ctx, task.TaskKey), taskInfo.Error, taskInfo.ErrorTrace)
} else {
log.Infof(ctx, "task %s is in state %s",
yellow(task.TaskKey), task.State.LifeCycleState)
cmdio.Yellow(ctx, task.TaskKey), task.State.LifeCycleState)
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/labs/project/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"strings"

"github.com/databricks/cli/cmd/labs/github"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/log"
"github.com/fatih/color"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -64,7 +64,7 @@ func NewInstaller(cmd *cobra.Command, name string, offlineInstall bool) (install
if err != nil {
return nil, fmt.Errorf("load: %w", err)
}
cmd.PrintErrln(color.YellowString("Installing %s in development mode from %s", prj.Name, wd))
cmd.PrintErrln(cmdio.Yellow(cmd.Context(), fmt.Sprintf("Installing %s in development mode from %s", prj.Name, wd)))
return &devInstallation{
Project: prj,
Command: cmd,
Expand Down Expand Up @@ -141,7 +141,7 @@ func (f *fetcher) checkReleasedVersions(cmd *cobra.Command, version string, offl
log.Debugf(ctx, "Latest %s version is: %s", f.name, versions[0].Version)
return versions[0].Version, nil
}
cmd.PrintErrln(color.YellowString("[WARNING] Installing unreleased version: %s", version))
cmd.PrintErrln(cmdio.Yellow(ctx, "[WARNING] Installing unreleased version: "+version))
return version, nil
}

Expand Down
7 changes: 3 additions & 4 deletions cmd/labs/project/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/databricks/databricks-sdk-go/config"
"github.com/databricks/databricks-sdk-go/service/compute"
"github.com/databricks/databricks-sdk-go/service/sql"
"github.com/fatih/color"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -152,8 +151,8 @@ func (i *installer) Upgrade(ctx context.Context) error {
return nil
}

func (i *installer) warningf(text string, v ...any) {
i.cmd.PrintErrln(color.YellowString(text, v...))
func (i *installer) warning(s string) {
i.cmd.PrintErrln(cmdio.Yellow(i.cmd.Context(), s))
}

func (i *installer) cleanupLib(ctx context.Context) error {
Expand Down Expand Up @@ -288,7 +287,7 @@ func (i *installer) installPythonDependencies(ctx context.Context, spec string)
process.WithCombinedOutput(&buf),
process.WithDir(libDir))
if err != nil {
i.warningf(buf.String())
i.warning(buf.String())
return fmt.Errorf("failed to install dependencies of %s", spec)
}
return nil
Expand Down
4 changes: 2 additions & 2 deletions cmd/labs/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import (
"time"

"github.com/databricks/cli/cmd/labs/github"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/env"
"github.com/databricks/cli/libs/log"
"github.com/databricks/cli/libs/python"
"github.com/databricks/databricks-sdk-go/logger"
"github.com/fatih/color"
"go.yaml.in/yaml/v3"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -318,7 +318,7 @@ func (p *Project) checkUpdates(cmd *cobra.Command) error {
}
ago := time.Since(latest.PublishedAt)
msg := "[UPGRADE ADVISED] Newer %s version was released %s ago. Please run `databricks labs upgrade %s` to upgrade: %s -> %s"
cmd.PrintErrln(color.YellowString(msg, p.Name, p.timeAgo(ago), p.Name, installed.Version, latest.Version))
cmd.PrintErrln(cmdio.Yellow(ctx, fmt.Sprintf(msg, p.Name, p.timeAgo(ago), p.Name, installed.Version, latest.Version)))
return nil
}

Expand Down
3 changes: 1 addition & 2 deletions experimental/aitools/cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/databricks/cli/experimental/aitools/lib/agents"
"github.com/databricks/cli/experimental/aitools/lib/installer"
"github.com/databricks/cli/libs/cmdio"
"github.com/fatih/color"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -141,7 +140,7 @@ func filterProjectScopeAgents(detected []*agents.Agent) []*agents.Agent {

// printNoAgentsMessage prints the "no agents detected" message.
func printNoAgentsMessage(ctx context.Context) {
cmdio.LogString(ctx, color.YellowString("No supported coding agents detected."))
cmdio.LogString(ctx, cmdio.Yellow(ctx, "No supported coding agents detected."))
cmdio.LogString(ctx, "")
cmdio.LogString(ctx, "Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity")
cmdio.LogString(ctx, "Please install at least one coding agent first.")
Expand Down
3 changes: 1 addition & 2 deletions experimental/aitools/lib/installer/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/env"
"github.com/databricks/cli/libs/log"
"github.com/fatih/color"
"golang.org/x/mod/semver"
)

Expand Down Expand Up @@ -304,7 +303,7 @@ func PrintInstallingFor(ctx context.Context, targetAgents []*agents.Agent) {
}

func printNoAgentsDetected(ctx context.Context) {
cmdio.LogString(ctx, color.YellowString("No supported coding agents detected."))
cmdio.LogString(ctx, cmdio.Yellow(ctx, "No supported coding agents detected."))
cmdio.LogString(ctx, "")
cmdio.LogString(ctx, "Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity")
cmdio.LogString(ctx, "Please install at least one coding agent first.")
Expand Down
Loading
Loading