mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-02 03:40:38 +08:00
feat: enhance Azure DevOps integration by adding work item as a ticket retrieval methods - Supporting ticket context for Azure DevOps
Signed-off-by: abishlal <abishlalns03@gmail.com>
This commit is contained in:
@ -39,7 +39,7 @@ class AzureDevopsProvider(GitProvider):
|
||||
"Azure DevOps provider is not available. Please install the required dependencies."
|
||||
)
|
||||
|
||||
self.azure_devops_client = self._get_azure_devops_client()
|
||||
self.azure_devops_client, self.azure_devops_board_client = self._get_azure_devops_client()
|
||||
self.diff_files = None
|
||||
self.workspace_slug = None
|
||||
self.repo_slug = None
|
||||
@ -593,8 +593,9 @@ class AzureDevopsProvider(GitProvider):
|
||||
credentials = BasicAuthentication("", auth_token)
|
||||
azure_devops_connection = Connection(base_url=org, creds=credentials)
|
||||
azure_devops_client = azure_devops_connection.clients.get_git_client()
|
||||
azure_devops_board_client = azure_devops_connection.clients.get_work_item_tracking_client()
|
||||
|
||||
return azure_devops_client
|
||||
return azure_devops_client, azure_devops_board_client
|
||||
|
||||
def _get_repo(self):
|
||||
if self.repo is None:
|
||||
@ -636,3 +637,49 @@ class AzureDevopsProvider(GitProvider):
|
||||
url = self.azure_devops_client.normalized_url + "/" + self.workspace_slug + "/_git/" + self.repo_slug + "/commit/" + last.commit_id
|
||||
return url
|
||||
|
||||
def get_linked_work_items(self) -> list:
|
||||
"""
|
||||
Get linked work items from the PR.
|
||||
"""
|
||||
try:
|
||||
work_items = self.azure_devops_client.get_pull_request_work_item_refs(
|
||||
project=self.workspace_slug,
|
||||
repository_id=self.repo_slug,
|
||||
pull_request_id=self.pr_num,
|
||||
)
|
||||
ids = [work_item.id for work_item in work_items]
|
||||
if not work_items:
|
||||
return []
|
||||
items = self.get_work_items(ids)
|
||||
return items
|
||||
except Exception as e:
|
||||
get_logger().exception(f"Failed to get linked work items, error: {e}")
|
||||
return []
|
||||
|
||||
def get_work_items(self, work_item_ids: int) -> list:
|
||||
"""
|
||||
Get work items by their IDs.
|
||||
"""
|
||||
try:
|
||||
raw_work_items = self.azure_devops_board_client.get_work_items(
|
||||
project=self.workspace_slug,
|
||||
ids=work_item_ids,
|
||||
)
|
||||
work_items = []
|
||||
for item in raw_work_items:
|
||||
work_items.append(
|
||||
{
|
||||
"id": item.id,
|
||||
"title": item.fields.get("System.Title", ""),
|
||||
"url": item.url,
|
||||
"body": item.fields.get("System.Description", ""),
|
||||
"state": item.fields.get("System.State", ""),
|
||||
"acceptance_criteria": item.fields.get(
|
||||
"Microsoft.VSTS.Common.AcceptanceCriteria", ""
|
||||
),
|
||||
}
|
||||
)
|
||||
return work_items
|
||||
except Exception as e:
|
||||
get_logger().exception(f"Failed to get work items, error: {e}")
|
||||
return []
|
||||
|
@ -199,6 +199,13 @@ Ticket Description:
|
||||
{{ ticket.body }}
|
||||
#####
|
||||
{%- endif %}
|
||||
|
||||
{%- if ticket.requirements %}
|
||||
Ticket Requirements:
|
||||
#####
|
||||
{{ ticket.requirements }}
|
||||
#####
|
||||
{%- endif %}
|
||||
=====
|
||||
{% endfor %}
|
||||
{%- endif %}
|
||||
|
@ -3,6 +3,7 @@ import traceback
|
||||
|
||||
from pr_agent.config_loader import get_settings
|
||||
from pr_agent.git_providers import GithubProvider
|
||||
from pr_agent.git_providers import AzureDevopsProvider
|
||||
from pr_agent.log import get_logger
|
||||
|
||||
# Compile the regex pattern once, outside the function
|
||||
@ -131,6 +132,32 @@ async def extract_tickets(git_provider):
|
||||
|
||||
return tickets_content
|
||||
|
||||
elif isinstance(git_provider, AzureDevopsProvider):
|
||||
tickets_info = git_provider.get_linked_work_items()
|
||||
tickets_content = []
|
||||
for ticket in tickets_info:
|
||||
try:
|
||||
ticket_body_str = ticket.get("body", "")
|
||||
if len(ticket_body_str) > MAX_TICKET_CHARACTERS:
|
||||
ticket_body_str = ticket_body_str[:MAX_TICKET_CHARACTERS] + "..."
|
||||
|
||||
tickets_content.append(
|
||||
{
|
||||
"ticket_id": ticket.get("id"),
|
||||
"ticket_url": ticket.get("url"),
|
||||
"title": ticket.get("title"),
|
||||
"body": ticket_body_str,
|
||||
"labels": ", ".join(ticket.get("labels", [])),
|
||||
"requirements": ticket.get("acceptance_criteria", ""),
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
get_logger().error(
|
||||
f"Error processing Azure DevOps ticket: {e}",
|
||||
artifact={"traceback": traceback.format_exc()},
|
||||
)
|
||||
return tickets_content
|
||||
|
||||
except Exception as e:
|
||||
get_logger().error(f"Error extracting tickets error= {e}",
|
||||
artifact={"traceback": traceback.format_exc()})
|
||||
|
Reference in New Issue
Block a user