From 4923c8d810cb028407026b27c68e9c9566db0fe0 Mon Sep 17 00:00:00 2001 From: mrT23 Date: Thu, 16 Jan 2025 08:34:01 +0200 Subject: [PATCH] feat: add support for ignoring PRs from specific users --- .../usage-guide/additional_configurations.md | 46 ++++++++++++++++++- pr_agent/servers/bitbucket_app.py | 35 ++++++++------ pr_agent/servers/github_app.py | 9 ++++ pr_agent/servers/gitlab_webhook.py | 8 ++++ pr_agent/settings/configuration.toml | 1 + 5 files changed, 84 insertions(+), 15 deletions(-) diff --git a/docs/docs/usage-guide/additional_configurations.md b/docs/docs/usage-guide/additional_configurations.md index 72aa99b8c..d76cd34ce 100644 --- a/docs/docs/usage-guide/additional_configurations.md +++ b/docs/docs/usage-guide/additional_configurations.md @@ -138,7 +138,17 @@ LANGSMITH_BASE_URL= ## Ignoring automatic commands in PRs -In some cases, you may want to automatically ignore specific PRs . Qodo Merge enables you to ignore PR with a specific title, or from/to specific branches (regex matching). +Qodo Merge allows you to automatically ignore certain PRs based on various criteria: + +- PRs with specific titles (using regex matching) +- PRs between specific branches (using regex matching) +- PRs that don't include changes from specific folders (using regex matching) +- PRs containing specific labels +- PRs opened by specific users + +### Example usage + +#### Ignoring PRs with specific titles To ignore PRs with a specific title such as "[Bump]: ...", you can add the following to your `configuration.toml` file: @@ -149,6 +159,7 @@ ignore_pr_title = ["\\[Bump\\]"] Where the `ignore_pr_title` is a list of regex patterns to match the PR title you want to ignore. Default is `ignore_pr_title = ["^\\[Auto\\]", "^Auto"]`. +#### Ignoring PRs between specific branches To ignore PRs from specific source or target branches, you can add the following to your `configuration.toml` file: @@ -161,6 +172,7 @@ ignore_pr_target_branches = ["qa"] Where the `ignore_pr_source_branches` and `ignore_pr_target_branches` are lists of regex patterns to match the source and target branches you want to ignore. They are not mutually exclusive, you can use them together or separately. +#### Ignoring PRs that don't include changes from specific folders To allow only specific folders (often needed in large monorepos), set: @@ -170,3 +182,35 @@ allow_only_specific_folders=['folder1','folder2'] ``` For the configuration above, automatic feedback will only be triggered when the PR changes include files from 'folder1' or 'folder2' + +#### Ignoring PRs containg specific labels + +To ignore PRs containg specific labels, you can add the following to your `configuration.toml` file: + +``` +[config] +ignore_pr_labels = ["do-not-merge"] +``` + +Where the `ignore_pr_labels` is a list of labels that when present in the PR, the PR will be ignored. + +#### Ignoring PRs from specific users + +Qodo Merge automatically identifies and ignores pull requests created by bots using: + +- GitHub's native bot detection system +- Name-based pattern matching + +While this detection is robust, it may not catch all cases, particularly when: + +- Bots are registered as regular user accounts +- Bot names don't match common patterns + +To supplement the automatic bot detection, you can manually specify users to ignore. Add the following to your `configuration.toml` file to ignore PRs from specific users: +``` +[config] +ignore_pr_authors = ["my-special-bot-user", ...] +``` + +Where the `ignore_pr_authors` is a list of usernames that you want to ignore. + diff --git a/pr_agent/servers/bitbucket_app.py b/pr_agent/servers/bitbucket_app.py index 2175db27d..5d93f1676 100644 --- a/pr_agent/servers/bitbucket_app.py +++ b/pr_agent/servers/bitbucket_app.py @@ -24,10 +24,6 @@ from pr_agent.identity_providers.identity_provider import Eligibility from pr_agent.log import LoggingFormat, get_logger, setup_logger from pr_agent.secret_providers import get_secret_provider -from pr_agent.servers.github_action_runner import get_setting_or_env, is_true -from pr_agent.tools.pr_code_suggestions import PRCodeSuggestions -from pr_agent.tools.pr_description import PRDescription -from pr_agent.tools.pr_reviewer import PRReviewer setup_logger(fmt=LoggingFormat.JSON, level="DEBUG") router = APIRouter() @@ -75,6 +71,18 @@ async def handle_manifest(request: Request, response: Response): return JSONResponse(manifest_obj) +def _get_username(data): + actor = data.get("data", {}).get("actor", {}) + if actor: + if "username" in actor: + return actor["username"] + elif "display_name" in actor: + return actor["display_name"] + elif "nickname" in actor: + return actor["nickname"] + return "" + + async def _perform_commands_bitbucket(commands_conf: str, agent: PRAgent, api_url: str, log_context: dict, data: dict): apply_repo_settings(api_url) if commands_conf == "pr_commands" and get_settings().config.disable_auto_feedback: # auto commands for PR, and auto feedback is disabled @@ -118,6 +126,14 @@ def should_process_pr_logic(data) -> bool: title = pr_data.get("title", "") source_branch = pr_data.get("source", {}).get("branch", {}).get("name", "") target_branch = pr_data.get("destination", {}).get("branch", {}).get("name", "") + sender = _get_username(data) + + # logic 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 # logic to ignore PRs with specific titles if title: @@ -167,16 +183,7 @@ async def inner(): return "OK" # Get the username of the sender - actor = data.get("data", {}).get("actor", {}) - if actor: - try: - username = actor["username"] - except KeyError: - try: - username = actor["display_name"] - except KeyError: - username = actor["nickname"] - log_context["sender"] = username + log_context["sender"] = _get_username(data) sender_id = data.get("data", {}).get("actor", {}).get("account_id", "") log_context["sender_id"] = sender_id diff --git a/pr_agent/servers/github_app.py b/pr_agent/servers/github_app.py index 6191862d1..9c9708fb3 100644 --- a/pr_agent/servers/github_app.py +++ b/pr_agent/servers/github_app.py @@ -257,6 +257,14 @@ def should_process_pr_logic(body) -> bool: pr_labels = pull_request.get("labels", []) source_branch = pull_request.get("head", {}).get("ref", "") target_branch = pull_request.get("base", {}).get("ref", "") + sender = body.get("sender", {}).get("login") + + # logic 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 # logic to ignore PRs with specific titles if title: @@ -276,6 +284,7 @@ def should_process_pr_logic(body) -> bool: get_logger().info(f"Ignoring PR with labels '{labels_str}' due to config.ignore_pr_labels settings") return False + # logic to ignore PRs with specific source or target branches 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 pull_request and (ignore_pr_source_branches or ignore_pr_target_branches): diff --git a/pr_agent/servers/gitlab_webhook.py b/pr_agent/servers/gitlab_webhook.py index 2cba7ac5e..6a3d6bcbd 100644 --- a/pr_agent/servers/gitlab_webhook.py +++ b/pr_agent/servers/gitlab_webhook.py @@ -100,6 +100,14 @@ def should_process_pr_logic(data) -> bool: if not data.get('object_attributes', {}): return False title = data['object_attributes'].get('title') + sender = data.get("user", {}).get("username", "") + + # logic 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' settings") + return False # logic to ignore MRs for titles, labels and source, target branches. ignore_mr_title = get_settings().get("CONFIG.IGNORE_PR_TITLE", []) diff --git a/pr_agent/settings/configuration.toml b/pr_agent/settings/configuration.toml index 29cd90e7d..681570d02 100644 --- a/pr_agent/settings/configuration.toml +++ b/pr_agent/settings/configuration.toml @@ -43,6 +43,7 @@ ignore_pr_title = ["^\\[Auto\\]", "^Auto"] # a list of regular expressions to ma ignore_pr_target_branches = [] # a list of regular expressions of target branches to ignore from PR agent when an PR is created ignore_pr_source_branches = [] # a list of regular expressions of source branches to ignore from PR agent when an PR is created ignore_pr_labels = [] # labels to ignore from PR agent when an PR is created +ignore_pr_authors = [] # authors to ignore from PR agent when an PR is created # is_auto_command = false # will be auto-set to true if the command is triggered by an automation enable_ai_metadata = false # will enable adding ai metadata