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

Support multiple locations for diagnostics #1610

Merged
merged 19 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
10 changes: 5 additions & 5 deletions bundle/config/mutator/python/python_diagnostics.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,11 @@ func parsePythonDiagnostics(input io.Reader) (diag.Diagnostics, error) {
}

diag := diag.Diagnostic{
Severity: severity,
Summary: parsedLine.Summary,
Detail: parsedLine.Detail,
Location: convertPythonLocation(parsedLine.Location),
Path: path,
Severity: severity,
Summary: parsedLine.Summary,
Detail: parsedLine.Detail,
Locations: []dyn.Location{convertPythonLocation(parsedLine.Location)},
Path: path,
}

diags = diags.Append(diag)
Expand Down
34 changes: 20 additions & 14 deletions bundle/config/mutator/python/python_diagnostics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ func TestParsePythonDiagnostics(t *testing.T) {
{
Severity: diag.Error,
Summary: "error summary",
Location: dyn.Location{
File: "src/examples/file.py",
Line: 1,
Column: 2,
Locations: []dyn.Location{
{
File: "src/examples/file.py",
Line: 1,
Column: 2,
},
},
},
},
Expand All @@ -52,9 +54,10 @@ func TestParsePythonDiagnostics(t *testing.T) {
input: `{"severity": "error", "summary": "error summary", "path": "resources.jobs.job0.name"}`,
expected: diag.Diagnostics{
{
Severity: diag.Error,
Summary: "error summary",
Path: dyn.MustPathFromString("resources.jobs.job0.name"),
Severity: diag.Error,
Summary: "error summary",
Path: dyn.MustPathFromString("resources.jobs.job0.name"),
Locations: []dyn.Location{{}},
},
},
},
Expand All @@ -73,9 +76,10 @@ func TestParsePythonDiagnostics(t *testing.T) {
input: `{"severity": "warning", "summary": "warning summary", "detail": "warning detail"}`,
expected: diag.Diagnostics{
{
Severity: diag.Warning,
Summary: "warning summary",
Detail: "warning detail",
Severity: diag.Warning,
Summary: "warning summary",
Detail: "warning detail",
Locations: []dyn.Location{{}},
shreyas-goenka marked this conversation as resolved.
Show resolved Hide resolved
},
},
},
Expand All @@ -85,12 +89,14 @@ func TestParsePythonDiagnostics(t *testing.T) {
`{"severity": "error", "summary": "error summary (2)"}`,
expected: diag.Diagnostics{
{
Severity: diag.Error,
Summary: "error summary (1)",
Severity: diag.Error,
Summary: "error summary (1)",
Locations: []dyn.Location{{}},
},
{
Severity: diag.Error,
Summary: "error summary (2)",
Severity: diag.Error,
Summary: "error summary (2)",
Locations: []dyn.Location{{}},
},
},
},
Expand Down
13 changes: 8 additions & 5 deletions bundle/config/mutator/python/python_mutator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,14 @@ func TestPythonMutator_load(t *testing.T) {

assert.Equal(t, 1, len(diags))
assert.Equal(t, "job doesn't have any tasks", diags[0].Summary)
assert.Equal(t, dyn.Location{
File: "src/examples/file.py",
Line: 10,
Column: 5,
}, diags[0].Location)
assert.Equal(t, []dyn.Location{
{
File: "src/examples/file.py",
Line: 10,
Column: 5,
},
}, diags[0].Locations)

}

func TestPythonMutator_load_disallowed(t *testing.T) {
Expand Down
8 changes: 4 additions & 4 deletions bundle/config/mutator/run_as.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,10 @@ func (m *setRunAs) Apply(_ context.Context, b *bundle.Bundle) diag.Diagnostics {
setRunAsForJobs(b)
return diag.Diagnostics{
{
Severity: diag.Warning,
Summary: "You are using the legacy mode of run_as. The support for this mode is experimental and might be removed in a future release of the CLI. In order to run the DLT pipelines in your DAB as the run_as user this mode changes the owners of the pipelines to the run_as identity, which requires the user deploying the bundle to be a workspace admin, and also a Metastore admin if the pipeline target is in UC.",
Path: dyn.MustPathFromString("experimental.use_legacy_run_as"),
Location: b.Config.GetLocation("experimental.use_legacy_run_as"),
Severity: diag.Warning,
Summary: "You are using the legacy mode of run_as. The support for this mode is experimental and might be removed in a future release of the CLI. In order to run the DLT pipelines in your DAB as the run_as user this mode changes the owners of the pipelines to the run_as identity, which requires the user deploying the bundle to be a workspace admin, and also a Metastore admin if the pipeline target is in UC.",
Path: dyn.MustPathFromString("experimental.use_legacy_run_as"),
Locations: b.Config.GetLocations("experimental.use_legacy_run_as"),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we display multiple locations here since they are all relevant.

},
}
}
Expand Down
8 changes: 8 additions & 0 deletions bundle/config/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,14 @@ func (r Root) GetLocation(path string) dyn.Location {
return v.Location()
}

func (r Root) GetLocations(path string) []dyn.Location {
shreyas-goenka marked this conversation as resolved.
Show resolved Hide resolved
v, err := dyn.Get(r.value, path)
if err != nil {
return []dyn.Location{}
}
return v.Locations()
}

// Value returns the dynamic configuration value of the root object. This value
// is the source of truth and is kept in sync with values in the typed configuration.
func (r Root) Value() dyn.Value {
Expand Down
6 changes: 4 additions & 2 deletions bundle/config/validate/files_to_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ func (v *filesToSync) Apply(ctx context.Context, rb bundle.ReadOnlyBundle) diag.
diags = diags.Append(diag.Diagnostic{
Severity: diag.Warning,
Summary: "There are no files to sync, please check your .gitignore and sync.exclude configuration",
Location: loc.Location(),
Path: loc.Path(),
// Show all locations where sync.exclude is defined, since merging
// sync.exclude is additive.
Locations: loc.Locations(),
Path: loc.Path(),
})
}

Expand Down
8 changes: 6 additions & 2 deletions bundle/config/validate/job_cluster_key_defined.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
)

func JobClusterKeyDefined() bundle.ReadOnlyMutator {
Expand Down Expand Up @@ -41,8 +42,11 @@ func (v *jobClusterKeyDefined) Apply(ctx context.Context, rb bundle.ReadOnlyBund
diags = diags.Append(diag.Diagnostic{
Severity: diag.Warning,
Summary: fmt.Sprintf("job_cluster_key %s is not defined", task.JobClusterKey),
Location: loc.Location(),
Path: loc.Path(),
// Show only the location where the job_cluster_key is defined.
// Other associated locations are not relevant since they are
// overridden during merging.
Locations: []dyn.Location{loc.Location()},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually I'll followup with a PR to show warnings when scalar configuration is being overridden.

Path: loc.Path(),
})
}
}
Expand Down
4 changes: 4 additions & 0 deletions bundle/config/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ func (l location) Location() dyn.Location {
return l.rb.Config().GetLocation(l.path)
}

func (l location) Locations() []dyn.Location {
return l.rb.Config().GetLocations(l.path)
}

func (l location) Path() dyn.Path {
return dyn.MustPathFromString(l.path)
}
Expand Down
9 changes: 5 additions & 4 deletions bundle/config/validate/validate_sync_patterns.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/databricks/cli/bundle"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
"github.com/databricks/cli/libs/fileset"
"golang.org/x/sync/errgroup"
)
Expand Down Expand Up @@ -64,10 +65,10 @@ func checkPatterns(patterns []string, path string, rb bundle.ReadOnlyBundle) (di
loc := location{path: fmt.Sprintf("%s[%d]", path, index), rb: rb}
mu.Lock()
diags = diags.Append(diag.Diagnostic{
Severity: diag.Warning,
Summary: fmt.Sprintf("Pattern %s does not match any files", p),
Location: loc.Location(),
Path: loc.Path(),
Severity: diag.Warning,
Summary: fmt.Sprintf("Pattern %s does not match any files", p),
Locations: []dyn.Location{loc.Location()},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not matter if we use loc.Locations() or just a single location here since array values can only have a single location during merging. Still only using a single location here to keep it easy to reason about.

Path: loc.Path(),
})
mu.Unlock()
}
Expand Down
50 changes: 38 additions & 12 deletions bundle/render/render_text_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,33 @@ import (

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

func printLocations(locations []dyn.Location) string {
res := strings.Builder{}

first := true
for _, loc := range locations {
if loc.File == "" {
continue
}

res.WriteString("\n")
if first {
res.WriteString(" in ")
first = false
} else {
res.WriteString(" ")
}

res.WriteString(color.CyanString(loc.String()))
}
return res.String()
}

var renderFuncMap = template.FuncMap{
"red": color.RedString,
"green": color.GreenString,
Expand All @@ -26,15 +49,14 @@ var renderFuncMap = template.FuncMap{
"italic": func(format string, a ...interface{}) string {
return color.New(color.Italic).Sprintf(format, a...)
},
"printLocations": printLocations,
}

const errorTemplate = `{{ "Error" | red }}: {{ .Summary }}
{{- if .Path.String }}
{{ "at " }}{{ .Path.String | green }}
{{- end }}
{{- if .Location.File }}
{{ "in " }}{{ .Location.String | cyan }}
{{- end }}
shreyas-goenka marked this conversation as resolved.
Show resolved Hide resolved
{{- printLocations .Locations -}}
{{- if .Detail }}

{{ .Detail }}
Expand All @@ -46,9 +68,7 @@ const warningTemplate = `{{ "Warning" | yellow }}: {{ .Summary }}
{{- if .Path.String }}
{{ "at " }}{{ .Path.String | green }}
{{- end }}
{{- if .Location.File }}
{{ "in " }}{{ .Location.String | cyan }}
{{- end }}
{{- printLocations .Locations -}}
{{- if .Detail }}

{{ .Detail }}
Expand Down Expand Up @@ -141,12 +161,18 @@ func renderDiagnostics(out io.Writer, b *bundle.Bundle, diags diag.Diagnostics)
t = warningT
}

// Make file relative to bundle root
if d.Location.File != "" && b != nil {
out, err := filepath.Rel(b.RootPath, d.Location.File)
// if we can't relativize the path, just use path as-is
if err == nil {
d.Location.File = out
for i := range d.Locations {
if b == nil {
break
}

// Make location relative to bundle root
if d.Locations[i].File != "" {
out, err := filepath.Rel(b.RootPath, d.Locations[i].File)
// if we can't relativize the path, just use path as-is
if err == nil {
d.Locations[i].File = out
}
}
}

Expand Down
Loading
Loading