mirror of https://github.com/databricks/cli.git
acc: Implement config merge (#2294)
## Changes Instead of using leaf-most config, all configs from root at acceptance/test.toml to all intermediate ones to leaf config are merged into one. Maps are merged, slices are appended, other values are overridden. I had to disable caching, because it is tricky when merging is involved - deep copy is needed. There is performance impact but currently it is tiny, about 1%. Also, remove empty root config. ## Tests Manually checked that inheritance of LocalOnly setting worked for these tests: Before - integration tests showed: ``` PASS acceptance.TestAccept/bundle/templates/wrong-url (0.70s) PASS acceptance.TestAccept/bundle/templates/wrong-path (0.44s) ``` After: ``` SKIP acceptance.TestAccept/bundle/templates/wrong-url (0.00s) SKIP acceptance.TestAccept/bundle/templates/wrong-path (0.00s) acceptance_test.go:216: Disabled via LocalOnly setting in bundle/templates/test.toml, bundle/templates/wrong-path/test.toml (CLOUD_ENV=***) ```
This commit is contained in:
parent
f71583fbc0
commit
ff4a5c2269
5
NOTICE
5
NOTICE
|
@ -109,3 +109,8 @@ License - https://github.com/hexops/gotextdiff/blob/main/LICENSE
|
||||||
https://github.com/BurntSushi/toml
|
https://github.com/BurntSushi/toml
|
||||||
Copyright (c) 2013 TOML authors
|
Copyright (c) 2013 TOML authors
|
||||||
https://github.com/BurntSushi/toml/blob/master/COPYING
|
https://github.com/BurntSushi/toml/blob/master/COPYING
|
||||||
|
|
||||||
|
dario.cat/mergo
|
||||||
|
Copyright (c) 2013 Dario Castañé. All rights reserved.
|
||||||
|
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||||
|
https://github.com/darccio/mergo/blob/master/LICENSE
|
||||||
|
|
|
@ -3,9 +3,11 @@ package acceptance_test
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"slices"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"dario.cat/mergo"
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
"github.com/databricks/cli/libs/testdiff"
|
"github.com/databricks/cli/libs/testdiff"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -13,11 +15,6 @@ import (
|
||||||
|
|
||||||
const configFilename = "test.toml"
|
const configFilename = "test.toml"
|
||||||
|
|
||||||
var (
|
|
||||||
configCache map[string]TestConfig
|
|
||||||
configMutex sync.Mutex
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestConfig struct {
|
type TestConfig struct {
|
||||||
// Place to describe what's wrong with this test. Does not affect how the test is run.
|
// Place to describe what's wrong with this test. Does not affect how the test is run.
|
||||||
Badness string
|
Badness string
|
||||||
|
@ -65,58 +62,55 @@ type ServerStub struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindConfig finds the closest config file.
|
// FindConfigs finds all the config relevant for this test,
|
||||||
func FindConfig(t *testing.T, dir string) (string, bool) {
|
// ordered from the most outermost (at acceptance/) to current test directory (identified by dir).
|
||||||
shared := false
|
// Argument dir must be a relative path from the root of acceptance tests (<project_root>/acceptance/).
|
||||||
|
func FindConfigs(t *testing.T, dir string) []string {
|
||||||
|
configs := []string{}
|
||||||
for {
|
for {
|
||||||
path := filepath.Join(dir, configFilename)
|
path := filepath.Join(dir, configFilename)
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return path, shared
|
configs = append(configs, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
shared = true
|
|
||||||
|
|
||||||
if dir == "" || dir == "." {
|
if dir == "" || dir == "." {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
dir = filepath.Dir(dir)
|
||||||
dir = filepath.Dir(dir)
|
|
||||||
|
if err == nil || os.IsNotExist(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Fatalf("Error while reading %s: %s", path, err)
|
t.Fatalf("Error while reading %s: %s", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Fatal("Config not found: " + configFilename)
|
slices.Reverse(configs)
|
||||||
return "", shared
|
return configs
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads the config file. Non-leaf configs are cached.
|
// LoadConfig loads the config file. Non-leaf configs are cached.
|
||||||
func LoadConfig(t *testing.T, dir string) (TestConfig, string) {
|
func LoadConfig(t *testing.T, dir string) (TestConfig, string) {
|
||||||
path, leafConfig := FindConfig(t, dir)
|
configs := FindConfigs(t, dir)
|
||||||
|
|
||||||
if leafConfig {
|
if len(configs) == 0 {
|
||||||
return DoLoadConfig(t, path), path
|
return TestConfig{}, "(no config)"
|
||||||
}
|
}
|
||||||
|
|
||||||
configMutex.Lock()
|
result := DoLoadConfig(t, configs[0])
|
||||||
defer configMutex.Unlock()
|
|
||||||
|
|
||||||
if configCache == nil {
|
for _, cfgName := range configs[1:] {
|
||||||
configCache = make(map[string]TestConfig)
|
cfg := DoLoadConfig(t, cfgName)
|
||||||
|
err := mergo.Merge(&result, cfg, mergo.WithOverride, mergo.WithAppendSlice)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error during config merge: %s: %s", cfgName, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result, ok := configCache[path]
|
return result, strings.Join(configs, ", ")
|
||||||
if ok {
|
|
||||||
return result, path
|
|
||||||
}
|
|
||||||
|
|
||||||
result = DoLoadConfig(t, path)
|
|
||||||
configCache[path] = result
|
|
||||||
return result, path
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoLoadConfig(t *testing.T, path string) TestConfig {
|
func DoLoadConfig(t *testing.T, path string) TestConfig {
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
# If test directory nor any of its parents do not have test.toml then this file serves as fallback configuration.
|
|
||||||
# The configurations are not merged across parents; the closest one is used fully.
|
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.23
|
||||||
toolchain go1.23.4
|
toolchain go1.23.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
dario.cat/mergo v1.0.1 // BSD 3-Clause
|
||||||
github.com/BurntSushi/toml v1.4.0 // MIT
|
github.com/BurntSushi/toml v1.4.0 // MIT
|
||||||
github.com/Masterminds/semver/v3 v3.3.1 // MIT
|
github.com/Masterminds/semver/v3 v3.3.1 // MIT
|
||||||
github.com/briandowns/spinner v1.23.1 // Apache 2.0
|
github.com/briandowns/spinner v1.23.1 // Apache 2.0
|
||||||
|
|
|
@ -5,8 +5,8 @@ cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKF
|
||||||
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
|
cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
|
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||||
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
|
Loading…
Reference in New Issue