diff --git a/backend/infrahub/core/schema/schema_branch.py b/backend/infrahub/core/schema/schema_branch.py index 35f514d870..280367397f 100644 --- a/backend/infrahub/core/schema/schema_branch.py +++ b/backend/infrahub/core/schema/schema_branch.py @@ -793,17 +793,17 @@ def validate_display_label(self) -> None: if len(node_schema.display_labels) == 1: # If the previous display_labels consist of a single attribute convert # it to an attribute based display label - converted_display_label = node_schema.display_labels[0] - if "__" not in converted_display_label: - # Previously we allowed defining a raw attribute name as a component of a - # display_label, if this is the case we need to append '__value' - converted_display_label = f"{converted_display_label}__value" - update_candidate.display_label = converted_display_label + update_candidate.display_label = _format_display_label_component( + component=node_schema.display_labels[0] + ) else: # If the previous display label consists of multiple attributes # convert it to a Jinja2 based display label update_candidate.display_label = " ".join( - [f"{{{{ {display_label} }}}}" for display_label in node_schema.display_labels] + [ + f"{{{{ {_format_display_label_component(component=display_label)} }}}}" + for display_label in node_schema.display_labels + ] ) self.set(name=name, schema=update_candidate) @@ -2592,3 +2592,16 @@ def manage_object_template_schemas(self) -> None: updated_used_by_node = set(chain(template_schema_kinds, set(core_node_schema.used_by))) core_node_schema.used_by = sorted(updated_used_by_node) self.set(name=InfrahubKind.NODE, schema=core_node_schema) + + +def _format_display_label_component(component: str) -> str: + """Return correct format for display_label. + + Previously both the format of 'name' and 'name__value' was + supported this function ensures that the proper 'name__value' + format is used + """ + if "__" in component: + return component + + return f"{component}__value" diff --git a/backend/tests/unit/core/schema/schema_branch/test_schema_convert_display_labels.py b/backend/tests/unit/core/schema/schema_branch/test_schema_convert_display_labels.py new file mode 100644 index 0000000000..029fc692d0 --- /dev/null +++ b/backend/tests/unit/core/schema/schema_branch/test_schema_convert_display_labels.py @@ -0,0 +1,103 @@ +from dataclasses import dataclass + +import pytest + +from infrahub.core.schema import AttributeSchema, NodeSchema, SchemaRoot +from infrahub.core.schema.schema_branch import SchemaBranch + + +@dataclass +class DisplayLabelTestCase: + name: str + schema_root: SchemaRoot + display_label: str + + +DISPLAY_LABEL_TEST_CASES: list[DisplayLabelTestCase] = [ + DisplayLabelTestCase( + name="single_attribute_label_no_value", + schema_root=SchemaRoot( + nodes=[ + NodeSchema( + name="Widget", + namespace="Test", + attributes=[AttributeSchema(name="name", kind="Text"), AttributeSchema(name="status", kind="Text")], + display_labels=["name"], + ) + ] + ), + display_label="name__value", + ), + DisplayLabelTestCase( + name="single_attribute_label_with_value", + schema_root=SchemaRoot( + nodes=[ + NodeSchema( + name="Widget", + namespace="Test", + attributes=[AttributeSchema(name="name", kind="Text"), AttributeSchema(name="status", kind="Text")], + display_labels=["name__value"], + ) + ] + ), + display_label="name__value", + ), + DisplayLabelTestCase( + name="dual_attribute_label_no_value", + schema_root=SchemaRoot( + nodes=[ + NodeSchema( + name="Widget", + namespace="Test", + attributes=[AttributeSchema(name="name", kind="Text"), AttributeSchema(name="status", kind="Text")], + display_labels=["name", "status"], + ) + ] + ), + display_label="{{ name__value }} {{ status__value }}", + ), + DisplayLabelTestCase( + name="dual_attribute_label_mixed_value", + schema_root=SchemaRoot( + nodes=[ + NodeSchema( + name="Widget", + namespace="Test", + attributes=[AttributeSchema(name="name", kind="Text"), AttributeSchema(name="status", kind="Text")], + display_labels=["name__value", "status"], + ) + ] + ), + display_label="{{ name__value }} {{ status__value }}", + ), + DisplayLabelTestCase( + name="defined_display_label", + schema_root=SchemaRoot( + nodes=[ + NodeSchema( + name="Widget", + namespace="Test", + attributes=[AttributeSchema(name="name", kind="Text"), AttributeSchema(name="status", kind="Text")], + display_labels=["name__value", "status"], + display_label="{{ name__value|upper }}: {{ status__value|lower }}", + ) + ] + ), + display_label="{{ name__value|upper }}: {{ status__value|lower }}", + ), +] + + +@pytest.mark.parametrize( + "test_case", + [pytest.param(tc, id=tc.name) for tc in DISPLAY_LABEL_TEST_CASES], +) +async def test_expected_final_display_label( + test_case: DisplayLabelTestCase, +) -> None: + """Test that the final computed display label matches the expected value.""" + schema_branch = SchemaBranch(cache={}, name="test") + schema_branch.load_schema(schema=test_case.schema_root) + schema_branch.process() + node = schema_branch.get_node(name="TestWidget", duplicate=False) + assert node.display_label == test_case.display_label