Skip to content

Add profiles to x/config/cli - #2456

Merged
nolag merged 1 commit into
mainfrom
rtinianov_cli_profiles
Oct 14, 2026
Merged

nolag merged 1 commit into
mainfrom
rtinianov_cli_profiles

Conversation

@nolag

@nolag nolag commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@nolag
nolag requested a balanced review from Copilot October 9, 2026 16:25
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

📊 API Diff Results

No changes detected for module github.com/smartcontractkit/chainlink-common

View full report

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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 Profile and ProfileWithSelector.
  • 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.

Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from 17d0e01 to 9404cdc Compare October 9, 2026 16:42
@nolag
nolag requested a balanced review from Copilot October 9, 2026 16:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/profile.go Outdated
Comment thread x/config/cli/profile.go
Comment thread x/config/cli/profile.go Outdated
Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch 2 times, most recently from 2a6849a to da8ed1e Compare October 13, 2026 13:02
@nolag
nolag requested a balanced review from Copilot October 13, 2026 13:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/entries.go Outdated
Comment thread x/config/cli/examples/profiles/README.md Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from da8ed1e to 11801e5 Compare October 13, 2026 13:48
@nolag
nolag requested a balanced review from Copilot October 13, 2026 13:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/profile.go
Comment thread x/config/cli/profile.go Outdated
Comment thread x/config/cli/profile.go Outdated
Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from 11801e5 to f48dd99 Compare October 13, 2026 14:11
@nolag
nolag requested a balanced review from Copilot October 13, 2026 14:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/profile.go
Comment thread x/config/cli/profile.go Outdated
Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from f48dd99 to 0b49b6a Compare October 13, 2026 17:11
@nolag
nolag requested a balanced review from Copilot October 13, 2026 17:12
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from 0b49b6a to ff7f8e5 Compare October 13, 2026 17:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/entries.go
Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from ff7f8e5 to 8896f49 Compare October 13, 2026 17:58
@nolag
nolag requested a balanced review from Copilot October 13, 2026 17:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from 8896f49 to 3e7e79d Compare October 14, 2026 14:57
@nolag
nolag requested a balanced review from Copilot October 14, 2026 14:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 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

Comment thread x/config/cli/profile.go
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from 3e7e79d to 5cfb2bd Compare October 14, 2026 15:05
@nolag
nolag requested a balanced review from Copilot October 14, 2026 15:06
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from 5cfb2bd to fbb8504 Compare October 14, 2026 15:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 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

Comment thread x/config/cli/entries.go Outdated
Comment thread x/config/cli/profile.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_profiles branch from fbb8504 to 804c070 Compare October 14, 2026 15:14
@nolag
nolag requested a balanced review from Copilot October 14, 2026 15:14
@nolag
nolag marked this pull request as ready for review October 14, 2026 15:42
@nolag
nolag requested a review from a team as a code owner October 14, 2026 15:42
@nolag
nolag enabled auto-merge October 14, 2026 15:47
Comment thread x/config/cli/profile.go

// 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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 🤷

Comment thread x/config/cli/profile.go
return len(k.goPath) > len(scope) && slices.Equal(k.goPath[:len(scope)], scope)
}

func scopesOverlap(a, b []string) bool {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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?

Comment thread x/config/cli/profile.go
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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does it matter if we construct just one instance of reflect.TypeFor[S]() outside the for loop?

Comment thread x/config/cli/profile.go
}

defer func() {
if r := recover(); r != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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?

Comment thread x/config/cli/profile.go
Comment on lines +135 to +139
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)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Comment thread x/config/cli/profile.go
}

built := clone.Slowly(defaults).(S)
vBuilt := reflect.ValueOf(&built).Elem()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this shorter form equivalent?

Suggested change
vBuilt := reflect.ValueOf(&built).Elem()
vBuilt := reflect.ValueOf(built)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

reflect.ValueOf(built) not addressable: next line's allocateField(...).Set panics "unaddressable value". &built + .Elem() needed.

@nolag
nolag added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit e5560b3 Oct 14, 2026
37 checks passed
@nolag
nolag deleted the rtinianov_cli_profiles branch October 14, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants