diff options
| author | Daniel Smith <daniel.smith@qt.io> | 2025-06-05 11:26:15 +0200 |
|---|---|---|
| committer | Daniel Smith <daniel.smith@qt.io> | 2025-06-30 09:56:09 +0000 |
| commit | 36141c9a38da51f3ad12d242c94c9d25461378b6 (patch) | |
| tree | 4d70c2f1b566b3a4176b24e9ec2cf8039623ebb2 | |
| parent | 887f835f864080cc5c16199b1be180abbe2555c1 (diff) | |
Avoid posting duplicate comments on new patchsets
In order to cut down on noise, the bot will only
post on files which have not been commented on
previously in the change, even if from an earlier
patchset.
Fixes: QTQAINFRA-7233
Change-Id: If95ea860398bdca2f62c0e56c1d4ac9f241bace6
Reviewed-by: Daniel Smith <daniel.smith@qt.io>
| -rw-r--r-- | src/main.py | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/main.py b/src/main.py index 6b27e42..98287db 100644 --- a/src/main.py +++ b/src/main.py @@ -341,6 +341,44 @@ def generate_review(comments_per_file): return review +async def get_existing_bot_comments(data, session): + """Fetch existing comments from Gerrit for the given change to find files already commented on by the bot.""" + change_number = data['change']['number'] + url = f"https://codereview.qt-project.org/a/changes/{change_number}/comments" + headers = {'Authorization': 'Basic ' + GERRIT_AUTH} + commented_files = set() + + log.info("%s: Fetching existing comments", change_number) + try: + async with session.get(url, headers=headers) as response: + if response.status == 200: + # Gerrit API response starts with )]}' + raw_response_text = await response.text() + if raw_response_text.startswith(")]}'\n"): + json_text = raw_response_text[5:] + else: + json_text = raw_response_text + + all_comments = json.loads(json_text) + for file_path, file_comments in all_comments.items(): + for comment_info in file_comments: + if 'author' in comment_info and \ + comment_info['author'].get('username') == GERRIT_USERNAME: + commented_files.add(file_path) + break # Found a bot comment for this file + log.info("%s: Found %d files previously commented on by the bot: %s", + change_number, len(commented_files), commented_files if commented_files else "None") + else: + response_text = await response.text() + log.error("%s: Error fetching comments: %s %s", change_number, response.status, response_text) + except aiohttp.ClientError as e: + log.error('%s: ClientError fetching comments: %s', change_number, str(e)) + except json.JSONDecodeError as e: + log.error('%s: JSONDecodeError parsing comments: %s', change_number, str(e)) + + return commented_files + + async def post_review(data, review, retry=0): """Post the review to Gerrit.""" change_number = data['change']['number'] @@ -541,6 +579,27 @@ async def handle(request): await clone_repo(data) await checkout_patch(data) comments = await run_security_header_check(data) + + # Filter comments if this is not the first patchset and there are comments + # Default patchset number to 1 if not present in data + current_patchset_number = data['patchSet'].get('number', 1) + if comments and current_patchset_number > 1: + log.info("%s: Patchset %s > 1, checking for existing bot comments.", + data['change']['number'], current_patchset_number) + # Create a new session for this specific task, or pass one if available + async with aiohttp.ClientSession() as session: + previously_commented_files = await get_existing_bot_comments(data, session) + + if previously_commented_files: + original_comment_count = len(comments) + comments = { + file: comment_info + for file, comment_info in comments.items() + if file not in previously_commented_files + } + if len(comments) < original_comment_count: + log.info("%s: Filtered comments from %d to %d based on previous bot activity.", + data['change']['number'], original_comment_count, len(comments)) except Exception as e: log.error("Error: %s", str(e)) await post_teams_error_message(data, str(e)) |
