feat: add support for ignoring PRs from specific users

This commit is contained in:
mrT23
2025-01-16 08:34:01 +02:00
parent 1997da3aac
commit 4923c8d810
5 changed files with 84 additions and 15 deletions

View File

@ -138,7 +138,17 @@ LANGSMITH_BASE_URL=<url>
## Ignoring automatic commands in PRs ## 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: 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"]`. 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: 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. 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. 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: 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' 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.

View File

@ -24,10 +24,6 @@ from pr_agent.identity_providers import get_identity_provider
from pr_agent.identity_providers.identity_provider import Eligibility from pr_agent.identity_providers.identity_provider import Eligibility
from pr_agent.log import LoggingFormat, get_logger, setup_logger from pr_agent.log import LoggingFormat, get_logger, setup_logger
from pr_agent.secret_providers import get_secret_provider 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") setup_logger(fmt=LoggingFormat.JSON, level="DEBUG")
router = APIRouter() router = APIRouter()
@ -75,6 +71,18 @@ async def handle_manifest(request: Request, response: Response):
return JSONResponse(manifest_obj) 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): async def _perform_commands_bitbucket(commands_conf: str, agent: PRAgent, api_url: str, log_context: dict, data: dict):
apply_repo_settings(api_url) 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 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", "") title = pr_data.get("title", "")
source_branch = pr_data.get("source", {}).get("branch", {}).get("name", "") source_branch = pr_data.get("source", {}).get("branch", {}).get("name", "")
target_branch = pr_data.get("destination", {}).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 # logic to ignore PRs with specific titles
if title: if title:
@ -167,16 +183,7 @@ async def handle_github_webhooks(background_tasks: BackgroundTasks, request: Req
return "OK" return "OK"
# Get the username of the sender # Get the username of the sender
actor = data.get("data", {}).get("actor", {}) log_context["sender"] = _get_username(data)
if actor:
try:
username = actor["username"]
except KeyError:
try:
username = actor["display_name"]
except KeyError:
username = actor["nickname"]
log_context["sender"] = username
sender_id = data.get("data", {}).get("actor", {}).get("account_id", "") sender_id = data.get("data", {}).get("actor", {}).get("account_id", "")
log_context["sender_id"] = sender_id log_context["sender_id"] = sender_id

View File

@ -257,6 +257,14 @@ def should_process_pr_logic(body) -> bool:
pr_labels = pull_request.get("labels", []) pr_labels = pull_request.get("labels", [])
source_branch = pull_request.get("head", {}).get("ref", "") source_branch = pull_request.get("head", {}).get("ref", "")
target_branch = pull_request.get("base", {}).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 # logic to ignore PRs with specific titles
if title: 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") get_logger().info(f"Ignoring PR with labels '{labels_str}' due to config.ignore_pr_labels settings")
return False 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_source_branches = get_settings().get("CONFIG.IGNORE_PR_SOURCE_BRANCHES", [])
ignore_pr_target_branches = get_settings().get("CONFIG.IGNORE_PR_TARGET_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): if pull_request and (ignore_pr_source_branches or ignore_pr_target_branches):

View File

@ -100,6 +100,14 @@ def should_process_pr_logic(data) -> bool:
if not data.get('object_attributes', {}): if not data.get('object_attributes', {}):
return False return False
title = data['object_attributes'].get('title') 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. # logic to ignore MRs for titles, labels and source, target branches.
ignore_mr_title = get_settings().get("CONFIG.IGNORE_PR_TITLE", []) ignore_mr_title = get_settings().get("CONFIG.IGNORE_PR_TITLE", [])

View File

@ -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_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_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_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 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 enable_ai_metadata = false # will enable adding ai metadata