Refuse config keys that no setting has (closes #419)
check / check (push) Successful in 9m24s
check / check (push) Successful in 9m24s
config.Parse walks the file as written and fails on the first key that
matches no setting, naming its dotted path and line, so a typo in
exclude or prune_grace_period no longer falls back silently. Keys that a
${...} reference brings in are checked once smartconfig has filled it
in, and named without a line. YAML merge keys and a top-level env
section, which smartconfig reads, still load; an anchor that contains
itself is an error, and each anchored map is checked once per type.
config set refuses such a key before writing, with the same error, and
sets a key under env like any other value. The key-to-field lookup
moves from internal/cli to config.SettingType so both use it.
Model: opus-5-5
This commit is contained in:
1 parent
0d0c76fa24
commit
26914097a1
6 files changed
+462
-47
No files matched your search
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -286,15 +287,37 @@ func Load(path string) (*Config, error) {
|
||||
}
|
||||
|
||||
// Parse reads YAML config data as Load does, without validating it. It
|
||||
// applies default values for optional fields, fills in ${...} references
|
||||
// using smartconfig, and expands ~ in paths.
|
||||
// refuses a key that no setting has, applies default values for optional
|
||||
// fields, fills in ${...} references using smartconfig, and expands ~ in
|
||||
// paths.
|
||||
func Parse(data []byte) (*Config, error) {
|
||||
// smartconfig drops line numbers, so keys are checked in the data as
|
||||
// written.
|
||||
var root yaml.Node
|
||||
|
||||
err := yaml.Unmarshal(data, &root)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config: %w", err)
|
||||
}
|
||||
|
||||
err = checkKeys(&root, reflect.TypeFor[Config](), "",
|
||||
map[*yaml.Node]bool{}, map[nodeAndType]bool{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load config using smartconfig for interpolation
|
||||
sc, err := smartconfig.NewFromReader(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load config file: %w", err)
|
||||
}
|
||||
|
||||
// A ${...} reference can bring in keys that are not in the file.
|
||||
err = checkFilledKeys(sc.Data())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := &Config{
|
||||
// Set defaults
|
||||
BlobSizeLimit: defaultBlobSizeLimit,
|
||||
|
||||
Reference in new issue
Block a user