Skip to content

Commit

Permalink
[Integration][ADO] Fix Entity Update Issue on Master Default Branch (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
lordsarcastic authored Jan 8, 2025
1 parent 2e5b8cd commit 9ec5975
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
deleteDependentEntities: true
createMissingRelatedEntities: true
useDefaultBranch: true
resources:
- kind: project
selector:
Expand Down
11 changes: 9 additions & 2 deletions integrations/azure-devops/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

<!-- towncrier release notes start -->

## 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)


Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)

10 changes: 10 additions & 0 deletions integrations/azure-devops/azure_devops/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 47 additions & 22 deletions integrations/azure-devops/azure_devops/webhooks/listeners/push.py
Original file line number Diff line number Diff line change
@@ -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}
Expand All @@ -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(
Expand Down

0 comments on commit 9ec5975

Please sign in to comment.