Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jinja2/filters): add builtin filter for merge_strategic #1287

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/pages/input_types/jinja.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ We support the following custom filters for use in Jinja2 templates:
=== "`reveal_maybe`"
!!! example "reveal `ref/secret` tag only if `compile --reveal` flag is set"
`{{ "?{base64:my_ref}" | reveal_maybe}}`
=== "Struct"
=== "`merge_strategic`"
!!! example "traverse object(s) and merge lists based on common `name`"
`{{ data | merge_strategic | yaml | trim | indent(6)}}`

!!! tip
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.
28 changes: 27 additions & 1 deletion kapitan/jinja2_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def load_jinja2_filters(env):
env.filters["reveal_maybe"] = reveal_maybe
env.filters["ternary"] = ternary
env.filters["shuffle"] = randomize_list

env.filters["merge_strategic"] = merge_strategic

def load_module_from_path(env, path):
"""
Expand Down Expand Up @@ -221,3 +221,29 @@ def randomize_list(mylist, seed=None):
except Exception:
pass
return mylist

def merge_strategic(data):
"""
Recursively traverse the input data structure.
- If encountering a list of dicts each with a 'name' key, merge them by name.
- Process nested dictionaries and lists recursively.
"""
if not isinstance(data, (list, dict)):
return data

if isinstance(data, list):
processed_list = [merge_strategic(item) for item in data]

if all(isinstance(item, dict) and 'name' in item for item in processed_list):
merged = {}
for item in processed_list:
key = item['name']
if key not in merged:
merged[key] = {}
merged[key].update(item)
return list(merged.values())
else:
return processed_list

if isinstance(data, dict):
return {key: merge_strategic(value) for key, value in data.items()}