mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-04 21:00:40 +08:00
Merge pull request #132 from Codium-ai/tr/code_enhancment
Enhancement of GitHub Webhook and Polling Server
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
|
from typing import Dict, Any
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -14,50 +15,65 @@ router = APIRouter()
|
|||||||
|
|
||||||
@router.post("/api/v1/github_webhooks")
|
@router.post("/api/v1/github_webhooks")
|
||||||
async def handle_github_webhooks(request: Request, response: Response):
|
async def handle_github_webhooks(request: Request, response: Response):
|
||||||
logging.debug("Received a github webhook")
|
"""
|
||||||
|
Receives and processes incoming GitHub webhook requests.
|
||||||
|
Verifies the request signature, parses the request body, and passes it to the handle_request function for further processing.
|
||||||
|
"""
|
||||||
|
logging.debug("Received a GitHub webhook")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
body = await request.json()
|
body = await request.json()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Error parsing request body", e)
|
logging.error("Error parsing request body", e)
|
||||||
raise HTTPException(status_code=400, detail="Error parsing request body") from e
|
raise HTTPException(status_code=400, detail="Error parsing request body") from e
|
||||||
|
|
||||||
body_bytes = await request.body()
|
body_bytes = await request.body()
|
||||||
signature_header = request.headers.get('x-hub-signature-256', None)
|
signature_header = request.headers.get('x-hub-signature-256', None)
|
||||||
try:
|
|
||||||
webhook_secret = settings.github.webhook_secret
|
webhook_secret = getattr(settings.github, 'webhook_secret', None)
|
||||||
except AttributeError:
|
|
||||||
webhook_secret = None
|
|
||||||
if webhook_secret:
|
if webhook_secret:
|
||||||
verify_signature(body_bytes, webhook_secret, signature_header)
|
verify_signature(body_bytes, webhook_secret, signature_header)
|
||||||
|
|
||||||
logging.debug(f'Request body:\n{body}')
|
logging.debug(f'Request body:\n{body}')
|
||||||
|
|
||||||
return await handle_request(body)
|
return await handle_request(body)
|
||||||
|
|
||||||
|
|
||||||
async def handle_request(body):
|
async def handle_request(body: Dict[str, Any]):
|
||||||
action = body.get("action", None)
|
"""
|
||||||
installation_id = body.get("installation", {}).get("id", None)
|
Handle incoming GitHub webhook requests.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
body: The request body.
|
||||||
|
"""
|
||||||
|
action = body.get("action")
|
||||||
|
installation_id = body.get("installation", {}).get("id")
|
||||||
settings.set("GITHUB.INSTALLATION_ID", installation_id)
|
settings.set("GITHUB.INSTALLATION_ID", installation_id)
|
||||||
agent = PRAgent()
|
agent = PRAgent()
|
||||||
|
|
||||||
if action == 'created':
|
if action == 'created':
|
||||||
if "comment" not in body:
|
if "comment" not in body:
|
||||||
return {}
|
return {}
|
||||||
comment_body = body.get("comment", {}).get("body", None)
|
comment_body = body.get("comment", {}).get("body")
|
||||||
if 'sender' in body and 'login' in body['sender'] and 'bot' in body['sender']['login']:
|
sender = body.get("sender", {}).get("login")
|
||||||
|
if sender and 'bot' in sender:
|
||||||
return {}
|
return {}
|
||||||
if "issue" not in body and "pull_request" not in body["issue"]:
|
if "issue" not in body or "pull_request" not in body["issue"]:
|
||||||
return {}
|
return {}
|
||||||
pull_request = body["issue"]["pull_request"]
|
pull_request = body["issue"]["pull_request"]
|
||||||
api_url = pull_request.get("url", None)
|
api_url = pull_request.get("url")
|
||||||
await agent.handle_request(api_url, comment_body)
|
await agent.handle_request(api_url, comment_body)
|
||||||
|
|
||||||
elif action in ["opened"] or 'reopened' in action:
|
elif action in ["opened"] or 'reopened' in action:
|
||||||
pull_request = body.get("pull_request", None)
|
pull_request = body.get("pull_request")
|
||||||
if not pull_request:
|
if not pull_request:
|
||||||
return {}
|
return {}
|
||||||
api_url = pull_request.get("url", None)
|
api_url = pull_request.get("url")
|
||||||
if api_url is None:
|
if not api_url:
|
||||||
return {}
|
return {}
|
||||||
await agent.handle_request(api_url, "/review")
|
await agent.handle_request(api_url, "/review")
|
||||||
else:
|
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,28 +15,40 @@ NOTIFICATION_URL = "https://api.github.com/notifications"
|
|||||||
|
|
||||||
|
|
||||||
def now() -> str:
|
def now() -> str:
|
||||||
|
"""
|
||||||
|
Get the current UTC time in ISO 8601 format.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The current UTC time in ISO 8601 format.
|
||||||
|
"""
|
||||||
now_utc = datetime.now(timezone.utc).isoformat()
|
now_utc = datetime.now(timezone.utc).isoformat()
|
||||||
now_utc = now_utc.replace("+00:00", "Z")
|
now_utc = now_utc.replace("+00:00", "Z")
|
||||||
return now_utc
|
return now_utc
|
||||||
|
|
||||||
|
|
||||||
async def polling_loop():
|
async def polling_loop():
|
||||||
|
"""
|
||||||
|
Polls for notifications and handles them accordingly.
|
||||||
|
"""
|
||||||
handled_ids = set()
|
handled_ids = set()
|
||||||
since = [now()]
|
since = [now()]
|
||||||
last_modified = [None]
|
last_modified = [None]
|
||||||
git_provider = get_git_provider()()
|
git_provider = get_git_provider()()
|
||||||
user_id = git_provider.get_user_id()
|
user_id = git_provider.get_user_id()
|
||||||
agent = PRAgent()
|
agent = PRAgent()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
deployment_type = settings.github.deployment_type
|
deployment_type = settings.github.deployment_type
|
||||||
token = settings.github.user_token
|
token = settings.github.user_token
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
deployment_type = 'none'
|
deployment_type = 'none'
|
||||||
token = None
|
token = None
|
||||||
|
|
||||||
if deployment_type != 'user':
|
if deployment_type != 'user':
|
||||||
raise ValueError("Deployment mode must be set to 'user' to get notifications")
|
raise ValueError("Deployment mode must be set to 'user' to get notifications")
|
||||||
if not token:
|
if not token:
|
||||||
raise ValueError("User token must be set to get notifications")
|
raise ValueError("User token must be set to get notifications")
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -52,6 +64,7 @@ async def polling_loop():
|
|||||||
params["since"] = since[0]
|
params["since"] = since[0]
|
||||||
if last_modified[0]:
|
if last_modified[0]:
|
||||||
headers["If-Modified-Since"] = last_modified[0]
|
headers["If-Modified-Since"] = last_modified[0]
|
||||||
|
|
||||||
async with session.get(NOTIFICATION_URL, headers=headers, params=params) as response:
|
async with session.get(NOTIFICATION_URL, headers=headers, params=params) as response:
|
||||||
if response.status == 200:
|
if response.status == 200:
|
||||||
if 'Last-Modified' in response.headers:
|
if 'Last-Modified' in response.headers:
|
||||||
|
Reference in New Issue
Block a user