Merge pull request #1786 from qodo-ai/pr-1736

Pr 1736
This commit is contained in:
Tal
2025-05-17 15:29:23 +03:00
committed by GitHub
6 changed files with 119 additions and 2 deletions

View File

@ -164,6 +164,7 @@ Qodo Merge allows you to automatically ignore certain PRs based on various crite
- PRs with specific titles (using regex matching) - PRs with specific titles (using regex matching)
- PRs between specific branches (using regex matching) - PRs between specific branches (using regex matching)
- PRs from specific repositories (using regex matching)
- PRs not from specific folders - PRs not from specific folders
- PRs containing specific labels - PRs containing specific labels
- PRs opened by specific users - PRs opened by specific users
@ -172,7 +173,7 @@ Qodo Merge allows you to automatically ignore certain PRs based on various crite
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:
``` ```toml
[config] [config]
ignore_pr_title = ["\\[Bump\\]"] ignore_pr_title = ["\\[Bump\\]"]
``` ```
@ -183,7 +184,7 @@ Where the `ignore_pr_title` is a list of regex patterns to match the PR title yo
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:
``` ```toml
[config] [config]
ignore_pr_source_branches = ['develop', 'main', 'master', 'stage'] ignore_pr_source_branches = ['develop', 'main', 'master', 'stage']
ignore_pr_target_branches = ["qa"] ignore_pr_target_branches = ["qa"]
@ -192,6 +193,18 @@ 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 from specific repositories
To ignore PRs from specific repositories, you can add the following to your `configuration.toml` file:
```toml
[config]
ignore_repositories = ["my-org/my-repo1", "my-org/my-repo2"]
```
Where the `ignore_repositories` is a list of regex patterns to match the repositories you want to ignore. This is useful when you have multiple repositories and want to exclude certain ones from analysis.
### Ignoring PRs not from specific folders ### Ignoring PRs not 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:

View File

@ -127,6 +127,14 @@ def should_process_pr_logic(data) -> bool:
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) sender = _get_username(data)
repo_full_name = pr_data.get("destination", {}).get("repository", {}).get("full_name", "")
# logic 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
# logic to ignore PRs from specific users # logic to ignore PRs from specific users
ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", []) ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", [])

View File

@ -258,6 +258,14 @@ def should_process_pr_logic(body) -> bool:
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") sender = body.get("sender", {}).get("login")
repo_full_name = body.get("repository", {}).get("full_name", "")
# logic to ignore PRs from specific repositories
ignore_repos = get_settings().get("CONFIG.IGNORE_REPOSITORIES", [])
if ignore_repos and repo_full_name:
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
# logic to ignore PRs from specific users # logic to ignore PRs from specific users
ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", []) ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", [])

View File

@ -113,6 +113,14 @@ def should_process_pr_logic(data) -> bool:
return False return False
title = data['object_attributes'].get('title') title = data['object_attributes'].get('title')
sender = data.get("user", {}).get("username", "") sender = data.get("user", {}).get("username", "")
repo_full_name = data.get('project', {}).get('path_with_namespace', "")
# logic to ignore PRs from specific repositories
ignore_repos = get_settings().get("CONFIG.IGNORE_REPOSITORIES", [])
if ignore_repos and repo_full_name:
if any(re.search(regex, repo_full_name) for regex in ignore_repos):
get_logger().info(f"Ignoring MR from repository '{repo_full_name}' due to 'config.ignore_repositories' setting")
return False
# logic to ignore PRs from specific users # logic to ignore PRs from specific users
ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", []) ignore_pr_users = get_settings().get("CONFIG.IGNORE_PR_AUTHORS", [])

View File

@ -55,6 +55,7 @@ ignore_pr_target_branches = [] # a list of regular expressions of target branche
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 ignore_pr_authors = [] # authors to ignore from PR agent when an PR is created
ignore_repositories = [] # a list of regular expressions of repository full names (e.g. "org/repo") to ignore from PR agent processing
# #
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

View File

@ -0,0 +1,79 @@
import pytest
from pr_agent.servers.github_app import should_process_pr_logic as github_should_process_pr_logic
from pr_agent.servers.bitbucket_app import should_process_pr_logic as bitbucket_should_process_pr_logic
from pr_agent.servers.gitlab_webhook import should_process_pr_logic as gitlab_should_process_pr_logic
from pr_agent.config_loader import get_settings
def make_bitbucket_payload(full_name):
return {
"data": {
"pullrequest": {
"title": "Test PR",
"source": {"branch": {"name": "feature/test"}},
"destination": {
"branch": {"name": "main"},
"repository": {"full_name": full_name}
}
},
"actor": {"username": "user", "type": "user"}
}
}
def make_github_body(full_name):
return {
"pull_request": {},
"repository": {"full_name": full_name},
"sender": {"login": "user"}
}
def make_gitlab_body(full_name):
return {
"object_attributes": {"title": "Test MR"},
"project": {"path_with_namespace": full_name}
}
PROVIDERS = [
("github", github_should_process_pr_logic, make_github_body),
("bitbucket", bitbucket_should_process_pr_logic, make_bitbucket_payload),
("gitlab", gitlab_should_process_pr_logic, make_gitlab_body),
]
class TestIgnoreRepositories:
def setup_method(self):
get_settings().set("CONFIG.IGNORE_REPOSITORIES", [])
@pytest.mark.parametrize("provider_name, provider_func, body_func", PROVIDERS)
def test_should_ignore_matching_repository(self, provider_name, provider_func, body_func):
get_settings().set("CONFIG.IGNORE_REPOSITORIES", ["org/repo-to-ignore"])
body = {
"pull_request": {},
"repository": {"full_name": "org/repo-to-ignore"},
"sender": {"login": "user"}
}
result = provider_func(body_func(body["repository"]["full_name"]))
# print(f"DEBUG: Provider={provider_name}, test_should_ignore_matching_repository, result={result}")
assert result is False, f"{provider_name}: PR from ignored repository should be ignored (return False)"
@pytest.mark.parametrize("provider_name, provider_func, body_func", PROVIDERS)
def test_should_not_ignore_non_matching_repository(self, provider_name, provider_func, body_func):
get_settings().set("CONFIG.IGNORE_REPOSITORIES", ["org/repo-to-ignore"])
body = {
"pull_request": {},
"repository": {"full_name": "org/other-repo"},
"sender": {"login": "user"}
}
result = provider_func(body_func(body["repository"]["full_name"]))
# print(f"DEBUG: Provider={provider_name}, test_should_not_ignore_non_matching_repository, result={result}")
assert result is True, f"{provider_name}: PR from non-ignored repository should not be ignored (return True)"
@pytest.mark.parametrize("provider_name, provider_func, body_func", PROVIDERS)
def test_should_not_ignore_when_config_empty(self, provider_name, provider_func, body_func):
get_settings().set("CONFIG.IGNORE_REPOSITORIES", [])
body = {
"pull_request": {},
"repository": {"full_name": "org/repo-to-ignore"},
"sender": {"login": "user"}
}
result = provider_func(body_func(body["repository"]["full_name"]))
# print(f"DEBUG: Provider={provider_name}, test_should_not_ignore_when_config_empty, result={result}")
assert result is True, f"{provider_name}: PR should not be ignored if ignore_repositories config is empty"