Skip to content

Commit 09b253d

Browse files
jmmcleanJon McLeanademariag
authored
feat(jinja2/filters): add builtin filter for merge_strategic (#1287)
Fixes # ## Proposed Changes * Add in jinja2 filter to traverse all items in a supplied struct, and create a strategic merge like experience where all items in a list will be merged together if a common key(`name`) is found ## Docs and Tests * [ ] Tests added * [x] Updated documentation Co-authored-by: Jon McLean <[email protected]> Co-authored-by: Alessandro De Maria <[email protected]>
1 parent 5e91256 commit 09b253d

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

docs/pages/input_types/jinja.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ We support the following custom filters for use in Jinja2 templates:
171171
=== "`reveal_maybe`"
172172
!!! example "reveal `ref/secret` tag only if `compile --reveal` flag is set"
173173
`{{ "?{base64:my_ref}" | reveal_maybe}}`
174+
=== "Struct"
175+
=== "`merge_strategic`"
176+
!!! example "traverse object(s) and merge lists based on common `name`"
177+
`{{ data | merge_strategic | yaml | trim | indent(6)}}`
174178

175179
!!! tip
176180
You can also provide path to your custom filter modules in CLI. By default, you can put your filters in `lib/jinja2_filters.py` and they will automatically get loaded.

kapitan/jinja2_filters.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def load_jinja2_filters(env):
5656
env.filters["reveal_maybe"] = reveal_maybe
5757
env.filters["ternary"] = ternary
5858
env.filters["shuffle"] = randomize_list
59-
59+
env.filters["merge_strategic"] = merge_strategic
6060

6161
def load_module_from_path(env, path):
6262
"""
@@ -221,3 +221,29 @@ def randomize_list(mylist, seed=None):
221221
except Exception:
222222
pass
223223
return mylist
224+
225+
def merge_strategic(data):
226+
"""
227+
Recursively traverse the input data structure.
228+
- If encountering a list of dicts each with a 'name' key, merge them by name.
229+
- Process nested dictionaries and lists recursively.
230+
"""
231+
if not isinstance(data, (list, dict)):
232+
return data
233+
234+
if isinstance(data, list):
235+
processed_list = [merge_strategic(item) for item in data]
236+
237+
if all(isinstance(item, dict) and 'name' in item for item in processed_list):
238+
merged = {}
239+
for item in processed_list:
240+
key = item['name']
241+
if key not in merged:
242+
merged[key] = {}
243+
merged[key].update(item)
244+
return list(merged.values())
245+
else:
246+
return processed_list
247+
248+
if isinstance(data, dict):
249+
return {key: merge_strategic(value) for key, value in data.items()}

0 commit comments

Comments
 (0)