diff --git a/integrations/azure-devops/.port/resources/port-app-config.yaml b/integrations/azure-devops/.port/resources/port-app-config.yaml index 5f65753452..22c6495922 100644 --- a/integrations/azure-devops/.port/resources/port-app-config.yaml +++ b/integrations/azure-devops/.port/resources/port-app-config.yaml @@ -1,5 +1,6 @@ deleteDependentEntities: true createMissingRelatedEntities: true +useDefaultBranch: true resources: - kind: project selector: diff --git a/integrations/azure-devops/CHANGELOG.md b/integrations/azure-devops/CHANGELOG.md index 2b670ff3da..84e6da5cb7 100644 --- a/integrations/azure-devops/CHANGELOG.md +++ b/integrations/azure-devops/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +## 0.1.104 (2025-01-08) + + +### Bug Fixes + +- Fixed bug where push events for port.yml file aren't processed for default branches + + ## 0.1.103 (2025-01-07) @@ -495,7 +503,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug Fixes -- Fixed `visibility` property in mapping which had a typo and changed the default relation to required `false` to be more permissive +- Fixed `visibility` property in mapping which had a typo and changed the default relation to required `false` to be more permissive ## 0.1.41 (2024-07-10) @@ -786,4 +794,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features - Created Azure DevOps ## using Ocean (PORT-4585) - diff --git a/integrations/azure-devops/azure_devops/misc.py b/integrations/azure-devops/azure_devops/misc.py index 18252a5fdf..cebb02f7e0 100644 --- a/integrations/azure-devops/azure_devops/misc.py +++ b/integrations/azure-devops/azure_devops/misc.py @@ -69,6 +69,16 @@ class AzureDevopsSelector(Selector): class GitPortAppConfig(PortAppConfig): spec_path: List[str] | str = Field(alias="specPath", default="port.yml") + use_default_branch: bool | None = Field( + default=None, + description=( + "If set to true, it uses default branch of the repository" + " for syncing the entities to Port. If set to false or None" + ", it uses the branch mentioned in the `branch` config pro" + "perty." + ), + alias="useDefaultBranch", + ) branch: str = "main" resources: list[ AzureDevopsProjectResourceConfig diff --git a/integrations/azure-devops/azure_devops/webhooks/listeners/push.py b/integrations/azure-devops/azure_devops/webhooks/listeners/push.py index b1b38f3be7..54e0558c3b 100644 --- a/integrations/azure-devops/azure_devops/webhooks/listeners/push.py +++ b/integrations/azure-devops/azure_devops/webhooks/listeners/push.py @@ -1,22 +1,24 @@ import asyncio import typing from typing import Any, Dict + from loguru import logger +from port_ocean.clients.port.types import UserAgentType from port_ocean.context.event import event from port_ocean.context.ocean import ocean -from port_ocean.clients.port.types import UserAgentType + +from azure_devops.gitops.generate_entities import generate_entities_from_commit_id +from azure_devops.misc import GitPortAppConfig, Kind, extract_branch_name_from_ref from azure_devops.webhooks.webhook_event import WebhookEvent -from azure_devops.misc import extract_branch_name_from_ref + from .listener import HookListener -from azure_devops.misc import GitPortAppConfig -from azure_devops.gitops.generate_entities import generate_entities_from_commit_id -from azure_devops.misc import Kind class PushHookListener(HookListener): webhook_events = [WebhookEvent(publisherId="tfs", eventType="git.push")] async def on_hook(self, data: Dict[str, Any]) -> None: + logger.debug(f"Got push event with initial data {data}") config: GitPortAppConfig = typing.cast(GitPortAppConfig, event.port_app_config) push_url = data["resource"]["url"] push_params = {"includeRefUpdates": True} @@ -27,33 +29,56 @@ async def on_hook(self, data: Dict[str, Any]) -> None: ref_update_tasks = [] for update in updates: + branch = extract_branch_name_from_ref(update["name"]) + if config.use_default_branch: + # The repository's default branch is not included in the ref updates + # but is in the initial data from the webhook event from the path + # `resource.repository.defaultBranch` + default_branch_with_ref: str = data["resource"]["repository"][ + "defaultBranch" + ] + default_branch = extract_branch_name_from_ref(default_branch_with_ref) + else: + default_branch = config.branch + + if branch != default_branch: + logger.info("Skipping ref update for non-default branch") + continue task = asyncio.create_task(self.process_ref_update(config, update)) ref_update_tasks.append(task) + if not ref_update_tasks: + logger.info("No ref updates to process") + return + + logger.debug(f"Created {len(ref_update_tasks)} tasks for processing updates") + await asyncio.gather(*ref_update_tasks, self.register_repository(push_data)) async def process_ref_update( - self, config: GitPortAppConfig, update: Dict[str, Any] + self, + config: GitPortAppConfig, + update: Dict[str, Any], ) -> None: + logger.info(f"Processing ref update with update: {update}") repo_id = update["repositoryId"] - branch = extract_branch_name_from_ref(update["name"]) old_commit = update["oldObjectId"] new_commit = update["newObjectId"] - if config.branch == branch: - new_entities = await generate_entities_from_commit_id( - self._client, config.spec_path, repo_id, new_commit - ) - logger.info(f"Got {len(new_entities)} new entities") - - old_entities = await generate_entities_from_commit_id( - self._client, config.spec_path, repo_id, old_commit - ) - logger.info(f"Got {len(old_entities)} old entities") - - await ocean.update_diff( - {"before": old_entities, "after": new_entities}, - UserAgentType.gitops, - ) + + new_entities = await generate_entities_from_commit_id( + self._client, config.spec_path, repo_id, new_commit + ) + logger.info(f"Got {len(new_entities)} new entities") + + old_entities = await generate_entities_from_commit_id( + self._client, config.spec_path, repo_id, old_commit + ) + logger.info(f"Got {len(old_entities)} old entities") + + await ocean.update_diff( + {"before": old_entities, "after": new_entities}, + UserAgentType.gitops, + ) async def register_repository(self, push_data: Dict[str, Any]) -> None: await ocean.register_raw(