feat: add key/value pair template functions#756
Conversation
e95699d to
3c0d803
Compare
|
@JamBalaya56562 please flag AI-generated PR explicitly in the PR description (ie "🤖 Generated with Claude Code" like in this PR) and add the AI agent as co-author of the commits. |
3c0d803 to
eab4ccd
Compare
|
Done — added the |
There was a problem hiding this comment.
Pull request overview
Adds two new template helper functions to parse key/value pair lists from strings and to group containers by the parsed keys, extending docker-gen’s existing groupBy* family for common env patterns like VIRTUAL_PORT="443:3000,3000:3000".
Changes:
- Added
splitKeyValuePairs(string →map[string]string) for parsing delimited key/value lists. - Added
groupByMultiKeyValuePairsto group containers by keys parsed from a delimited field value. - Documented the new helpers in the README and added unit tests covering core behavior (including
SplitNvalue preservation).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| README.md | Documents the two new template helpers and their arguments. |
| internal/template/template.go | Registers the new helpers in the template function map. |
| internal/template/groupby.go | Implements splitKeyValuePairs and groupByMultiKeyValuePairs using existing grouping machinery. |
| internal/template/groupby_test.go | Adds unit tests for both new helper functions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func groupByMultiKeyValuePairs(entries interface{}, key, listSep, kvpSep, defaultKey string) (map[string][]interface{}, error) { | ||
| return generalizedGroupByKey("groupByMultiKeyValuePairs", entries, key, func(groups map[string][]interface{}, value interface{}, v interface{}) { | ||
| for k := range splitKeyValuePairs(value.(string), listSep, kvpSep, defaultKey) { | ||
| groups[k] = append(groups[k], v) | ||
| } | ||
| }) | ||
| } |
There was a problem hiding this comment.
Good catch — fixed. groupByMultiKeyValuePairs now takes defaultKey ...string and forwards it as defaultKey..., so the documented optional [$defaultKey] works and a 4-argument template call no longer fails at runtime. Added TestGroupByMultiKeyValuePairsDefaultKeyOmitted to cover the omitted-key case.
| var key, value string | ||
| if strings.Contains(kvp, kvpSep) { | ||
| parts := strings.SplitN(kvp, kvpSep, 2) | ||
| key, value = parts[0], parts[1] | ||
| } else if len(defaultKey) == 0 || defaultKey[0] == "" { | ||
| key, value = kvp, kvp | ||
| } else { | ||
| key, value = defaultKey[0], kvp | ||
| } | ||
| output[key] = value |
There was a problem hiding this comment.
Done — splitKeyValuePairs now uses a single strings.SplitN(kvp, kvpSep, 2) and checks len(parts) == 2, instead of strings.Contains followed by SplitN, so each segment is scanned once.
eab4ccd to
1352017
Compare
|
Thanks — applied both Copilot suggestions:
|
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1352017 to
b138587
Compare
Summary
Adds two template helpers originally proposed in #319:
splitKeyValuePairs $string $listSep $kvpSep [$defaultKey]— splits a string into amap[string]string. Each item (delimited by$listSep) is split into a key/value pair by$kvpSep. Items that do not contain$kvpSepfall back to$defaultKeyas the key (or to the item itself when$defaultKeyis empty or omitted).groupByMultiKeyValuePairs $containers $fieldPath $listSep $kvpSep [$defaultKey]— likegroupByMulti, but the field value is parsed into key/value pairs bysplitKeyValuePairsand the containers are grouped by key.Motivating example: parsing an env value such as
VIRTUAL_PORT="443:3000,3000:3000".Notes
This reimplements the stale PR #319 against the current
internal/layout, reusing the existinggeneralizedGroupByKeymachinery. Two issues in the original were fixed while porting:strings.Split(kvp, kvpSep)and indexed[0]/[1], silently dropping extra segments when the value itself contained the separator. It now usesstrings.SplitN(kvp, kvpSep, 2), so a value such asurl=http://a=bkeepshttp://a=bintact.RuntimeContainer; the current code stores*RuntimeContainer, so the ported test uses the pointer type.Tests
Added unit tests for both functions (including a case that exercises the
SplitNfix) and documented both in the README.Reimplements #319
🤖 Generated with Claude Code