Emit warnings when conflicting configuration is specified

This commit is contained in:
Shreyas Goenka 2024-06-18 19:33:06 +02:00
parent 533d357a71
commit b0cebdc6bf
No known key found for this signature in database
GPG Key ID: 92A07DF49CCB0622
7 changed files with 162 additions and 0 deletions

View File

@ -0,0 +1,72 @@
package validate
import (
"context"
"fmt"
"path/filepath"
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
)
// This mutator emits warnings if a configuration value is being override by another
// value in the configuration files, effectively making the configuration useless.
func ConflictingConfiguration() bundle.ReadOnlyMutator {
return &conflictingConfiguration{}
}
type conflictingConfiguration struct{}
func (v *conflictingConfiguration) Name() string {
return "validate:conflicting_configuration"
}
func isKindScalar(v dyn.Value) bool {
switch v.Kind() {
case dyn.KindString, dyn.KindInt, dyn.KindBool, dyn.KindFloat, dyn.KindTime, dyn.KindNil:
return true
default:
return false
}
}
func conflictingConfigurationWarning(v dyn.Value, p dyn.Path, rb bundle.ReadOnlyBundle) string {
loc := v.Location()
rel, err := filepath.Rel(rb.RootPath(), loc.File)
if err == nil {
loc.File = rel
}
yamlLocations := v.YamlLocations()
for i, yamlLocation := range yamlLocations {
rel, err := filepath.Rel(rb.RootPath(), yamlLocation.File)
if err == nil {
yamlLocations[i].File = rel
}
}
return fmt.Sprintf("Multiple values found for the same configuration %s. Only the value from location %s will be used. Locations found: %s", p.String(), loc, yamlLocations)
}
func (v *conflictingConfiguration) Apply(ctx context.Context, rb bundle.ReadOnlyBundle) diag.Diagnostics {
diags := diag.Diagnostics{}
_, err := dyn.Walk(rb.Config().Value(), func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
if !isKindScalar(v) {
return v, nil
}
if len(v.YamlLocations()) >= 2 {
diags = diags.Append(diag.Diagnostic{
Severity: diag.Warning,
Summary: conflictingConfigurationWarning(v, p, rb),
Location: v.Location(),
Path: p,
})
}
return v, nil
})
diags = append(diags, diag.FromErr(err)...)
return diags
}

View File

@ -0,0 +1,28 @@
package validate
import (
"context"
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/libs/diag"
)
type preInitialize struct{}
// Apply implements bundle.Mutator.
func (v *preInitialize) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
return bundle.ApplyReadOnly(ctx, bundle.ReadOnly(b), bundle.Parallel(
ConflictingConfiguration(),
))
}
// Name implements bundle.Mutator.
func (v *preInitialize) Name() string {
return "validate:pre_initialize"
}
// Validations to perform before initialization of the bundle. These validations
// are thus applied for most bundle commands.
func PreInitialize() bundle.Mutator {
return &preInitialize{}
}

View File

@ -4,6 +4,7 @@ import (
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/config"
"github.com/databricks/cli/bundle/config/mutator"
"github.com/databricks/cli/bundle/config/validate"
"github.com/databricks/cli/bundle/deploy/metadata"
"github.com/databricks/cli/bundle/deploy/terraform"
"github.com/databricks/cli/bundle/permissions"
@ -18,6 +19,7 @@ func Initialize() bundle.Mutator {
return newPhase(
"initialize",
[]bundle.Mutator{
validate.PreInitialize(),
mutator.RewriteSyncPaths(),
mutator.MergeJobClusters(),
mutator.MergeJobTasks(),

View File

@ -0,0 +1,9 @@
bundle:
name: test warnings for conflicting configuration
include:
- "*.yml"
variables:
bar:
default: conflicts

View File

@ -0,0 +1,6 @@
variables:
bar:
default: conflicts
baz:
default: conflicts

View File

@ -0,0 +1,3 @@
variables:
baz:
default: conflicts

View File

@ -0,0 +1,42 @@
package config_tests
import (
"context"
"path/filepath"
"testing"
"github.com/databricks/cli/bundle"
"github.com/databricks/cli/bundle/config/validate"
"github.com/databricks/cli/libs/diag"
"github.com/databricks/cli/libs/dyn"
"github.com/stretchr/testify/assert"
)
func TestConflictingConfigurationValidate(t *testing.T) {
b := load(t, "validate/conflicting_configuration")
ctx := context.Background()
diags := bundle.ApplyReadOnly(ctx, bundle.ReadOnly(b), validate.ConflictingConfiguration())
assert.Len(t, diags, 2)
assert.Contains(t, diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Multiple values found for the same configuration variables.baz.default. Only the value from location resources2.yml:3:14 will be used. Locations found: [resources2.yml:3:14 resources1.yml:6:14]",
Location: dyn.Location{
File: filepath.FromSlash("validate/conflicting_configuration/resources2.yml"),
Line: 3,
Column: 14,
},
Path: dyn.MustPathFromString("variables.baz.default"),
})
assert.Contains(t, diags, diag.Diagnostic{
Severity: diag.Warning,
Summary: "Multiple values found for the same configuration variables.bar.default. Only the value from location resources1.yml:3:14 will be used. Locations found: [resources1.yml:3:14 databricks.yml:9:14]",
Location: dyn.Location{
File: filepath.FromSlash("validate/conflicting_configuration/resources1.yml"),
Line: 3,
Column: 14,
},
Path: dyn.MustPathFromString("variables.bar.default"),
})
}