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..09a138bf 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 +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) + 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 890cff35..ad4a68a0 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -326,3 +326,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))