Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions pr_agent/tools/pr_code_suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,16 @@ def _extract_link(comment_text: str):
pr_comment_updated += f"{prev_suggestion_table}\n"

get_logger().info(f"Persistent mode - updating comment {comment_url} to latest {name} message")
if progress_response: # publish to 'progress_response' comment, because it refreshes immediately
git_provider.edit_comment(progress_response, pr_comment_updated)
git_provider.remove_comment(comment)
comment = progress_response
else:
git_provider.edit_comment(comment, pr_comment_updated)
git_provider.edit_comment(comment, pr_comment_updated)
if progress_response:
# best-effort: propagating would re-trigger the duplicate-thread fallback below
try:
git_provider.edit_comment(progress_response, "Code suggestions published in the persistent thread above.")
git_provider.remove_comment(progress_response)
except Exception as cleanup_error:
get_logger().warning(
f"Failed to clean up progress note after persistent update, leaving it in place: {cleanup_error}"
)
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
return comment
except Exception as e:
get_logger().exception(f"Failed to update persistent review, error: {e}")
Expand Down
27 changes: 27 additions & 0 deletions tests/unittest/test_pr_code_suggestions_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,30 @@ async def test_push_inline_code_suggestions_falls_back_to_individual_publish_cal
assert second_retry[0]["relevant_lines_start"] == 2
assert second_retry[0]["relevant_lines_end"] == 2
assert "```suggestion\n return new_worker()" in second_retry[0]["body"]


def test_persistent_update_survives_progress_cleanup_failure():
"""A failing progress-note cleanup must not abort the persistent update:
if the cleanup error propagated, the caller would fall back to publishing
a new suggestions thread, re-creating the duplicate-thread bug."""
initial_header = "## PR Code Suggestions"
existing = MagicMock()
existing.body = f"{initial_header}\n<!-- aaa1111 -->\n<table>old suggestions</table>"
provider = MagicMock()
provider.get_issue_comments.return_value = [existing]
provider.get_comment_url.return_value = "https://example.test/comment/1"
provider.get_latest_commit_url.return_value = "https://example.test/commit/deadbee"
# First edit updates the persistent comment and succeeds; the second edit
# (re-labelling the progress note before deletion) fails.
provider.edit_comment.side_effect = [None, RuntimeError("cleanup failed")]
progress_note = MagicMock()

result = PRCodeSuggestions.publish_persistent_comment_with_history(
provider, f"{initial_header}\n<table>new suggestions</table>", initial_header,
update_header=False, name="suggestions", final_update_message=False,
progress_response=progress_note)

assert result is existing
assert provider.edit_comment.call_count == 2
provider.remove_comment.assert_not_called()
provider.publish_comment.assert_not_called()
Loading