Skip to content

Add lists and maps as types the CLI and environment variables can hold - #2444

Open
nolag wants to merge 2 commits into
mainfrom
rtinianov_cli_list_maps
Open

nolag wants to merge 2 commits into
mainfrom
rtinianov_cli_list_maps

Conversation

@nolag

@nolag nolag commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Note, the readme already has this documented. I missed splitting it out into this PR.

I originally had maps and lists in the prior PR, but pulled them out.

@nolag
nolag requested a balanced review from Copilot October 6, 2026 14:23
@github-actions

github-actions Bot commented Oct 6, 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.

Copilot review overview

🟡 Changes recommended

Pointer collections can panic, recursive types can overflow, and several supported values do not round-trip correctly.

Review effort: Balanced
Findings: 5 High severity · 3 Medium severity

Open (8)
What changed in this PR

Adds list and map support to CLI flags and environment-backed configuration.

Changes:

  • Adds CSV list and key-value map parsing.
  • Merges maps across defaults, files, environment, and flags.
  • Adds validation, documentation, and tests for composite types.
File Description
x/​config/​cli/​walk.go Rejects pointer-keyed maps.
x/​config/​cli/​register.go Registers list and map flags.
x/​config/​cli/​maps.go Implements map parsing and merging.
x/​config/​cli/​list.go Implements CSV list parsing.
x/​config/​cli/​entry.go Decodes file values and merges maps.
x/​config/​cli/​decode.go Converts textual map keys from files.
x/​config/​cli/​binder.go Integrates transformed file value types.
x/​config/​cli/​binder_test.go Tests list and map behavior.
x/​config/​cli/​examples/​simple/​README.md Demonstrates list inputs.

💡 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/decode.go Outdated
Comment thread x/config/cli/decode.go Outdated
Comment thread x/config/cli/register.go Outdated
Comment thread x/config/cli/register.go Outdated
Comment thread x/config/cli/walk.go Outdated
Comment thread x/config/cli/decode.go Outdated
Comment thread x/config/cli/list.go
Comment thread x/config/cli/maps.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from 0ad8a5f to 21ebe67 Compare October 6, 2026 15:03
@nolag
nolag requested a balanced review from Copilot October 6, 2026 15:03

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.

Comment thread x/config/cli/walk.go Outdated
Comment thread x/config/cli/decode.go Outdated
Comment thread x/config/cli/list.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch 2 times, most recently from ab70fd0 to ff83b0d Compare October 6, 2026 15:39
@nolag
nolag requested a balanced review from Copilot October 6, 2026 15:39

@github-actions github-actions Bot 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.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: a2c647f Previous: 0ad8a5f Ratio
BenchmarkKeystore_Sign/nop/out-of-process 92204 ns/op 23754 ns/op 3.88
BenchmarkKeystore_Sign/hex/out-of-process 93343 ns/op 24071 ns/op 3.88
BenchmarkKeystore_Sign/ed25519/out-of-process 140247 ns/op 44601 ns/op 3.14

This comment was automatically generated by workflow using github-action-benchmark.

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.

Copilot review overview

🟡 Changes recommended

Recursive non-string map keys and non-reflexive keys such as NaN can bypass the intended conversion and merge semantics.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (3)

Comment thread x/config/cli/decode.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from ff83b0d to 9be9c02 Compare October 6, 2026 16:02
@nolag
nolag requested a balanced review from Copilot October 6, 2026 16:02

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.

Copilot review overview

🟡 Changes recommended

Map-key validation rejects valid opaque leaves while missing channel and composite-NaN identity hazards.

Review effort: Balanced
Findings: 3 Medium severity

Open (3)
Resolved since last review (1)

Comment thread x/config/cli/decode.go Outdated
Comment thread x/config/cli/walk.go Outdated
Comment thread x/config/cli/walk.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from 9be9c02 to 754f206 Compare October 6, 2026 16:33
@nolag
nolag requested a balanced review from Copilot October 6, 2026 16:35

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.

Copilot review overview

🟡 Changes recommended

Atomic map types and ignored fields currently receive incorrect merge or conversion behavior.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Resolved since last review (3)

Comment thread x/config/cli/decode.go
Comment thread x/config/cli/entry.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from 754f206 to 31b4e0e Compare October 6, 2026 16:44
@nolag
nolag requested a balanced review from Copilot October 6, 2026 16:47

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.

Copilot review overview

🟡 Changes recommended

CSV whitespace trimming corrupts valid list and map values and prevents defaults from round-tripping.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Resolved since last review (2)

Comment thread x/config/cli/list.go Outdated
Comment thread x/config/cli/maps.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from 31b4e0e to a64f313 Compare October 6, 2026 17:01
@nolag
nolag requested a balanced review from Copilot October 6, 2026 17:02

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.

Copilot review overview

🟡 Changes recommended

Collection defaults can produce misleading, non-round-trippable help values for UnmarshalText-only types.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
Resolved since last review (2)

Comment thread x/config/cli/register.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from a64f313 to 5f4860a Compare October 6, 2026 18:42
@nolag
nolag requested a balanced review from Copilot October 6, 2026 18: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.

Copilot review overview

🟡 Changes recommended

Interface-typed list or map elements can currently cause a runtime panic during flag parsing.

Review effort: Balanced
Findings: 1 High severity

Open (1)
Resolved since last review (1)

Comment thread x/config/cli/register.go Outdated
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch 2 times, most recently from 4b75d01 to aa3787a Compare October 6, 2026 18:56
@nolag
nolag requested a balanced review from Copilot October 6, 2026 18:56

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.

Copilot review overview

🔵 Needs a closer look

The reflection-based recursive type conversion and multi-source map merging warrant final human validation.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Resolved since last review (1)

Comment thread x/config/cli/binder.go
@nolag
nolag requested a balanced review from Copilot October 6, 2026 19: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.

Copilot review overview

🔵 Needs a closer look

NaN map keys produce displayed defaults that cannot be parsed back.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Suppress defaults containing NaN map keys that cannot round-trip

x/​config/​cli/​maps.go:69

A default map can already contain a NaN key, but this serializes it as NaN=value even though mapKey rejects that text at lines 318-320. Passing the displayed default back therefore fails. Treat a key that does not equal itself as unwritable and suppress the map default, as is already done for other non-round-trippable entries.

Comment on lines +626 to +627
{"a list element", []string{"--strings", "a,"}, "Strings.1 failed on the 'required' tag"},
{"a map entry", []string{"--map", "k="}, "Map.k failed on the 'required' tag"},

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.

Change not strictly needed, but lines it up better with the rest of the tests and allows us to avoid file writes

@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from d032913 to 77297b8 Compare October 7, 2026 14:27
@nolag
nolag force-pushed the rtinianov_cli_list_maps branch from 77297b8 to 16e467d Compare October 7, 2026 14:27
@nolag
nolag requested a balanced review from Copilot October 7, 2026 14:27

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.

Copilot review overview

🟢 Approval recommended

The implementation is coherent, documented, and comprehensively tested across supported sources and edge cases.

Review effort: Balanced
Findings: None

@nolag
nolag marked this pull request as ready for review October 7, 2026 14:47
@nolag
nolag requested a review from a team as a code owner October 7, 2026 14:47
@nolag
nolag enabled auto-merge October 7, 2026 14:54
Comment thread x/config/cli/maps.go
Comment on lines +30 to +31
if entry == "" {
continue

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 an empty entry valid?

Comment thread x/config/cli/maps.go
Comment on lines +63 to +64
for iter := v.MapRange(); iter.Next(); {
pairs = append(pairs, textOf(iter.Key())+mapKVSep+textOf(iter.Value()))

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.

I think you can use Seq2() here?

Suggested change
for iter := v.MapRange(); iter.Next(); {
pairs = append(pairs, textOf(iter.Key())+mapKVSep+textOf(iter.Value()))
for key, val := range v.Seq2() {
pairs = append(pairs, textOf(key)+mapKVSep+textOf(val))

Comment thread x/config/cli/decode.go
// Pointers and channels compare by identity, so two parses of one text are different keys. An interface may hold
// either, or a value that can't be a key at all. Arrays and structs are the only composite key types, and neither can
// hold itself except through a pointer.
func holdsIdentity(t reflect.Type) 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.

Since the check is based on Kind, maybe include that in the name?

Suggested change
func holdsIdentity(t reflect.Type) bool {
func isIdentityKind(t reflect.Type) bool {

Comment thread x/config/cli/decode.go

// seen makes two texts that parse to one key, such as 16 and 0x10, an error rather than one silently replacing the
// other.
func mapKey(t reflect.Type, text string, seen map[any]string) (reflect.Value, 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.

nit/ maybe worth naming these params more descriptively:

Suggested change
func mapKey(t reflect.Type, text string, seen map[any]string) (reflect.Value, error) {
func mapKey(mapType reflect.Type, keyText string, seen map[any]string) (reflect.Value, error) {

This branch has not been deployed

No deployments
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.

4 participants