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

IFC-619 Add deprecation for attributes and relationships #4931

Merged
merged 4 commits into from
Nov 20, 2024
Merged
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 backend/infrahub/core/schema/attribute_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def is_attribute(self) -> bool:
def is_relationship(self) -> bool:
return False

@property
def is_deprecated(self) -> bool:
return bool(self.deprecation)

@field_validator("kind")
@classmethod
def kind_options(cls, v: str) -> str:
Expand Down
16 changes: 16 additions & 0 deletions backend/infrahub/core/schema/definitions/internal.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,14 @@ def to_dict(self) -> dict[str, Any]:
optional=True,
extra={"update": UpdateSupport.ALLOWED},
),
SchemaAttribute(
name="deprecation",
kind="Text",
optional=True,
description="Mark attribute as deprecated and provide a user-friendly message to display",
max_length=DEFAULT_DESCRIPTION_LENGTH,
extra={"update": UpdateSupport.ALLOWED},
),
],
relationships=[
SchemaRelationship(
Expand Down Expand Up @@ -803,6 +811,14 @@ def to_dict(self) -> dict[str, Any]:
optional=True,
extra={"update": UpdateSupport.ALLOWED},
),
SchemaAttribute(
name="deprecation",
kind="Text",
optional=True,
description="Mark relationship as deprecated and provide a user-friendly message to display",
max_length=DEFAULT_DESCRIPTION_LENGTH,
extra={"update": UpdateSupport.ALLOWED},
),
],
relationships=[
SchemaRelationship(
Expand Down
6 changes: 6 additions & 0 deletions backend/infrahub/core/schema/generated/attribute_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,9 @@ class GeneratedAttributeSchema(HashableModel):
description="Type of allowed override for the attribute.",
json_schema_extra={"update": "allowed"},
)
deprecation: Optional[str] = Field(
default=None,
description="Mark attribute as deprecated and provide a user-friendly message to display",
max_length=128,
json_schema_extra={"update": "allowed"},
)
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,9 @@ class GeneratedRelationshipSchema(HashableModel):
description="Set the relationship as read-only, users won't be able to change its value.",
json_schema_extra={"update": "allowed"},
)
deprecation: Optional[str] = Field(
default=None,
description="Mark relationship as deprecated and provide a user-friendly message to display",
max_length=128,
json_schema_extra={"update": "allowed"},
)
4 changes: 4 additions & 0 deletions backend/infrahub/core/schema/relationship_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def is_attribute(self) -> bool:
def is_relationship(self) -> bool:
return True

@property
def is_deprecated(self) -> bool:
return bool(self.deprecation)

def get_class(self) -> type[Relationship]:
return Relationship

Expand Down
24 changes: 24 additions & 0 deletions backend/infrahub/core/schema/schema_branch.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ def process(self, validate_schema: bool = True) -> None:
def process_pre_validation(self) -> None:
self.generate_identifiers()
self.process_default_values()
self.process_deprecations()
self.process_cardinality_counts()
self.process_inheritance()
self.process_hierarchy()
Expand Down Expand Up @@ -1348,6 +1349,29 @@ def process_cardinality_counts(self) -> None:

self.set(name=name, schema=node)

def process_deprecations(self) -> None:
"""Mark deprecated attributes and relationships as optional."""
for name in self.all_names:
node = self.get(name=name, duplicate=False)

change_required = False
for item in node.attributes + node.relationships:
if item.is_deprecated:
gmazoyer marked this conversation as resolved.
Show resolved Hide resolved
log.warn(f"'{item.name}' for '{node.kind}' has been marked as deprecated, remember to clean it up")
if not item.optional:
change_required = True

if not change_required:
continue

node = node.duplicate()

for item in node.attributes + node.relationships:
if item.is_deprecated and not item.optional:
item.optional = True

self.set(name=name, schema=node)

def generate_weight(self) -> None:
for name in self.all_names:
node = self.get(name=name, duplicate=False)
Expand Down
45 changes: 45 additions & 0 deletions backend/tests/unit/core/schema_manager/test_manager_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2571,3 +2571,48 @@ def test_schema_branch_conflicting_required_relationships(schema_all_in_one):
assert "BuiltinTag" in exc.value.args[0]
assert "BuiltinCriticality" in exc.value.args[0]
assert "cannot both have required relationships" in exc.value.args[0]


async def test_process_deprecations(organization_schema):
SCHEMA1 = {
"name": "Criticality",
"namespace": "Test",
"default_filter": "name__value",
"branch": BranchSupportType.AWARE.value,
"attributes": [
{"name": "name", "kind": "Text", "unique": True},
{"name": "description", "kind": "Text", "deprecation": "I'm not used anymore"},
],
"relationships": [
{
"name": "first",
"peer": "CoreOrganization",
"cardinality": "one",
"optional": False,
"deprecation": "Use the second one instead",
},
{"name": "second", "peer": "CoreOrganization", "cardinality": "one", "optional": False},
],
}

copy_core_models = copy.deepcopy(core_models)
copy_core_models["nodes"].append(SCHEMA1)
schema = SchemaRoot(**copy_core_models)

schema_branch = SchemaBranch(cache={}, name="test")
schema_branch.load_schema(schema=schema)
schema_branch.load_schema(schema=organization_schema)

schema_branch.process_deprecations()

test_criticality = schema_branch.get_node(name="TestCriticality", duplicate=False)

assert not test_criticality.get_attribute(name="name").is_deprecated
assert test_criticality.get_attribute(name="description").is_deprecated
assert test_criticality.get_relationship(name="first").is_deprecated
assert not test_criticality.get_relationship(name="second").is_deprecated

assert not test_criticality.get_attribute(name="name").optional
assert test_criticality.get_attribute(name="description").optional
assert test_criticality.get_relationship(name="first").optional
assert not test_criticality.get_relationship(name="second").optional
1 change: 1 addition & 0 deletions changelog/4245.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a "deprecation" property to attribute and relationship schema in order to allow users to identify deprecated fields for nodes and provide a user-friendly message about the deprecation reasons.
12 changes: 12 additions & 0 deletions docs/docs/reference/schema/attribute.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Below is the list of all available options to define an Attribute in the schema
| [**choices**](#choices) | Attribute | Define a list of valid choices for a dropdown attribute. | False |
| [**computed_attribute**](#computed_attribute) | Attribute | Defines how the value of this attribute will be populated. | False |
| [**default_value**](#default_value) | Attribute | Default value of the attribute. | False |
| [**deprecation**](#deprecation) | Attribute | Mark attribute as deprecated and provide a user-friendly message to display | False |
| [**description**](#description) | Attribute | Short description of the attribute. | False |
| [**enum**](#enum) | Attribute | Define a list of valid values for the attribute. | False |
| [**kind**](#kind) | Attribute | Defines the type of the attribute. | True |
Expand Down Expand Up @@ -114,6 +115,17 @@ extensions:
| **Default Value** | |
| **Constraints** | |

### deprecation

| Key | Value |
| ---- | --------------- |
| **Name** | deprecation |
| **Kind** | `Text` |
| **Description** | Mark attribute as deprecated and provide a user-friendly message to display |
| **Optional** | True |
| **Default Value** | |
| **Constraints** | Length: min -, max 128 |

### description

| Key | Value |
Expand Down
12 changes: 12 additions & 0 deletions docs/docs/reference/schema/relationship.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Below is the list of all available options to define a Relationship in the schem
| [**allow_override**](#allow_override) | Attribute | Type of allowed override for the relationship. | False |
| [**branch**](#branch) | Attribute | Type of branch support for the relatioinship, if not defined it will be determine based both peers. | False |
| [**cardinality**](#cardinality) | Attribute | Defines how many objects are expected on the other side of the relationship. | False |
| [**deprecation**](#deprecation) | Attribute | Mark relationship as deprecated and provide a user-friendly message to display | False |
| [**description**](#description) | Attribute | Short description of the relationship. | False |
| [**direction**](#direction) | Attribute | Defines the direction of the relationship, Unidirectional relationship are required when the same model is on both side. | False |
| [**hierarchical**](#hierarchical) | Attribute | Internal attribute to track the type of hierarchy this relationship is part of, must match a valid Generic Kind | False |
Expand Down Expand Up @@ -72,6 +73,17 @@ Below is the list of all available options to define a Relationship in the schem
| **Constraints** | |
| **Accepted Values** | `one` `many` |

### deprecation

| Key | Value |
| ---- | --------------- |
| **Name** | deprecation |
| **Kind** | `Text` |
| **Description** | Mark relationship as deprecated and provide a user-friendly message to display |
| **Optional** | True |
| **Default Value** | |
| **Constraints** | Length: min -, max 128 |

### description

| Key | Value |
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/reference/schema/validator-migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ In this context, an element represent either a Node, a Generic, an Attribute or
| **order_weight** | allowed |
| **default_value** | allowed |
| **allow_override** | allowed |
| **deprecation** | allowed |


### Relationship
Expand All @@ -91,6 +92,7 @@ In this context, an element represent either a Node, a Generic, an Attribute or
| **on_delete** | allowed |
| **allow_override** | allowed |
| **read_only** | allowed |
| **deprecation** | allowed |


### Generic
Expand Down
Loading