diff --git a/pr_agent/algo/utils.py b/pr_agent/algo/utils.py
index 63af5635..d883d4ef 100644
--- a/pr_agent/algo/utils.py
+++ b/pr_agent/algo/utils.py
@@ -250,7 +250,7 @@ def convert_to_markdown_v2(output_data: dict,
if gfm_supported:
if reference_link is not None and len(reference_link) > 0:
if relevant_lines_str:
- issue_str = f"{issue_header}\n\n{issue_content}
\n\n{relevant_lines_str}\n\n "
+ issue_str = f"{issue_header}\n\n{issue_content}\n
\n\n{relevant_lines_str}\n\n "
else:
issue_str = f"{issue_header}
{issue_content}"
else:
diff --git a/pr_agent/git_providers/azuredevops_provider.py b/pr_agent/git_providers/azuredevops_provider.py
index eb362af3..e305d7c2 100644
--- a/pr_agent/git_providers/azuredevops_provider.py
+++ b/pr_agent/git_providers/azuredevops_provider.py
@@ -183,6 +183,7 @@ class AzureDevopsProvider(GitProvider):
return True
def set_pr(self, pr_url: str):
+ self.pr_url = pr_url
self.workspace_slug, self.repo_slug, self.pr_num = self._parse_pr_url(pr_url)
self.pr = self._get_pr()
@@ -614,8 +615,11 @@ class AzureDevopsProvider(GitProvider):
return pr_id
except Exception as e:
if get_settings().config.verbosity_level >= 2:
- get_logger().error(f"Failed to get pr id, error: {e}")
+ get_logger().info(f"Failed to get pr id, error: {e}")
return ""
def publish_file_comments(self, file_comments: list) -> bool:
pass
+
+ def get_line_link(self, relevant_file: str, relevant_line_start: int, relevant_line_end: int = None) -> str:
+ return self.pr_url+f"?_a=files&path={relevant_file}"
diff --git a/pr_agent/servers/azuredevops_server_webhook.py b/pr_agent/servers/azuredevops_server_webhook.py
index 96e4060a..ce6e050b 100644
--- a/pr_agent/servers/azuredevops_server_webhook.py
+++ b/pr_agent/servers/azuredevops_server_webhook.py
@@ -33,20 +33,16 @@ azure_devops_server = get_settings().get("azure_devops_server")
WEBHOOK_USERNAME = azure_devops_server.get("webhook_username")
WEBHOOK_PASSWORD = azure_devops_server.get("webhook_password")
-def handle_request(
- background_tasks: BackgroundTasks, url: str, body: str, log_context: dict
+async def handle_request_comment( url: str, body: str, log_context: dict
):
log_context["action"] = body
log_context["api_url"] = url
- async def inner():
- try:
- with get_logger().contextualize(**log_context):
- await PRAgent().handle_request(url, body)
- except Exception as e:
- get_logger().error(f"Failed to handle webhook: {e}")
-
- background_tasks.add_task(inner)
+ try:
+ with get_logger().contextualize(**log_context):
+ await PRAgent().handle_request(url, body)
+ except Exception as e:
+ get_logger().exception(f"Failed to handle webhook", artifact={"url": url, "body": body}, error=str(e))
# currently only basic auth is supported with azure webhooks
@@ -68,6 +64,9 @@ async def _perform_commands_azure(commands_conf: str, agent: PRAgent, api_url: s
get_logger().info(f"Auto feedback is disabled, skipping auto commands for PR {api_url=}", **log_context)
return
commands = get_settings().get(f"azure_devops_server.{commands_conf}")
+ if not commands:
+ return
+
get_settings().set("config.is_auto_command", True)
for command in commands:
try:
@@ -83,12 +82,7 @@ async def _perform_commands_azure(commands_conf: str, agent: PRAgent, api_url: s
get_logger().error(f"Failed to perform command {command}: {e}")
-@router.post("/", dependencies=[Depends(authorize)])
-async def handle_webhook(background_tasks: BackgroundTasks, request: Request):
- log_context = {"server_type": "azure_devops_server"}
- data = await request.json()
- get_logger().info(json.dumps(data))
-
+async def handle_request_azure(data, log_context):
actions = []
if data["eventType"] == "git.pullrequest.created":
# API V1 (latest)
@@ -96,7 +90,10 @@ async def handle_webhook(background_tasks: BackgroundTasks, request: Request):
log_context["event"] = data["eventType"]
log_context["api_url"] = pr_url
await _perform_commands_azure("pr_commands", PRAgent(), pr_url, log_context)
- return
+ return JSONResponse(
+ status_code=status.HTTP_202_ACCEPTED,
+ content=jsonable_encoder({"message": "webhook triggered successfully"})
+ )
elif data["eventType"] == "ms.vss-code.git-pullrequest-comment-event" and "content" in data["resource"]["comment"]:
if available_commands_rgx.match(data["resource"]["comment"]["content"]):
if(data["resourceVersion"] == "2.0"):
@@ -124,7 +121,7 @@ async def handle_webhook(background_tasks: BackgroundTasks, request: Request):
for action in actions:
try:
- handle_request(background_tasks, pr_url, action, log_context)
+ await handle_request_comment(pr_url, action, log_context)
except Exception as e:
get_logger().error("Azure DevOps Trigger failed. Error:" + str(e))
return JSONResponse(
@@ -135,6 +132,18 @@ async def handle_webhook(background_tasks: BackgroundTasks, request: Request):
status_code=status.HTTP_202_ACCEPTED, content=jsonable_encoder({"message": "webhook triggered successfully"})
)
+@router.post("/", dependencies=[Depends(authorize)])
+async def handle_webhook(background_tasks: BackgroundTasks, request: Request):
+ log_context = {"server_type": "azure_devops_server"}
+ data = await request.json()
+ # get_logger().info(json.dumps(data))
+
+ background_tasks.add_task(handle_request_azure, data, log_context)
+
+ return JSONResponse(
+ status_code=status.HTTP_202_ACCEPTED, content=jsonable_encoder({"message": "webhook triggered successfully"})
+ )
+
@router.get("/")
async def root():
return {"status": "ok"}
diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml
index 5552584a..b9a8e15c 100644
--- a/pr_agent/settings/configuration.toml
+++ b/pr_agent/settings/configuration.toml
@@ -327,3 +327,11 @@ utilize_auto_best_practices = true # public - disable usage of auto best practic
extra_instructions = "" # public - extra instructions to the auto best practices generation prompt
content = ""
max_patterns = 5 # max number of patterns to be detected
+
+
+[azure_devops_server]
+pr_commands = [
+ "/describe",
+ "/review",
+ "/improve",
+]
\ No newline at end of file
diff --git a/pr_agent/tools/pr_description.py b/pr_agent/tools/pr_description.py
index 709d6f22..fc3eca33 100644
--- a/pr_agent/tools/pr_description.py
+++ b/pr_agent/tools/pr_description.py
@@ -683,8 +683,9 @@ class PRDescription:
filename = filename.strip()
link = self.git_provider.get_line_link(filename, relevant_line_start=-1)
if (not link or not diff_plus_minus) and ('additional files' not in filename.lower()):
- get_logger().warning(f"Error getting line link for '{filename}'")
- continue
+ # get_logger().warning(f"Error getting line link for '{filename}'")
+ link = ""
+ # continue
# Add file data to the PR body
file_change_description_br = insert_br_after_x_chars(file_change_description, x=(delta - 5))