From 25140edf82cb12c8b3e7b1087185722a49bfecbc Mon Sep 17 00:00:00 2001 From: Adebayo Oluwadunsin Iyanuoluwa <88881603+oiadebayo@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:57:40 +0100 Subject: [PATCH] [Integration][ADO] Fix missing team context for non default teams while ingesting boards (#1127) --- integrations/azure-devops/CHANGELOG.md | 8 ++++++ .../client/azure_devops_client.py | 26 +++++++++++-------- integrations/azure-devops/pyproject.toml | 2 +- .../client/test_azure_devops_client.py | 6 +++-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/integrations/azure-devops/CHANGELOG.md b/integrations/azure-devops/CHANGELOG.md index fb25c3a3d0..ed1272aefd 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.79 (2024-11-07) + + +### Bug Fixes + +- Fixed the API endpoint used in the boards kind to iterate through all project teams, ensuring non-default team boards and columns are ingested + + ## 0.1.78 (2024-11-06) diff --git a/integrations/azure-devops/azure_devops/client/azure_devops_client.py b/integrations/azure-devops/azure_devops/client/azure_devops_client.py index 666110ce10..4e86886148 100644 --- a/integrations/azure-devops/azure_devops/client/azure_devops_client.py +++ b/integrations/azure-devops/azure_devops/client/azure_devops_client.py @@ -286,24 +286,27 @@ async def get_columns(self) -> AsyncGenerator[list[dict[str, Any]], None]: ] async def _enrich_boards( - self, boards: list[dict[str, Any]], project_id: str + self, boards: list[dict[str, Any]], project_id: str, team_id: str ) -> list[dict[str, Any]]: for board in boards: response = await self.send_request( "GET", - f"{self._organization_base_url}/{project_id}/{API_URL_PREFIX}/work/boards/{board['id']}", + f"{self._organization_base_url}/{project_id}/{team_id}/{API_URL_PREFIX}/work/boards/{board['id']}", ) board.update(response.json()) return boards - async def _get_boards(self, project_id: str) -> list[dict[str, Any]]: - get_boards_url = ( - f"{self._organization_base_url}/{project_id}/{API_URL_PREFIX}/work/boards" - ) - response = await self.send_request("GET", get_boards_url) - board_data = response.json().get("value", []) - logger.info(f"Found {len(board_data)} boards for project {project_id}") - return await self._enrich_boards(board_data, project_id) + async def _get_boards( + self, project_id: str + ) -> AsyncGenerator[list[dict[str, Any]], None]: + teams_url = f"{self._organization_base_url}/{API_URL_PREFIX}/projects/{project_id}/teams" + async for teams_in_project in self._get_paginated_by_top_and_skip(teams_url): + for team in teams_in_project: + get_boards_url = f"{self._organization_base_url}/{project_id}/{team['id']}/{API_URL_PREFIX}/work/boards" + response = await self.send_request("GET", get_boards_url) + board_data = response.json().get("value", []) + logger.info(f"Found {len(board_data)} boards for project {project_id}") + yield await self._enrich_boards(board_data, project_id, team["id"]) @cache_iterator_result() async def get_boards_in_organization( @@ -313,7 +316,8 @@ async def get_boards_in_organization( yield [ {**board, "__project": project} for project in projects - for board in await self._get_boards(project["id"]) + async for boards in self._get_boards(project["id"]) + for board in boards ] async def generate_subscriptions_webhook_events(self) -> list[WebhookEvent]: diff --git a/integrations/azure-devops/pyproject.toml b/integrations/azure-devops/pyproject.toml index 960386f154..e38f19bfb6 100644 --- a/integrations/azure-devops/pyproject.toml +++ b/integrations/azure-devops/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "azure-devops" -version = "0.1.78" +version = "0.1.79" description = "An Azure Devops Ocean integration" authors = ["Matan Geva "] diff --git a/integrations/azure-devops/tests/azure_devops/client/test_azure_devops_client.py b/integrations/azure-devops/tests/azure_devops/client/test_azure_devops_client.py index ab8a3ce55e..66f2003204 100644 --- a/integrations/azure-devops/tests/azure_devops/client/test_azure_devops_client.py +++ b/integrations/azure-devops/tests/azure_devops/client/test_azure_devops_client.py @@ -572,8 +572,10 @@ async def test_get_boards_in_organization(mock_event_context: MagicMock) -> None async def mock_generate_projects() -> AsyncGenerator[List[Dict[str, Any]], None]: yield [{"id": "proj1", "name": "Project One"}] - async def mock_get_boards(project_id: str) -> List[Dict[str, Any]]: - return [ + async def mock_get_boards( + project_id: str, + ) -> AsyncGenerator[List[Dict[str, Any]], None]: + yield [ {"id": "board1", "name": "Board One"}, {"id": "board2", "name": "Board Two"}, ]