Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Integration][ADO] Fix Entity Update Issue on Master Default Branch #1248

Merged
merged 12 commits into from
Jan 8, 2025
Merged
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")
lordsarcastic marked this conversation as resolved.
Show resolved Hide resolved

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
Loading