Azure: handle inline /ask

This commit is contained in:
Thomas De Keulenaer
2025-05-09 12:13:42 +02:00
parent 67272700a6
commit 24a90cab8e
2 changed files with 33 additions and 1 deletions

View File

@ -21,7 +21,7 @@ try:
# noinspection PyUnresolvedReferences
from azure.devops.connection import Connection
# noinspection PyUnresolvedReferences
from azure.devops.released.git import (Comment, CommentThread, GitPullRequest, GitVersionDescriptor, GitClient)
from azure.devops.released.git import (Comment, CommentThread, GitPullRequest, GitVersionDescriptor, GitClient, CommentThreadContext)
# noinspection PyUnresolvedReferences
from azure.identity import DefaultAzureCredential
from msrest.authentication import BasicAuthentication
@ -564,6 +564,13 @@ class AzureDevopsProvider(GitProvider):
except Exception as e:
get_logger().exception(f"Failed to reply to thread, error: {e}")
def get_thread_context(self, thread_id: int) -> CommentThreadContext:
try:
thread = self.azure_devops_client.get_pull_request_thread(self.repo_slug, self.pr_num, thread_id, self.workspace_slug)
return thread.thread_context
except Exception as e:
get_logger().exception(f"Failed to set thread status, error: {e}")
@staticmethod
def _parse_pr_url(pr_url: str) -> Tuple[str, str, int]:
parsed_url = urlparse(pr_url)

View File

@ -23,6 +23,7 @@ from pr_agent.agent.pr_agent import PRAgent, command2class
from pr_agent.algo.utils import update_settings_from_args
from pr_agent.config_loader import get_settings
from pr_agent.git_providers import get_git_provider_with_context
from pr_agent.git_providers.azuredevops_provider import AzureDevopsProvider
from pr_agent.git_providers.utils import apply_repo_settings
from pr_agent.log import LoggingFormat, get_logger, setup_logger
@ -41,6 +42,7 @@ async def handle_request_comment(url: str, body: str, thread_id: int, comment_id
with get_logger().contextualize(**log_context):
agent = PRAgent()
provider = get_git_provider_with_context(pr_url=url)
body = handle_line_comment(body, thread_id, provider)
handled = await agent.handle_request(url, body, notify=lambda: provider.reply_to_thread(thread_id, "On it! ⏳", True))
# mark command comment as closed
if handled:
@ -49,6 +51,29 @@ async def handle_request_comment(url: str, body: str, thread_id: int, comment_id
except Exception as e:
get_logger().exception(f"Failed to handle webhook", artifact={"url": url, "body": body}, error=str(e))
def handle_line_comment(body: str, thread_id: int, provider: AzureDevopsProvider):
body = body.strip()
if not body.startswith('/ask '):
return body
thread_context = provider.get_thread_context(thread_id)
if not thread_context:
return body
path = thread_context.file_path
if thread_context.left_file_end or thread_context.left_file_start:
start_line = thread_context.left_file_start.line
end_line = thread_context.left_file_end.line
side = "left"
elif thread_context.right_file_end or thread_context.right_file_start:
start_line = thread_context.right_file_start.line
end_line = thread_context.right_file_end.line
side = "right"
else:
get_logger().info("No line range found in thread context", artifact={"thread_context": thread_context})
return body
question = body[5:].lstrip() # remove 4 chars: '/ask '
return f"/ask_line --line_start={start_line} --line_end={end_line} --side={side} --file_name={path} --comment_id={thread_id} {question}"
# currently only basic auth is supported with azure webhooks
# for this reason, https must be enabled to ensure the credentials are not sent in clear text