Skip to content
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
27 changes: 24 additions & 3 deletions backend/infrahub/api/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@
SchemaDiff,
SchemaUpdateValidationResult,
)
from infrahub.core.schema import GenericSchema, MainSchemaTypes, NodeSchema, ProfileSchema, SchemaRoot, TemplateSchema
from infrahub.core.schema import (
GenericSchema,
MainSchemaTypes,
NodeSchema,
ProfileSchema,
SchemaRoot,
SchemaWarning,
TemplateSchema,
)
from infrahub.core.schema.constants import SchemaNamespace # noqa: TC001
from infrahub.core.validators.models.validate_migration import (
SchemaValidateMigrationData,
Expand Down Expand Up @@ -130,6 +138,9 @@ class SchemaUpdate(BaseModel):
hash: str = Field(..., description="The new hash for the entire schema")
previous_hash: str = Field(..., description="The previous hash for the entire schema")
diff: SchemaDiff = Field(..., description="The modifications to the schema")
warnings: list[SchemaWarning] = Field(
default_factory=list, description="Warnings encountered while loading the schema"
)

@computed_field
def schema_updated(self) -> bool:
Expand Down Expand Up @@ -307,8 +318,10 @@ async def load_schema(
log.info("schema_load_request", branch=branch.name)

errors: list[str] = []
warnings: list[SchemaWarning] = []
for schema in schemas.schemas:
errors += schema.validate_namespaces()
warnings += schema.gather_warnings()

if errors:
raise SchemaNotValidError(message=", ".join(errors))
Expand Down Expand Up @@ -402,7 +415,7 @@ async def load_schema(
)
await service.event.send(event=event)

return SchemaUpdate(hash=updated_hash, previous_hash=original_hash, diff=result.diff)
return SchemaUpdate(hash=updated_hash, previous_hash=original_hash, diff=result.diff, warnings=warnings)


@router.post("/check")
Expand All @@ -417,8 +430,10 @@ async def check_schema(
log.info("schema_check_request", branch=branch.name)

errors: list[str] = []
warnings: list[SchemaWarning] = []
for schema in schemas.schemas:
errors += schema.validate_namespaces()
warnings += schema.gather_warnings()

if errors:
raise SchemaNotValidError(message=", ".join(errors))
Expand All @@ -445,4 +460,10 @@ async def check_schema(
if error_messages:
raise SchemaNotValidError(message=",\n".join(error_messages))

return JSONResponse(status_code=202, content={"diff": result.diff.model_dump()})
return JSONResponse(
status_code=202,
content={
"diff": result.diff.model_dump(),
"warnings": [warning.model_dump(mode="json") for warning in warnings],
},
)
56 changes: 56 additions & 0 deletions backend/infrahub/core/schema/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import uuid
from enum import Enum
from typing import Any, TypeAlias

from infrahub_sdk.utils import deep_merge_dict
Expand Down Expand Up @@ -44,6 +45,21 @@ class SchemaExtension(HashableModel):
nodes: list[NodeExtensionSchema] = Field(default_factory=list)


class SchemaWarningType(Enum):
DEPRECATION = "deprecation"


class SchemaWarningKind(BaseModel):
kind: str = Field(..., description="The kind impacted by the warning")
field: str | None = Field(default=None, description="The attribute or relationship impacted by the warning")


class SchemaWarning(BaseModel):
type: SchemaWarningType = Field(..., description="The type of warning")
kinds: list[SchemaWarningKind] = Field(default_factory=list, description="The kinds impacted by the warning")
message: str = Field(..., description="The message that describes the warning")


class SchemaRoot(BaseModel):
model_config = ConfigDict(extra="forbid")

Expand Down Expand Up @@ -80,6 +96,46 @@ def validate_namespaces(self) -> list[str]:

return errors

def gather_warnings(self) -> list[SchemaWarning]:
models = self.nodes + self.generics
warnings: list[SchemaWarning] = []
for model in models:
if model.display_labels is not None:
warnings.append(
SchemaWarning(
type=SchemaWarningType.DEPRECATION,
kinds=[SchemaWarningKind(kind=model.kind)],
message="display_labels are deprecated, use display_label instead",
)
)
if model.default_filter is not None:
warnings.append(
SchemaWarning(
type=SchemaWarningType.DEPRECATION,
kinds=[SchemaWarningKind(kind=model.kind)],
message="default_filter is deprecated",
)
)
for attribute in model.attributes:
if attribute.max_length is not None:
warnings.append(
SchemaWarning(
type=SchemaWarningType.DEPRECATION,
kinds=[SchemaWarningKind(kind=model.kind, field=attribute.name)],
message="Use of 'max_length' on attributes is deprecated, use parameters instead",
)
)
if attribute.min_length is not None:
warnings.append(
SchemaWarning(
type=SchemaWarningType.DEPRECATION,
kinds=[SchemaWarningKind(kind=model.kind, field=attribute.name)],
message="Use of 'min_length' on attributes is deprecated, use parameters instead",
)
)

return warnings

def generate_uuid(self) -> None:
"""Generate UUID for all nodes, attributes & relationships
Mainly useful during unit tests."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,29 @@ async def test_schema02_load_update(
},
},
"removed": {},
}
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingThingLegacy", "field": "value"}],
"message": "Use of 'max_length' on attributes is deprecated, use parameters instead",
},
{
"type": "deprecation",
"kinds": [{"kind": "TestingThingLegacy", "field": "value"}],
"message": "Use of 'min_length' on attributes is deprecated, use parameters instead",
},
{
"type": "deprecation",
"kinds": [{"kind": "TestingThing", "field": "value"}],
"message": "Use of 'max_length' on attributes is deprecated, use parameters instead",
},
{
"type": "deprecation",
"kinds": [{"kind": "TestingThing", "field": "value"}],
"message": "Use of 'min_length' on attributes is deprecated, use parameters instead",
},
],
}

async def test_step02_load_schema_with_overrides(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ async def test_step02_check_add_specific_overrides(
},
"removed": {},
},
"warnings": [],
}

async def test_step02_load_schema_with_overrides(
Expand Down Expand Up @@ -787,6 +788,7 @@ async def test_step03_check_delete_overridden_field(
},
"removed": {},
},
"warnings": [],
}

async def test_step03_load_schema_with_deleted_override(
Expand Down Expand Up @@ -942,6 +944,7 @@ async def test_step04_check_generic_weight_updates(
},
"removed": {},
},
"warnings": [],
}

async def test_step04_load_schema_with_updated_generic_weight(
Expand Down Expand Up @@ -1170,6 +1173,7 @@ async def test_step05_check_delete_generic_fields(
},
"removed": {},
},
"warnings": [],
}

async def test_step05_load_schema_with_generic_deletes(
Expand Down Expand Up @@ -1331,6 +1335,7 @@ async def test_step06_check_deleted_overridden_fields(
},
"removed": {},
},
"warnings": [],
}

async def test_step06_load_schema_with_override_deletes(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ async def test_step02_check_attr_add_rename(
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}

async def test_step02_load_attr_add_rename(
Expand Down Expand Up @@ -287,6 +294,13 @@ async def test_step03_check(self, db: InfrahubDatabase, client: InfrahubClient,
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ async def test_check_schema_02(self, client: InfrahubClient, branch_1: Branch, l
},
},
},
"warnings": [],
}

async def test_load_schema_02(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,8 @@ async def test_step02_check_change_node_kind(
"added": {},
"changed": {SPECIFIC_ONE_KIND_UPDATED: {"added": {}, "changed": {"name": None}, "removed": {}}},
"removed": {},
}
},
"warnings": [],
}

async def test_step02_load_node_kind_change(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ async def test_step02_check(self, db: InfrahubDatabase, client: InfrahubClient,
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

Expand Down Expand Up @@ -297,6 +304,13 @@ async def test_step03_check(self, db: InfrahubDatabase, client: InfrahubClient,
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ async def test_step02_check_attr_add_rename(
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}

async def test_step02_load(self, db: InfrahubDatabase, client: InfrahubClient, initial_dataset, schema_step02):
Expand Down Expand Up @@ -185,6 +192,13 @@ async def test_step03_check(self, db: InfrahubDatabase, client: InfrahubClient,
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,13 @@ async def test_step02_check_attr_add_rename(
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}

async def test_step02_load_attr_add_rename(
Expand Down Expand Up @@ -283,6 +290,13 @@ async def test_step03_check(self, db: InfrahubDatabase, client: InfrahubClient,
},
"removed": {},
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

Expand Down Expand Up @@ -357,7 +371,16 @@ async def test_step04_check(self, db: InfrahubDatabase, client: InfrahubClient,

success, response = await client.schema.check(schemas=[schema_step04], branch=self.branch1.name)

assert response == {"diff": {"added": {}, "changed": {}, "removed": {"TestingTag": None}}}
assert response == {
"diff": {"added": {}, "changed": {}, "removed": {"TestingTag": None}},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

async def test_step04_load(self, db: InfrahubDatabase, client: InfrahubClient, initial_dataset, schema_step04):
Expand Down Expand Up @@ -416,7 +439,14 @@ async def test_step05_check(self, db: InfrahubDatabase, client: InfrahubClient,
"removed": {},
},
},
}
},
"warnings": [
{
"type": "deprecation",
"kinds": [{"kind": "TestingCar", "field": None}],
"message": "default_filter is deprecated",
}
],
}
assert success

Expand Down
Loading