1- import asyncio
21import copy
32import os
3+ import re
44from typing import Any , Dict
55
66from fastapi import APIRouter , FastAPI , HTTPException , Request , Response
1010from starlette_context .middleware import RawContextMiddleware
1111
1212from pr_agent .agent .pr_agent import PRAgent
13+ from pr_agent .algo .utils import update_settings_from_args
1314from pr_agent .config_loader import get_settings , global_settings
15+ from pr_agent .git_providers .utils import apply_repo_settings
1416from pr_agent .log import LoggingFormat , get_logger , setup_logger
1517from pr_agent .servers .utils import verify_signature
1618
@@ -50,7 +52,7 @@ async def get_body(request: Request):
5052 if not signature_header :
5153 get_logger ().error ("Missing signature header" )
5254 raise HTTPException (status_code = 400 , detail = "Missing signature header" )
53-
55+
5456 try :
5557 verify_signature (body_bytes , webhook_secret , f"sha256={ signature_header } " )
5658 except Exception as ex :
@@ -70,6 +72,9 @@ async def handle_request(body: Dict[str, Any], event: str):
7072
7173 # Handle different event types
7274 if event == "pull_request" :
75+ if not should_process_pr_logic (body ):
76+ get_logger ().debug (f"Request ignored: PR logic filtering" )
77+ return {}
7378 if action in ["opened" , "reopened" , "synchronized" ]:
7479 await handle_pr_event (body , event , action , agent )
7580 elif event == "issue_comment" :
@@ -90,12 +95,21 @@ async def handle_pr_event(body: Dict[str, Any], event: str, action: str, agent:
9095
9196 # Handle PR based on action
9297 if action in ["opened" , "reopened" ]:
93- commands = get_settings ().get ("gitea.pr_commands" , [])
94- for command in commands :
95- await agent .handle_request (api_url , command )
98+ # commands = get_settings().get("gitea.pr_commands", [])
99+ await _perform_commands_gitea ("pr_commands" , agent , body , api_url )
100+ # for command in commands:
101+ # await agent.handle_request(api_url, command)
96102 elif action == "synchronized" :
97103 # Handle push to PR
98- await agent .handle_request (api_url , "/review --incremental" )
104+ commands_on_push = get_settings ().get (f"gitea.push_commands" , {})
105+ handle_push_trigger = get_settings ().get (f"gitea.handle_push_trigger" , False )
106+ if not commands_on_push or not handle_push_trigger :
107+ get_logger ().info ("Push event, but no push commands found or push trigger is disabled" )
108+ return
109+ get_logger ().debug (f'A push event has been received: { api_url } ' )
110+ await _perform_commands_gitea ("push_commands" , agent , body , api_url )
111+ # for command in commands_on_push:
112+ # await agent.handle_request(api_url, command)
99113
100114async def handle_comment_event (body : Dict [str , Any ], event : str , action : str , agent : PRAgent ):
101115 """Handle comment events"""
@@ -113,6 +127,85 @@ async def handle_comment_event(body: Dict[str, Any], event: str, action: str, ag
113127
114128 await agent .handle_request (pr_url , comment_body )
115129
130+ async def _perform_commands_gitea (commands_conf : str , agent : PRAgent , body : dict , api_url : str ):
131+ apply_repo_settings (api_url )
132+ if commands_conf == "pr_commands" and get_settings ().config .disable_auto_feedback : # auto commands for PR, and auto feedback is disabled
133+ get_logger ().info (f"Auto feedback is disabled, skipping auto commands for PR { api_url = } " )
134+ return
135+ if not should_process_pr_logic (body ): # Here we already updated the configuration with the repo settings
136+ return {}
137+ commands = get_settings ().get (f"gitea.{ commands_conf } " )
138+ if not commands :
139+ get_logger ().info (f"New PR, but no auto commands configured" )
140+ return
141+ get_settings ().set ("config.is_auto_command" , True )
142+ for command in commands :
143+ split_command = command .split (" " )
144+ command = split_command [0 ]
145+ args = split_command [1 :]
146+ other_args = update_settings_from_args (args )
147+ new_command = ' ' .join ([command ] + other_args )
148+ get_logger ().info (f"{ commands_conf } . Performing auto command '{ new_command } ', for { api_url = } " )
149+ await agent .handle_request (api_url , new_command )
150+
151+ def should_process_pr_logic (body ) -> bool :
152+ try :
153+ pull_request = body .get ("pull_request" , {})
154+ title = pull_request .get ("title" , "" )
155+ pr_labels = pull_request .get ("labels" , [])
156+ source_branch = pull_request .get ("head" , {}).get ("ref" , "" )
157+ target_branch = pull_request .get ("base" , {}).get ("ref" , "" )
158+ sender = body .get ("sender" , {}).get ("login" )
159+ repo_full_name = body .get ("repository" , {}).get ("full_name" , "" )
160+
161+ # logic to ignore PRs from specific repositories
162+ ignore_repos = get_settings ().get ("CONFIG.IGNORE_REPOSITORIES" , [])
163+ if ignore_repos and repo_full_name :
164+ if any (re .search (regex , repo_full_name ) for regex in ignore_repos ):
165+ get_logger ().info (f"Ignoring PR from repository '{ repo_full_name } ' due to 'config.ignore_repositories' setting" )
166+ return False
167+
168+ # logic to ignore PRs from specific users
169+ ignore_pr_users = get_settings ().get ("CONFIG.IGNORE_PR_AUTHORS" , [])
170+ if ignore_pr_users and sender :
171+ if any (re .search (regex , sender ) for regex in ignore_pr_users ):
172+ get_logger ().info (f"Ignoring PR from user '{ sender } ' due to 'config.ignore_pr_authors' setting" )
173+ return False
174+
175+ # logic to ignore PRs with specific titles
176+ if title :
177+ ignore_pr_title_re = get_settings ().get ("CONFIG.IGNORE_PR_TITLE" , [])
178+ if not isinstance (ignore_pr_title_re , list ):
179+ ignore_pr_title_re = [ignore_pr_title_re ]
180+ if ignore_pr_title_re and any (re .search (regex , title ) for regex in ignore_pr_title_re ):
181+ get_logger ().info (f"Ignoring PR with title '{ title } ' due to config.ignore_pr_title setting" )
182+ return False
183+
184+ # logic to ignore PRs with specific labels or source branches or target branches.
185+ ignore_pr_labels = get_settings ().get ("CONFIG.IGNORE_PR_LABELS" , [])
186+ if pr_labels and ignore_pr_labels :
187+ labels = [label ['name' ] for label in pr_labels ]
188+ if any (label in ignore_pr_labels for label in labels ):
189+ labels_str = ", " .join (labels )
190+ get_logger ().info (f"Ignoring PR with labels '{ labels_str } ' due to config.ignore_pr_labels settings" )
191+ return False
192+
193+ # logic to ignore PRs with specific source or target branches
194+ ignore_pr_source_branches = get_settings ().get ("CONFIG.IGNORE_PR_SOURCE_BRANCHES" , [])
195+ ignore_pr_target_branches = get_settings ().get ("CONFIG.IGNORE_PR_TARGET_BRANCHES" , [])
196+ if pull_request and (ignore_pr_source_branches or ignore_pr_target_branches ):
197+ if any (re .search (regex , source_branch ) for regex in ignore_pr_source_branches ):
198+ get_logger ().info (
199+ f"Ignoring PR with source branch '{ source_branch } ' due to config.ignore_pr_source_branches settings" )
200+ return False
201+ if any (re .search (regex , target_branch ) for regex in ignore_pr_target_branches ):
202+ get_logger ().info (
203+ f"Ignoring PR with target branch '{ target_branch } ' due to config.ignore_pr_target_branches settings" )
204+ return False
205+ except Exception as e :
206+ get_logger ().error (f"Failed 'should_process_pr_logic': { e } " )
207+ return True
208+
116209# FastAPI app setup
117210middleware = [Middleware (RawContextMiddleware )]
118211app = FastAPI (middleware = middleware )
0 commit comments