2929 InfrahubPythonTransformConfig ,
3030 InfrahubRepositoryConfig ,
3131)
32+ from infrahub_sdk .spec .menu import MenuFile
33+ from infrahub_sdk .spec .object import ObjectFile
3234from infrahub_sdk .template import Jinja2Template
3335from infrahub_sdk .template .exceptions import JinjaTemplateError
3436from infrahub_sdk .utils import compare_lists
35- from infrahub_sdk .yaml import SchemaFile
37+ from infrahub_sdk .yaml import InfrahubFile , SchemaFile
3638from prefect import flow , task
3739from prefect .cache_policies import NONE
3840from prefect .logging import get_run_logger
3941from pydantic import BaseModel , Field
4042from pydantic import ValidationError as PydanticValidationError
4143from typing_extensions import Self
4244
43- from infrahub .core .constants import ArtifactStatus , ContentType , InfrahubKind , RepositorySyncStatus
45+ from infrahub .core .constants import ArtifactStatus , ContentType , InfrahubKind , RepositoryObjects , RepositorySyncStatus
4446from infrahub .core .registry import registry
4547from infrahub .events .artifact_action import ArtifactCreatedEvent , ArtifactUpdatedEvent
4648from infrahub .events .models import EventMeta
5456 import types
5557
5658 from infrahub_sdk .checks import InfrahubCheck
59+ from infrahub_sdk .ctl .utils import YamlFileVar
5760 from infrahub_sdk .schema .repository import InfrahubRepositoryArtifactDefinitionConfig
5861 from infrahub_sdk .transforms import InfrahubTransform
5962
@@ -159,7 +162,7 @@ async def init(cls, service: InfrahubServices, commit: str | None = None, **kwar
159162 async def ensure_location_is_defined (self ) -> None :
160163 if self .location :
161164 return
162- client = self .get_client ()
165+ client = self .sdk
163166 repo = await client .get (
164167 kind = CoreGenericRepository , name__value = self .name , exclude = ["tags" , "credential" ], raise_when_missing = True
165168 )
@@ -179,6 +182,7 @@ async def import_objects_from_files(
179182
180183 config_file = await self .get_repository_config (branch_name = infrahub_branch_name , commit = commit ) # type: ignore[misc]
181184 sync_status = RepositorySyncStatus .IN_SYNC if config_file else RepositorySyncStatus .ERROR_IMPORT
185+
182186 error : Exception | None = None
183187
184188 try :
@@ -189,6 +193,17 @@ async def import_objects_from_files(
189193 branch_name = infrahub_branch_name , commit = commit , config_file = config_file
190194 ) # type: ignore[misc]
191195
196+ await self .import_objects (
197+ branch_name = infrahub_branch_name ,
198+ commit = commit ,
199+ config_file = config_file ,
200+ ) # type: ignore[misc]
201+ await self .import_objects (
202+ branch_name = infrahub_branch_name ,
203+ commit = commit ,
204+ config_file = config_file ,
205+ ) # type: ignore[misc]
206+
192207 await self .import_all_python_files ( # type: ignore[call-overload]
193208 branch_name = infrahub_branch_name , commit = commit , config_file = config_file
194209 ) # type: ignore[misc]
@@ -815,6 +830,80 @@ async def import_python_transforms(
815830 log .info (f"TransformPython { transform_name !r} not found locally, deleting" )
816831 await transform_definition_in_graph [transform_name ].delete ()
817832
833+ async def _load_yamlfile_from_disk (self , paths : list [Path ], file_type : type [YamlFileVar ]) -> list [YamlFileVar ]:
834+ data_files = file_type .load_from_disk (paths = paths )
835+
836+ for data_file in data_files :
837+ if not data_file .valid or not data_file .content :
838+ raise ValueError (f"{ data_file .error_message } ({ data_file .location } )" )
839+
840+ return data_files
841+
842+ async def _load_objects (
843+ self ,
844+ paths : list [Path ],
845+ branch : str ,
846+ file_type : type [InfrahubFile ],
847+ ) -> None :
848+ """Load one or multiple objects files into Infrahub."""
849+
850+ log = get_run_logger ()
851+ files = await self ._load_yamlfile_from_disk (paths = paths , file_type = file_type )
852+
853+ for file in files :
854+ await file .validate_format (client = self .sdk , branch = branch )
855+ schema = await self .sdk .schema .get (kind = file .spec .kind , branch = branch )
856+ if not schema .human_friendly_id and not schema .default_filter :
857+ raise ValueError (
858+ f"Schemas of objects or menus defined within { file .location } "
859+ "should have a `human_friendly_id` defined to avoid creating duplicated objects."
860+ )
861+
862+ for file in files :
863+ log .info (f"Loading objects defined in { file .location } " )
864+ await file .process (client = self .sdk , branch = branch )
865+
866+ async def _import_file_paths (
867+ self , branch_name : str , commit : str , files_pathes : list [Path ], object_type : RepositoryObjects
868+ ) -> None :
869+ branch_wt = self .get_worktree (identifier = commit or branch_name )
870+ file_pathes = [branch_wt .directory / file_path for file_path in files_pathes ]
871+
872+ # We currently assume there can't be concurrent imports, but if so, we might need to clone the client before tracking here.
873+ async with self .sdk .start_tracking (
874+ identifier = f"group-repo-{ object_type .value } -{ self .id } " ,
875+ delete_unused_nodes = True ,
876+ branch = branch_name ,
877+ group_type = "CoreRepositoryGroup" ,
878+ group_params = {"content" : object_type .value , "repository" : str (self .id )},
879+ ):
880+ file_type = repo_object_type_to_file_type (object_type )
881+ await self ._load_objects (
882+ paths = file_pathes ,
883+ branch = branch_name ,
884+ file_type = file_type ,
885+ )
886+
887+ @task (name = "import-objects" , task_run_name = "Import Objects" , cache_policy = NONE ) # type: ignore[arg-type]
888+ async def import_objects (
889+ self ,
890+ branch_name : str ,
891+ commit : str ,
892+ config_file : InfrahubRepositoryConfig ,
893+ ) -> None :
894+ await self ._import_file_paths (
895+ branch_name = branch_name ,
896+ commit = commit ,
897+ files_pathes = config_file .objects ,
898+ object_type = RepositoryObjects .OBJECT ,
899+ )
900+ await self ._import_file_paths (
901+ branch_name = branch_name ,
902+ commit = commit ,
903+ files_pathes = config_file .menus ,
904+ object_type = RepositoryObjects .MENU ,
905+ )
906+
818907 @task (name = "check-definition-get" , task_run_name = "Get Check Definition" , cache_policy = NONE ) # type: ignore[arg-type]
819908 async def get_check_definition (
820909 self ,
@@ -1342,3 +1431,13 @@ async def render_artifact(
13421431
13431432 await self .service .event .send (event = event )
13441433 return ArtifactGenerateResult (changed = True , checksum = checksum , storage_id = storage_id , artifact_id = artifact .id )
1434+
1435+
1436+ def repo_object_type_to_file_type (repo_object : RepositoryObjects ) -> type [InfrahubFile ]:
1437+ match repo_object :
1438+ case RepositoryObjects .OBJECT :
1439+ return ObjectFile
1440+ case RepositoryObjects .MENU :
1441+ return MenuFile
1442+ case _:
1443+ raise ValueError (f"Unknown repository object type: { repo_object } " )
0 commit comments