mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 04:40:38 +08:00
Compare commits
2 Commits
v0.27
...
hl/jira_se
Author | SHA1 | Date | |
---|---|---|---|
5cc9dcf72a | |||
a87dd37f66 |
@ -120,9 +120,44 @@ jira_api_email = "YOUR_EMAIL"
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
#### Jira Server/Data Center 💎
|
#### Jira Data Center/Server 💎
|
||||||
|
|
||||||
Currently, we only support the Personal Access Token (PAT) Authentication method.
|
##### Local App Authentication (For Qodo Merge On-Premise Customers)
|
||||||
|
|
||||||
|
##### 1. Step 1: Set up an application link in Jira Data Center/Server
|
||||||
|
* Go to Jira Administration > Applications > Application Links > Click on `Create link`
|
||||||
|
{width=384}
|
||||||
|
* Choose `External application` and set the direction to `Incoming` and then click `Continue`
|
||||||
|
|
||||||
|
{width=256}
|
||||||
|
* In the following screen, enter the following details:
|
||||||
|
* Name: `Qodo Merge`
|
||||||
|
* Redirect URL: Enter you Qodo Merge URL followed `https://{QODO_MERGE_ENDPOINT}/register_ticket_provider`
|
||||||
|
* Permission: Select `Read`
|
||||||
|
* Click `Save`
|
||||||
|
|
||||||
|
{width=384}
|
||||||
|
* Copy the `Client ID` and `Client secret` and set them in you `.secrets` file:
|
||||||
|
|
||||||
|
{width=256}
|
||||||
|
```toml
|
||||||
|
[jira]
|
||||||
|
jira_app_secret = "..."
|
||||||
|
jira_client_id = "..."
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 2. Step 2: Authenticate with Jira Data Center/Server
|
||||||
|
* Open this URL in your browser: `https://{QODO_MERGE_ENDPOINT}/jira_auth`
|
||||||
|
* Click on link
|
||||||
|
|
||||||
|
{width=384}
|
||||||
|
|
||||||
|
* You will be redirected to Jira Data Center/Server, click `Allow`
|
||||||
|
* You will be redirected back to Qodo Merge PR Agent and you will see a success message.
|
||||||
|
|
||||||
|
|
||||||
|
##### Personal Access Token (PAT) Authentication
|
||||||
|
We also support Personal Access Token (PAT) Authentication method.
|
||||||
|
|
||||||
1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account
|
1. Create a [Personal Access Token (PAT)](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html) in your Jira account
|
||||||
2. In your Configuration file/Environment variables/Secrets file, add the following lines:
|
2. In your Configuration file/Environment variables/Secrets file, add the following lines:
|
||||||
|
@ -101,3 +101,22 @@ def set_claude_model():
|
|||||||
get_settings().set('config.model', model_claude)
|
get_settings().set('config.model', model_claude)
|
||||||
get_settings().set('config.model_weak', model_claude)
|
get_settings().set('config.model_weak', model_claude)
|
||||||
get_settings().set('config.fallback_models', [model_claude])
|
get_settings().set('config.fallback_models', [model_claude])
|
||||||
|
|
||||||
|
|
||||||
|
def is_user_name_a_bot(name: str) -> bool:
|
||||||
|
if not name:
|
||||||
|
return False
|
||||||
|
bot_indicators = ['codium', 'bot_', 'bot-', '_bot', '-bot', 'qodo', "service", "github", "jenkins", "auto",
|
||||||
|
"cicd", "validator", "ci-", "assistant", "srv-"]
|
||||||
|
return any(indicator in name.lower() for indicator in bot_indicators)
|
||||||
|
|
||||||
|
|
||||||
|
def is_pr_description_indicating_bot(description: str) -> bool:
|
||||||
|
if not description:
|
||||||
|
return False
|
||||||
|
bot_descriptions = ["Snyk has created this PR", "This PR was created automatically by",
|
||||||
|
"This PR was created by a bot",
|
||||||
|
"This pull request was automatically generated by"]
|
||||||
|
# Check is it's a Snyk bot
|
||||||
|
if any(bot_description in description for bot_description in bot_descriptions):
|
||||||
|
return True
|
@ -19,7 +19,7 @@ from starlette_context.middleware import RawContextMiddleware
|
|||||||
from pr_agent.agent.pr_agent import PRAgent
|
from pr_agent.agent.pr_agent import PRAgent
|
||||||
from pr_agent.algo.utils import update_settings_from_args
|
from pr_agent.algo.utils import update_settings_from_args
|
||||||
from pr_agent.config_loader import get_settings, global_settings
|
from pr_agent.config_loader import get_settings, global_settings
|
||||||
from pr_agent.git_providers.utils import apply_repo_settings
|
from pr_agent.git_providers.utils import apply_repo_settings, is_user_name_a_bot, is_pr_description_indicating_bot
|
||||||
from pr_agent.identity_providers import get_identity_provider
|
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
|
||||||
@ -102,11 +102,22 @@ async def _perform_commands_bitbucket(commands_conf: str, agent: PRAgent, api_ur
|
|||||||
def is_bot_user(data) -> bool:
|
def is_bot_user(data) -> bool:
|
||||||
try:
|
try:
|
||||||
actor = data.get("data", {}).get("actor", {})
|
actor = data.get("data", {}).get("actor", {})
|
||||||
|
description = data.get("data", {}).get("pullrequest", {}).get("description", "")
|
||||||
# allow actor type: user . if it's "AppUser" or "team" then it is a bot user
|
# allow actor type: user . if it's "AppUser" or "team" then it is a bot user
|
||||||
allowed_actor_types = {"user"}
|
allowed_actor_types = {"user"}
|
||||||
if actor and actor["type"].lower() not in allowed_actor_types:
|
if actor and actor["type"].lower() not in allowed_actor_types:
|
||||||
get_logger().info(f"BitBucket actor type is not 'user', skipping: {actor}")
|
get_logger().info(f"BitBucket actor type is not 'user', skipping: {actor}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
username = actor.get("username", "")
|
||||||
|
if username and is_user_name_a_bot(username):
|
||||||
|
get_logger().info(f"BitBucket actor is a bot user, skipping: {username}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
if description and is_pr_description_indicating_bot(description):
|
||||||
|
get_logger().info(f"Description indicates a bot user: {actor}",
|
||||||
|
artifact={"description": description})
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
get_logger().error(f"Failed 'is_bot_user' logic: {e}")
|
get_logger().error(f"Failed 'is_bot_user' logic: {e}")
|
||||||
return False
|
return False
|
||||||
|
@ -18,7 +18,7 @@ from pr_agent.config_loader import get_settings, global_settings
|
|||||||
from pr_agent.git_providers import (get_git_provider,
|
from pr_agent.git_providers import (get_git_provider,
|
||||||
get_git_provider_with_context)
|
get_git_provider_with_context)
|
||||||
from pr_agent.git_providers.git_provider import IncrementalPR
|
from pr_agent.git_providers.git_provider import IncrementalPR
|
||||||
from pr_agent.git_providers.utils import apply_repo_settings
|
from pr_agent.git_providers.utils import apply_repo_settings, is_user_name_a_bot, is_pr_description_indicating_bot
|
||||||
from pr_agent.identity_providers import get_identity_provider
|
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
|
||||||
@ -238,13 +238,22 @@ def get_log_context(body, event, action, build_number):
|
|||||||
return log_context, sender, sender_id, sender_type
|
return log_context, sender, sender_id, sender_type
|
||||||
|
|
||||||
|
|
||||||
def is_bot_user(sender, sender_type):
|
def is_bot_user(sender, sender_type, user_description):
|
||||||
try:
|
try:
|
||||||
# logic to ignore PRs opened by bot
|
# logic to ignore PRs opened by bot
|
||||||
if get_settings().get("GITHUB_APP.IGNORE_BOT_PR", False) and sender_type == "Bot":
|
if get_settings().get("GITHUB_APP.IGNORE_BOT_PR", False):
|
||||||
if 'pr-agent' not in sender:
|
if sender_type.lower() == "bot":
|
||||||
|
if 'pr-agent' not in sender:
|
||||||
|
get_logger().info(f"Ignoring PR from '{sender=}' because it is a bot")
|
||||||
|
return True
|
||||||
|
if is_user_name_a_bot(sender):
|
||||||
get_logger().info(f"Ignoring PR from '{sender=}' because it is a bot")
|
get_logger().info(f"Ignoring PR from '{sender=}' because it is a bot")
|
||||||
return True
|
return True
|
||||||
|
# Ignore PRs opened by bot users based on their description
|
||||||
|
if isinstance(user_description, str) and is_pr_description_indicating_bot(user_description):
|
||||||
|
get_logger().info(f"Description indicates a bot user: {sender}",
|
||||||
|
artifact={"description": user_description})
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
get_logger().error(f"Failed 'is_bot_user' logic: {e}")
|
get_logger().error(f"Failed 'is_bot_user' logic: {e}")
|
||||||
return False
|
return False
|
||||||
@ -307,7 +316,8 @@ async def handle_request(body: Dict[str, Any], event: str):
|
|||||||
log_context, sender, sender_id, sender_type = get_log_context(body, event, action, build_number)
|
log_context, sender, sender_id, sender_type = get_log_context(body, event, action, build_number)
|
||||||
|
|
||||||
# logic to ignore PRs opened by bot, PRs with specific titles, labels, source branches, or target branches
|
# logic to ignore PRs opened by bot, PRs with specific titles, labels, source branches, or target branches
|
||||||
if is_bot_user(sender, sender_type) and 'check_run' not in body:
|
pr_description = body.get("pull_request", {}).get("body", "")
|
||||||
|
if is_bot_user(sender, sender_type, pr_description) and 'check_run' not in body:
|
||||||
return {}
|
return {}
|
||||||
if action != 'created' and 'check_run' not in body:
|
if action != 'created' and 'check_run' not in body:
|
||||||
if not should_process_pr_logic(body):
|
if not should_process_pr_logic(body):
|
||||||
|
@ -15,7 +15,7 @@ from starlette_context.middleware import RawContextMiddleware
|
|||||||
from pr_agent.agent.pr_agent import PRAgent
|
from pr_agent.agent.pr_agent import PRAgent
|
||||||
from pr_agent.algo.utils import update_settings_from_args
|
from pr_agent.algo.utils import update_settings_from_args
|
||||||
from pr_agent.config_loader import get_settings, global_settings
|
from pr_agent.config_loader import get_settings, global_settings
|
||||||
from pr_agent.git_providers.utils import apply_repo_settings
|
from pr_agent.git_providers.utils import apply_repo_settings, is_user_name_a_bot, is_pr_description_indicating_bot
|
||||||
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
|
||||||
|
|
||||||
@ -86,10 +86,14 @@ def is_bot_user(data) -> bool:
|
|||||||
try:
|
try:
|
||||||
# logic to ignore bot users (unlike Github, no direct flag for bot users in gitlab)
|
# logic to ignore bot users (unlike Github, no direct flag for bot users in gitlab)
|
||||||
sender_name = data.get("user", {}).get("name", "unknown").lower()
|
sender_name = data.get("user", {}).get("name", "unknown").lower()
|
||||||
bot_indicators = ['codium', 'bot_', 'bot-', '_bot', '-bot']
|
if is_user_name_a_bot(sender_name):
|
||||||
if any(indicator in sender_name for indicator in bot_indicators):
|
|
||||||
get_logger().info(f"Skipping GitLab bot user: {sender_name}")
|
get_logger().info(f"Skipping GitLab bot user: {sender_name}")
|
||||||
return True
|
return True
|
||||||
|
pr_description = data.get('object_attributes', {}).get('description', '')
|
||||||
|
if pr_description and is_pr_description_indicating_bot(pr_description):
|
||||||
|
get_logger().info(f"Description indicates a bot user: {sender_name}",
|
||||||
|
artifact={"description": pr_description})
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
get_logger().error(f"Failed 'is_bot_user' logic: {e}")
|
get_logger().error(f"Failed 'is_bot_user' logic: {e}")
|
||||||
return False
|
return False
|
||||||
|
Reference in New Issue
Block a user