Repository navigation
Add profiles to x/config/cli - #2456
Conversation
📊 API Diff Results
|
There was a problem hiding this comment.
🟡 Changes recommended
Profile help can panic when a profile sets a pointer subsection to nil.
1 open finding
What changed in this PR
Adds profile-based defaults to the config CLI, including nested-section support, source precedence, help output, tests, and examples.
Changes:
- Introduces
ProfileandProfileWithSelector. - Tracks source-supplied fields so they override profiles.
- Adds profile examples, documentation, and tests.
| File | Description |
|---|---|
x/config/go.mod |
Adds deep-cloning dependency. |
x/config/go.sum |
Updates dependency checksums. |
x/config/cli/register.go |
Records required-field metadata. |
x/config/cli/README.md |
Documents profile APIs. |
x/config/cli/profile.go |
Implements profile selection, application, and help. |
x/config/cli/profile_test.go |
Tests profile behavior. |
x/config/cli/options.go |
Updates option documentation. |
x/config/cli/entry.go |
Applies profiles after decoding sources. |
x/config/cli/entries.go |
Reports source-set map fields. |
x/config/cli/binder.go |
Documents profile processing order. |
x/config/cli/examples/profiles/README.md |
Documents standalone profiles. |
x/config/cli/examples/profiles/main.go |
Adds standalone example. |
x/config/cli/examples/profiles/example.toml |
Adds example configuration. |
x/config/cli/examples/profiles/appconfig/gen/main.go |
Adds documentation generator. |
x/config/cli/examples/profiles/appconfig/doccomments_gen.go |
Adds generated field documentation. |
x/config/cli/examples/profiles/appconfig/config.go |
Defines example chain configuration. |
x/config/cli/examples/nested_profiles/README.md |
Documents nested profiles. |
x/config/cli/examples/nested_profiles/main.go |
Adds nested profile example. |
x/config/cli/examples/nested_profiles/example.toml |
Adds nested example configuration. |
x/config/cli/examples/nested_profiles/appconfig/gen/main.go |
Adds nested documentation generator. |
x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go |
Adds generated nested documentation. |
x/config/cli/examples/nested_profiles/appconfig/config.go |
Defines nested example configuration. |
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
17d0e01 to
9404cdc
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Profile application currently breaks per-key map precedence, retains stale profiles across executions, and accepts invalid selector types.
4 open findings
1 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
2a6849a to
da8ed1e
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Map-entry environment variables can fail to override profile-provided keys because their names are resolved before profiles are applied.
2 open findings
4 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
da8ed1e to
11801e5
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Profile-key validation and help rendering have unresolved correctness issues.
4 open findings
2 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
11801e5 to
f48dd99
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Profile setup can fail on cyclic defaults or nil profile functions, and help can omit effective required defaults.
3 open findings
4 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
f48dd99 to
0b49b6a
Compare
0b49b6a to
ff7f8e5
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Map-entry environment resolution can incorrectly fail against stale defaults before the selected profile is applied.
2 open findings
3 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
ff7f8e5 to
8896f49
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Repeated execution can reuse a stale selector after its source is removed, causing the wrong profile to be applied.
1 open finding
2 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
8896f49 to
3e7e79d
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The caller-owned profile map can be mutated after validation, bypassing safeguards and potentially causing runtime panics.
1 open finding
1 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
3e7e79d to
5cfb2bd
Compare
5cfb2bd to
fbb8504
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
Reflection-based section reconstruction and multi-source map layering warrant final human review despite broad test coverage.
2 open findings
1 resolved since last review
Files not reviewed (2)
- x/config/cli/examples/nested_profiles/appconfig/doccomments_gen.go: Generated file
- x/config/cli/examples/profiles/appconfig/doccomments_gen.go: Generated file
🧠 Review effort: Balanced
fbb8504 to
804c070
Compare
|
|
||
| // visitEntries calls visit for m and each map below it on leaf's path, then for each value leaf sets, named as their | ||
| // flags would be, such as section.chains.mainnet.labels. | ||
| func visitEntries(leaf *entryLeaf, name string, m reflect.Value, depth int, visit func(name string, v reflect.Value, isMap bool) error) error { |
There was a problem hiding this comment.
Did you consider writing this as an iterator, returning Seq2[string,reflect.Value]? The unused/suppressed error handling goes away. Although maybe the third isMap param throws things off by forcing some kind of wrapper struct 🤷
| return len(k.goPath) > len(scope) && slices.Equal(k.goPath[:len(scope)], scope) | ||
| } | ||
|
|
||
| func scopesOverlap(a, b []string) bool { |
There was a problem hiding this comment.
This implementation reads a little stricter to me than I would expect from "overlap". Is there a way to say that one prefixes the other? Or points to an ancestor node? Is a "scope" different from a path?
| for _, k := range entry.leaves { | ||
| parent := lookupField(v, k.goPath[:len(k.goPath)-1]) | ||
| // Types are checked as a struct shares its first field's address. | ||
| if parent.Type() != reflect.TypeFor[S]() || parent.Addr().Pointer() != wantSection { |
There was a problem hiding this comment.
Does it matter if we construct just one instance of reflect.TypeFor[S]() outside the for loop?
| } | ||
|
|
||
| defer func() { | ||
| if r := recover(); r != nil { |
There was a problem hiding this comment.
Is it inevitable that we have to recover generally? (i.e. can users of the lib cause this to happen, so no way around it?)
Or are we only worried about our own internal deliberate panics, meaning we could consider checking more narrowly for a specific error type?
| for _, other := range texts[i+1:] { | ||
| if strings.EqualFold(text, other) { | ||
| return fmt.Errorf("profile %v gives %s the keys %q and %q, which differ only in case, so an env var for either is ambiguous", profile, key, text, other) | ||
| } | ||
| } |
There was a problem hiding this comment.
Could shed some indentation here with package slices funcs but not sure it will be much cleaner since you'll need the index to reproduce the error message.
There was a problem hiding this comment.
Oh but more generally can the O(n^2) loop be avoided? e.g. by using https://pkg.go.dev/golang.org/x/text/cases#Fold to do just two passes?
There was a problem hiding this comment.
Done (will open another PR) but not with cases.Fold.
Claude says:
Fold does full folding: joins ß and ss. Runtime env matching uses strings.EqualFold, which keeps them apart, so Fold would reject keys runtime finds fine. Instead foldText maps each rune to smallest rune in its unicode.SimpleFold orbit. Same equality as EqualFold, one map lookup per key.
| } | ||
|
|
||
| built := clone.Slowly(defaults).(S) | ||
| vBuilt := reflect.ValueOf(&built).Elem() |
There was a problem hiding this comment.
Is this shorter form equivalent?
| vBuilt := reflect.ValueOf(&built).Elem() | |
| vBuilt := reflect.ValueOf(built) |
There was a problem hiding this comment.
reflect.ValueOf(built) not addressable: next line's allocateField(...).Set panics "unaddressable value". &built + .Elem() needed.



No description provided.