Improve handling of tagging and Github app user interaction

This commit is contained in:
Ori Kotek
2023-07-06 12:58:05 +03:00
parent 0ebd29d398
commit b6333e7f20
5 changed files with 44 additions and 9 deletions

View File

@ -10,11 +10,16 @@ class PRAgent:
self.installation_id = installation_id self.installation_id = installation_id
async def handle_request(self, pr_url, request): async def handle_request(self, pr_url, request):
if 'please review' in request.lower(): if 'please review' in request.lower() or 'review' == request.lower().strip() or len(request) == 0:
reviewer = PRReviewer(pr_url, self.installation_id) reviewer = PRReviewer(pr_url, self.installation_id)
await reviewer.review() await reviewer.review()
elif 'please answer' in request.lower(): else:
question = re.split(r'(?i)please answer', request)[1].strip() if "please answer" in request.lower():
question = re.split(r'(?i)please answer', request)[1].strip()
elif request.lower().strip().startswith("answer"):
question = re.split(r'(?i)answer', request)[1].strip()
else:
question = request
answerer = PRQuestions(pr_url, question, self.installation_id) answerer = PRQuestions(pr_url, question, self.installation_id)
await answerer.answer() await answerer.answer()

View File

@ -24,6 +24,7 @@ class GithubProvider:
self.repo = None self.repo = None
self.pr_num = None self.pr_num = None
self.pr = None self.pr = None
self.github_user_id = None
if pr_url: if pr_url:
self.set_pr(pr_url) self.set_pr(pr_url)
@ -42,6 +43,8 @@ class GithubProvider:
def publish_comment(self, pr_comment: str, is_temporary: bool = False): def publish_comment(self, pr_comment: str, is_temporary: bool = False):
response = self.pr.create_issue_comment(pr_comment) response = self.pr.create_issue_comment(pr_comment)
if hasattr(response, "user") and hasattr(response.user, "login"):
self.github_user_id = response.user.login
response.is_temporary = is_temporary response.is_temporary = is_temporary
if not hasattr(self.pr, 'comments_list'): if not hasattr(self.pr, 'comments_list'):
self.pr.comments_list = [] self.pr.comments_list = []
@ -109,6 +112,14 @@ class GithubProvider:
def get_pr_branch(self): def get_pr_branch(self):
return self.pr.head.ref return self.pr.head.ref
def get_user_id(self):
if not self.github_user_id:
try:
self.github_user_id = self.github_client.get_user().login
except Exception as e:
logging.exception(f"Failed to get user id, error: {e}")
return self.github_user_id
def get_notifications(self, since: datetime): def get_notifications(self, since: datetime):
deployment_type = settings.get("GITHUB.DEPLOYMENT_TYPE", "user") deployment_type = settings.get("GITHUB.DEPLOYMENT_TYPE", "user")

View File

@ -40,7 +40,7 @@ async def handle_request(body):
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", None)
if "says 'Please" in comment_body: if 'sender' in body and 'login' in body['sender'] and 'bot' in body['sender']['login']:
return {} return {}
if "issue" not in body and "pull_request" not in body["issue"]: if "issue" not in body and "pull_request" not in body["issue"]:
return {} return {}

View File

@ -7,6 +7,7 @@ import aiohttp
from pr_agent.agent.pr_agent import PRAgent from pr_agent.agent.pr_agent import PRAgent
from pr_agent.config_loader import settings from pr_agent.config_loader import settings
from pr_agent.git_providers import get_git_provider
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
NOTIFICATION_URL = "https://api.github.com/notifications" NOTIFICATION_URL = "https://api.github.com/notifications"
@ -21,6 +22,8 @@ def now() -> str:
async def polling_loop(): async def polling_loop():
since = [now()] since = [now()]
last_modified = [None] last_modified = [None]
git_provider = get_git_provider()()
user_id = git_provider.get_user_id()
try: try:
deployment_type = settings.github.deployment_type deployment_type = settings.github.deployment_type
token = settings.github.user_token token = settings.github.user_token
@ -58,12 +61,18 @@ async def polling_loop():
async with session.get(latest_comment, headers=headers) as comment_response: async with session.get(latest_comment, headers=headers) as comment_response:
if comment_response.status == 200: if comment_response.status == 200:
comment = await comment_response.json() comment = await comment_response.json()
if hasattr(comment, 'user') and hasattr(comment['user'], 'login'):
if comment['user']['login'] == user_id:
continue
comment_body = comment['body'] if 'body' in comment else '' comment_body = comment['body'] if 'body' in comment else ''
commenter_github_user = comment['user']['login'] if 'user' in comment else '' commenter_github_user = comment['user']['login'] if 'user' in comment else ''
logging.info(f"Commenter: {commenter_github_user}\nComment: {comment_body}") logging.info(f"Commenter: {commenter_github_user}\nComment: {comment_body}")
if comment_body.strip().startswith("@"): user_tag = "@" + user_id
agent = PRAgent() if user_tag not in comment_body:
await agent.handle_request(pr_url, comment_body) continue
rest_of_comment = comment_body.split(user_tag)[1].strip()
agent = PRAgent()
await agent.handle_request(pr_url, rest_of_comment)
elif response.status != 304: elif response.status != 304:
print(f"Failed to fetch notifications. Status code: {response.status}") print(f"Failed to fetch notifications. Status code: {response.status}")

View File

@ -82,8 +82,18 @@ class PRReviewer:
logging.error("Unable to decode JSON response from AI") logging.error("Unable to decode JSON response from AI")
data = {} data = {}
markdown_text = convert_to_markdown(data) markdown_text = convert_to_markdown(data)
markdown_text += "\nAdd a comment that says 'Please review' to ask for a new review after you update the PR.\n" user = self.git_provider.get_user_id()
markdown_text += "Add a comment that says 'Please answer <QUESTION...>' to ask a question about this PR.\n" markdown_text += "\n### How to use\n"
if user and '[bot]' not in user:
markdown_text += f"> Tag me in a comment '@{user}' to ask for a new review after you update the PR.\n"
markdown_text += "> You can also tag me and ask any question, " \
f"for example '@{user} is the PR ready for merge?'"
else:
markdown_text += "> Add a comment that says 'review' to ask for a new review " \
"after you update the PR.\n"
markdown_text += "> You can also add a comment that says 'answer QUESTION', " \
"for example 'answer is the PR ready for merge?'"
if settings.config.verbosity_level >= 2: if settings.config.verbosity_level >= 2:
logging.info(f"Markdown response:\n{markdown_text}") logging.info(f"Markdown response:\n{markdown_text}")
return markdown_text return markdown_text