From 5a56d11e16bffd8e223e3a035517e54d70e2b82c Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 16:37:58 +0530 Subject: [PATCH 01/11] fix: Add ignore logic for Bitbucket Server webhook --- pr_agent/servers/bitbucket_server_webhook.py | 52 ++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 873e931f..f4dbdb46 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -40,6 +40,53 @@ def handle_request( background_tasks.add_task(inner) +def should_process_pr_logic(data) -> bool: + try: + pr_data = data.get("pullRequest", {}) + title = pr_data.get("title", "") + source_branch = pr_data.get("fromRef", {}).get("displayId", "") + target_branch = pr_data.get("toRef", {}).get("displayId", "") + sender = pr_data.get("author", {}).get("user", {}).get("name", "") + repo_full_name = pr_data.get("toRef", {}).get("repository", {}).get("project", {}).get("key", "") + "/" + pr_data.get("toRef", {}).get("repository", {}).get("slug", "") + + # To ignore PRs from specific repositories + ignore_repos = get_settings().get("CONFIG.IGNORE_REPOSITORIES", []) + if repo_full_name and ignore_repos: + if any(re.search(regex, repo_full_name) for regex in ignore_repos): + get_logger().info(f"Ignoring PR from repository '{repo_full_name}' due to 'config.ignore_repositories' setting") + return False + + # To ignore PRs from specific users + ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", []) + if ignore_pr_users and sender: + if sender in ignore_pr_users: + get_logger().info(f"Ignoring PR from user '{sender}' due to 'config.ignore_pr_authors' setting") + return False + + # To ignore PRs with specific titles + if title: + ignore_pr_title_re = get_settings().get("CONFIG.IGNORE_PR_TITLE", []) + if not isinstance(ignore_pr_title_re, list): + ignore_pr_title_re = [ignore_pr_title_re] + if ignore_pr_title_re and any(re.search(regex, title) for regex in ignore_pr_title_re): + get_logger().info(f"Ignoring PR with title '{title}' due to config.ignore_pr_title setting") + return False + + ignore_pr_source_branches = get_settings().get("CONFIG.IGNORE_PR_SOURCE_BRANCHES", []) + ignore_pr_target_branches = get_settings().get("CONFIG.IGNORE_PR_TARGET_BRANCHES", []) + if (ignore_pr_source_branches or ignore_pr_target_branches): + if any(re.search(regex, source_branch) for regex in ignore_pr_source_branches): + get_logger().info( + f"Ignoring PR with source branch '{source_branch}' due to config.ignore_pr_source_branches settings") + return False + if any(re.search(regex, target_branch) for regex in ignore_pr_target_branches): + get_logger().info( + f"Ignoring PR with target branch '{target_branch}' due to config.ignore_pr_target_branches settings") + return False + except Exception as e: + get_logger().error(f"Failed 'should_process_pr_logic': {e}") + return True + @router.post("/") async def redirect_to_webhook(): return RedirectResponse(url="/webhook") @@ -73,6 +120,11 @@ async def handle_webhook(background_tasks: BackgroundTasks, request: Request): if data["eventKey"] == "pr:opened": apply_repo_settings(pr_url) + if not should_process_pr_logic(data): + get_logger().info(f"PR ignored due to config settings", **log_context) + return JSONResponse( + status_code=status.HTTP_200_OK, content=jsonable_encoder({"message": "PR ignored by config"}) + ) if get_settings().config.disable_auto_feedback: # auto commands for PR, and auto feedback is disabled get_logger().info(f"Auto feedback is disabled, skipping auto commands for PR {pr_url}", **log_context) return From 50c2578cfd18adbbc0edf70d36f87e7b3ea3aa73 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 16:42:29 +0530 Subject: [PATCH 02/11] fix: comments --- pr_agent/servers/bitbucket_server_webhook.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index f4dbdb46..9e4819bd 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -47,7 +47,9 @@ def should_process_pr_logic(data) -> bool: source_branch = pr_data.get("fromRef", {}).get("displayId", "") target_branch = pr_data.get("toRef", {}).get("displayId", "") sender = pr_data.get("author", {}).get("user", {}).get("name", "") - repo_full_name = pr_data.get("toRef", {}).get("repository", {}).get("project", {}).get("key", "") + "/" + pr_data.get("toRef", {}).get("repository", {}).get("slug", "") + project_key = pr_data.get("toRef", {}).get("repository", {}).get("project", {}).get("key", "") + repo_slug = pr_data.get("toRef", {}).get("repository", {}).get("slug", "") + repo_full_name = f"{project_key}/{repo_slug}" if project_key and repo_slug else "" # To ignore PRs from specific repositories ignore_repos = get_settings().get("CONFIG.IGNORE_REPOSITORIES", []) From e7268dd3147af0eb948aa76ed35acb40c1860736 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 16:45:42 +0530 Subject: [PATCH 03/11] fix: error handling in PR processing logic --- pr_agent/servers/bitbucket_server_webhook.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 9e4819bd..d3237029 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -1,6 +1,7 @@ import ast import json import os +import re from typing import List import uvicorn @@ -87,6 +88,7 @@ def should_process_pr_logic(data) -> bool: return False except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") + return False return True @router.post("/") From 1713cded21d5b3b156caa095f0d9bc298eb6d3d4 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 23:36:16 +0530 Subject: [PATCH 04/11] chore: allow_only_specific_folders logic in PR processing --- pr_agent/servers/bitbucket_server_webhook.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index d3237029..32dae1ee 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -51,6 +51,7 @@ def should_process_pr_logic(data) -> bool: project_key = pr_data.get("toRef", {}).get("repository", {}).get("project", {}).get("key", "") repo_slug = pr_data.get("toRef", {}).get("repository", {}).get("slug", "") repo_full_name = f"{project_key}/{repo_slug}" if project_key and repo_slug else "" + pr_id = pr_data.get("id", None) # To ignore PRs from specific repositories ignore_repos = get_settings().get("CONFIG.IGNORE_REPOSITORIES", []) @@ -86,6 +87,24 @@ def should_process_pr_logic(data) -> bool: get_logger().info( f"Ignoring PR with target branch '{target_branch}' due to config.ignore_pr_target_branches settings") return False + + # --- allow_only_specific_folders logic --- + allowed_folders = get_settings().config.get("allow_only_specific_folders", []) + if allowed_folders and pr_id and project_key and repo_slug: + try: + from pr_agent.git_providers.bitbucket_server_provider import BitbucketServerProvider + bitbucket_server_url = get_settings().get("BITBUCKET_SERVER.URL", "") + pr_url = f"{bitbucket_server_url}/projects/{project_key}/repos/{repo_slug}/pull-requests/{pr_id}" + provider = BitbucketServerProvider(pr_url=pr_url) + changed_files = provider.get_files() + if changed_files: + for file_path in changed_files: + if not any(file_path.startswith(folder) for folder in allowed_folders): + get_logger().info(f"Ignoring PR because file '{file_path}' is not in allowed folders {allowed_folders}") + return False + except Exception as e: + get_logger().error(f"Failed allow_only_specific_folders logic: {e}") + return False except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") return False From 0742d8052fe2581d3160278eb6366b1e605b2384 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 23:39:34 +0530 Subject: [PATCH 05/11] refactor: update comment for allow_only_specific_folders logic in PR processing --- pr_agent/servers/bitbucket_server_webhook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 32dae1ee..7992249e 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -88,7 +88,7 @@ def should_process_pr_logic(data) -> bool: f"Ignoring PR with target branch '{target_branch}' due to config.ignore_pr_target_branches settings") return False - # --- allow_only_specific_folders logic --- + # allow_only_specific_folders allowed_folders = get_settings().config.get("allow_only_specific_folders", []) if allowed_folders and pr_id and project_key and repo_slug: try: From 598e2c731b2905c4c245f58be81d4e1f292537f1 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 23:44:02 +0530 Subject: [PATCH 06/11] refactor: enhance allow_only_specific_folders logic to check if all changed files are outside allowed folders --- pr_agent/servers/bitbucket_server_webhook.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 7992249e..c3884122 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -88,7 +88,7 @@ def should_process_pr_logic(data) -> bool: f"Ignoring PR with target branch '{target_branch}' due to config.ignore_pr_target_branches settings") return False - # allow_only_specific_folders + # Allow_only_specific_folders allowed_folders = get_settings().config.get("allow_only_specific_folders", []) if allowed_folders and pr_id and project_key and repo_slug: try: @@ -98,13 +98,19 @@ def should_process_pr_logic(data) -> bool: provider = BitbucketServerProvider(pr_url=pr_url) changed_files = provider.get_files() if changed_files: + # Check if ALL files are outside allowed folders + all_files_outside = True for file_path in changed_files: - if not any(file_path.startswith(folder) for folder in allowed_folders): - get_logger().info(f"Ignoring PR because file '{file_path}' is not in allowed folders {allowed_folders}") - return False + if any(file_path.startswith(folder) for folder in allowed_folders): + all_files_outside = False + break + + if all_files_outside: + get_logger().info(f"Ignoring PR because all files {changed_files} are outside allowed folders {allowed_folders}") + return False except Exception as e: get_logger().error(f"Failed allow_only_specific_folders logic: {e}") - return False + pass except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") return False From 6057812a20b8550ea314fd3539860fc39f3eccdb Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 23:52:02 +0530 Subject: [PATCH 07/11] refactor: improve pull request data extraction and error handling in should_process_pr_logic --- pr_agent/servers/bitbucket_server_webhook.py | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index c3884122..ead4ea4e 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -45,11 +45,22 @@ def should_process_pr_logic(data) -> bool: try: pr_data = data.get("pullRequest", {}) title = pr_data.get("title", "") - source_branch = pr_data.get("fromRef", {}).get("displayId", "") - target_branch = pr_data.get("toRef", {}).get("displayId", "") - sender = pr_data.get("author", {}).get("user", {}).get("name", "") - project_key = pr_data.get("toRef", {}).get("repository", {}).get("project", {}).get("key", "") - repo_slug = pr_data.get("toRef", {}).get("repository", {}).get("slug", "") + + from_ref = pr_data.get("fromRef", {}) + source_branch = from_ref.get("displayId", "") if from_ref else "" + + to_ref = pr_data.get("toRef", {}) + target_branch = to_ref.get("displayId", "") if to_ref else "" + + author = pr_data.get("author", {}) + user = author.get("user", {}) if author else {} + sender = user.get("name", "") if user else "" + + repository = to_ref.get("repository", {}) if to_ref else {} + project = repository.get("project", {}) if repository else {} + project_key = project.get("key", "") if project else "" + repo_slug = repository.get("slug", "") if repository else "" + repo_full_name = f"{project_key}/{repo_slug}" if project_key and repo_slug else "" pr_id = pr_data.get("id", None) @@ -63,7 +74,7 @@ def should_process_pr_logic(data) -> bool: # To ignore PRs from specific users ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", []) if ignore_pr_users and sender: - if sender in ignore_pr_users: + if any(re.search(regex, sender) for regex in ignore_pr_users): get_logger().info(f"Ignoring PR from user '{sender}' due to 'config.ignore_pr_authors' setting") return False @@ -110,7 +121,7 @@ def should_process_pr_logic(data) -> bool: return False except Exception as e: get_logger().error(f"Failed allow_only_specific_folders logic: {e}") - pass + return True except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") return False From 4ab97d89694973230f489ef167bfd2897c9cd78d Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Wed, 9 Jul 2025 23:59:07 +0530 Subject: [PATCH 08/11] fix: correct error handling in should_process_pr_logic to prevent processing on failure --- pr_agent/servers/bitbucket_server_webhook.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index ead4ea4e..8748dd30 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -121,7 +121,7 @@ def should_process_pr_logic(data) -> bool: return False except Exception as e: get_logger().error(f"Failed allow_only_specific_folders logic: {e}") - return True + return False except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") return False From efdb0f57449d81769d6b7bbfe4100c472a800feb Mon Sep 17 00:00:00 2001 From: Tal Date: Sat, 12 Jul 2025 20:07:51 +0300 Subject: [PATCH 09/11] Update pr_agent/servers/bitbucket_server_webhook.py Co-authored-by: qodo-merge-for-open-source[bot] <189517486+qodo-merge-for-open-source[bot]@users.noreply.github.com> --- pr_agent/servers/bitbucket_server_webhook.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 8748dd30..9d38f18c 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -121,7 +121,8 @@ def should_process_pr_logic(data) -> bool: return False except Exception as e: get_logger().error(f"Failed allow_only_specific_folders logic: {e}") - return False + # Continue processing PR when folder check fails + pass except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") return False From 4a8e9b79e86e51e5bcd0e9906a69e109383465a8 Mon Sep 17 00:00:00 2001 From: Abhinav Kumar <113254225+abhinav-1305@users.noreply.github.com> Date: Sat, 12 Jul 2025 22:39:18 +0530 Subject: [PATCH 10/11] Update pr_agent/servers/bitbucket_server_webhook.py Co-authored-by: qodo-merge-for-open-source[bot] <189517486+qodo-merge-for-open-source[bot]@users.noreply.github.com> --- pr_agent/servers/bitbucket_server_webhook.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 9d38f18c..56763e98 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -119,13 +119,9 @@ def should_process_pr_logic(data) -> bool: if all_files_outside: get_logger().info(f"Ignoring PR because all files {changed_files} are outside allowed folders {allowed_folders}") return False - except Exception as e: - get_logger().error(f"Failed allow_only_specific_folders logic: {e}") - # Continue processing PR when folder check fails - pass except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") - return False + return True return True @router.post("/") From 71bbc52a998e70615a2c3201753f9553f278e441 Mon Sep 17 00:00:00 2001 From: Tal Date: Sat, 12 Jul 2025 20:13:45 +0300 Subject: [PATCH 11/11] Update bitbucket_server_webhook.py --- pr_agent/servers/bitbucket_server_webhook.py | 35 ++++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/pr_agent/servers/bitbucket_server_webhook.py b/pr_agent/servers/bitbucket_server_webhook.py index 56763e98..a38644f0 100644 --- a/pr_agent/servers/bitbucket_server_webhook.py +++ b/pr_agent/servers/bitbucket_server_webhook.py @@ -102,26 +102,25 @@ def should_process_pr_logic(data) -> bool: # Allow_only_specific_folders allowed_folders = get_settings().config.get("allow_only_specific_folders", []) if allowed_folders and pr_id and project_key and repo_slug: - try: - from pr_agent.git_providers.bitbucket_server_provider import BitbucketServerProvider - bitbucket_server_url = get_settings().get("BITBUCKET_SERVER.URL", "") - pr_url = f"{bitbucket_server_url}/projects/{project_key}/repos/{repo_slug}/pull-requests/{pr_id}" - provider = BitbucketServerProvider(pr_url=pr_url) - changed_files = provider.get_files() - if changed_files: - # Check if ALL files are outside allowed folders - all_files_outside = True - for file_path in changed_files: - if any(file_path.startswith(folder) for folder in allowed_folders): - all_files_outside = False - break - - if all_files_outside: - get_logger().info(f"Ignoring PR because all files {changed_files} are outside allowed folders {allowed_folders}") - return False + from pr_agent.git_providers.bitbucket_server_provider import BitbucketServerProvider + bitbucket_server_url = get_settings().get("BITBUCKET_SERVER.URL", "") + pr_url = f"{bitbucket_server_url}/projects/{project_key}/repos/{repo_slug}/pull-requests/{pr_id}" + provider = BitbucketServerProvider(pr_url=pr_url) + changed_files = provider.get_files() + if changed_files: + # Check if ALL files are outside allowed folders + all_files_outside = True + for file_path in changed_files: + if any(file_path.startswith(folder) for folder in allowed_folders): + all_files_outside = False + break + + if all_files_outside: + get_logger().info(f"Ignoring PR because all files {changed_files} are outside allowed folders {allowed_folders}") + return False except Exception as e: get_logger().error(f"Failed 'should_process_pr_logic': {e}") - return True + return True # On exception - we continue. Otherwise, we could just end up with filtering all PRs return True @router.post("/")