diff --git a/backend/infrahub/core/merge.py b/backend/infrahub/core/merge.py index 994eee4f27..ec226ecf57 100644 --- a/backend/infrahub/core/merge.py +++ b/backend/infrahub/core/merge.py @@ -6,7 +6,7 @@ from infrahub.core.diff.model.path import BranchTrackingId from infrahub.core.manager import NodeManager from infrahub.core.models import SchemaUpdateValidationResult -from infrahub.core.protocols import CoreRepository +from infrahub.core.protocols import CoreReadOnlyRepository, CoreRepository from infrahub.core.registry import registry from infrahub.core.timestamp import Timestamp from infrahub.exceptions import MergeFailedError, ValidationError @@ -223,6 +223,30 @@ async def rollback(self) -> None: await self.diff_merger.rollback(at=self._merge_at) async def merge_repositories(self) -> None: + await self.merge_core_read_only_repositories() + await self.merge_core_repositories() + + async def merge_core_read_only_repositories(self) -> None: + repos_in_main_list = await NodeManager.query(schema=CoreReadOnlyRepository, db=self.db) + repos_in_main = {repo.id: repo for repo in repos_in_main_list} + + repos_in_branch_list = await NodeManager.query( + schema=CoreReadOnlyRepository, db=self.db, branch=self.source_branch + ) + for repo in repos_in_branch_list: + if repo.id not in repos_in_main: + continue + + model = GitRepositoryMerge( + repository_id=repo.id, + repository_name=repo.name.value, + source_branch=self.source_branch.name, + destination_branch=self.destination_branch.name, + destination_branch_id=str(self.destination_branch.get_uuid()), + ) + await self.workflow.submit_workflow(workflow=GIT_REPOSITORIES_MERGE, parameters={"model": model}) + + async def merge_core_repositories(self) -> None: # Collect all Repositories in Main because we'll need the commit in Main for each one. repos_in_main_list = await NodeManager.query(schema=CoreRepository, db=self.db) repos_in_main = {repo.id: repo for repo in repos_in_main_list} diff --git a/backend/infrahub/git/models.py b/backend/infrahub/git/models.py index 3d58744314..70804a9a97 100644 --- a/backend/infrahub/git/models.py +++ b/backend/infrahub/git/models.py @@ -88,11 +88,11 @@ class GitRepositoryMerge(BaseModel): repository_id: str = Field(..., description="The unique ID of the Repository") repository_name: str = Field(..., description="The name of the repository") - internal_status: str = Field(..., description="Administrative status of the repository") + internal_status: str | None = Field(default=None, description="Administrative status of the repository") source_branch: str = Field(..., description="The source branch") destination_branch: str = Field(..., description="The destination branch") destination_branch_id: str = Field(..., description="The ID of the destination branch") - default_branch: str = Field(..., description="The default branch in Git") + default_branch: str | None = Field(default=None, description="The default branch in Git") class GitRepositoryImportObjects(BaseModel): diff --git a/backend/infrahub/git/tasks.py b/backend/infrahub/git/tasks.py index e85235bc6a..16c418208e 100644 --- a/backend/infrahub/git/tasks.py +++ b/backend/infrahub/git/tasks.py @@ -502,6 +502,7 @@ async def pull_read_only(model: GitRepositoryPullReadOnly) -> None: flow_run_name="Merge {model.source_branch} > {model.destination_branch} in git repository", ) async def merge_git_repository(model: GitRepositoryMerge) -> None: + log = get_run_logger() await add_tags(branches=[model.source_branch, model.destination_branch], nodes=[model.repository_id]) client = get_client() @@ -511,6 +512,7 @@ async def merge_git_repository(model: GitRepositoryMerge) -> None: ) if model.internal_status == RepositoryInternalStatus.STAGING.value: + log.info(f"Merging {InfrahubKind.GENERICREPOSITORY}") repo_source = await client.get( kind=InfrahubKind.GENERICREPOSITORY, id=model.repository_id, branch=model.source_branch ) @@ -522,6 +524,28 @@ async def merge_git_repository(model: GitRepositoryMerge) -> None: repo_main.commit.value = commit await repo_main.save() + log.info(f"Finished merging {InfrahubKind.GENERICREPOSITORY}") + + elif not model.default_branch: + repo_source = await client.get( + kind=InfrahubKind.READONLYREPOSITORY, id=model.repository_id, branch=model.source_branch + ) + repo_destination = await client.get( + kind=InfrahubKind.READONLYREPOSITORY, id=model.repository_id, branch=model.destination_branch + ) + + if ( + repo_destination.ref.value != repo_source.ref.value + or repo_destination.commit.value != repo_source.commit.value + ): + log.info(f"Merging {InfrahubKind.READONLYREPOSITORY}") + + repo_destination.ref.value = repo_source.ref.value + repo_destination.commit.value = repo_source.commit.value + await repo_destination.save() + + log.info(f"Finished merging {InfrahubKind.READONLYREPOSITORY}") + else: async with lock.registry.get(name=model.repository_name, namespace="repository"): await repo.merge(source_branch=model.source_branch, dest_branch=model.destination_branch) diff --git a/backend/tests/unit/core/diff/test_coordinator_lock.py b/backend/tests/unit/core/diff/test_coordinator_lock.py index 12cd8d6406..fdd7f58cc1 100644 --- a/backend/tests/unit/core/diff/test_coordinator_lock.py +++ b/backend/tests/unit/core/diff/test_coordinator_lock.py @@ -16,7 +16,7 @@ from infrahub.core.merge import BranchMerger from infrahub.core.node import Node from infrahub.core.schema import SchemaRoot -from infrahub.core.schema.definitions.core.repository import core_repository +from infrahub.core.schema.definitions.core.repository import core_read_only_repository, core_repository from infrahub.core.schema.node_schema import NodeSchema from infrahub.core.timestamp import Timestamp from infrahub.database import InfrahubDatabase, get_db @@ -55,6 +55,15 @@ async def dummy_repository_schema(self, db: InfrahubDatabase, default_branch: Br default_branch.update_schema_hash() await default_branch.save(db=db) + dummy_repository = NodeSchema( + name=core_read_only_repository.name, + namespace=core_read_only_repository.namespace, + ) + schema = SchemaRoot(nodes=[dummy_repository]) + registry.schema.register_schema(schema=schema, branch=default_branch.name) + default_branch.update_schema_hash() + await default_branch.save(db=db) + async def get_diff_coordinator(self, db: InfrahubDatabase, diff_branch: Branch) -> DiffCoordinator: config.SETTINGS.database.max_depth_search_hierarchy = 10 component_registry = get_component_registry() diff --git a/changelog/5978.added.md b/changelog/5978.added.md new file mode 100644 index 0000000000..746c8e3943 --- /dev/null +++ b/changelog/5978.added.md @@ -0,0 +1 @@ +Merge core read only repositories on branch merge