Skip to content

Conversation

@maoliver-amd
Copy link

@maoliver-amd maoliver-amd commented Dec 5, 2024

This extends the existing cang-tidy/format review capability by adding additional functionality:

  • Auto hide/minimize old outdated review comments
  • Mark outdated review conversations as resolved
  • Delete outdated review conversations (user option to select between resolving or deleting)
  • Reuse existing review conversations on subsequent runs in case issue is still present (prevent spam comments for identical issues being continuously added on each run)(user option to either resue or resolve/delete and repost)
  • Reuse existing review comment on subsequent runs for issues still present while also creating a new comment should any additional new issues be detected (reduces duplicate issue spam)

Uses graphql queries to provide additional functionality beyond what the github api suppots

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced options to manage pull request review comments: delete outdated comments and reuse existing comments.
    • Enhanced GitHub API client with new GraphQL queries and mutations for improved review comment management.
    • Added functionality to track and report reused suggestions in review summaries.
  • Bug Fixes

    • Improved handling of existing review comments, including fetching, closing, and hiding stale reviews.
  • Tests

    • Added mock GraphQL request handling in tests to simulate interactions with the GitHub API for review comments.

Comment on lines 72 to 75
#: See :std:option:`--delete-comments`.
delete_comments: bool = True
#: See :std:option:`--reuse-comments`.
reuse_comments: bool = True
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds 2 new user options:

  1. delete_comments: Old out of date review comment conversations/suggestions will be deleted if set to true of marked as resolved if set to False
  2. reuse_comments: On subsequent runs if an issue still exists and an existing review comment conversation exists then if set to true then the existing conversation will be used. If False a new conversation will be made and the old one resolved/deleted depending on delete_comments

2bndy5

This comment was marked as resolved.

2bndy5

This comment was marked as resolved.

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 5, 2024

You'll also need to update the PR reviews test with mocked responses to the graphQL API.

with requests_mock.Mocker() as mock:

You'll find more about that at requests-mock lib's docs

@maoliver-amd
Copy link
Author

You'll also need to update the PR reviews test with mocked responses to the graphQL API.

with requests_mock.Mocker() as mock:

You'll find more about that at requests-mock lib's docs

Added the mock responses (I think I did it correctly)

2bndy5

This comment was marked as resolved.

2bndy5 added a commit that referenced this pull request Dec 7, 2024
With the html marker used in our other generated comments. This is to avoid ambiguity and help on-board new features in #131.
2bndy5 added a commit that referenced this pull request Dec 7, 2024
With the html marker used in our other generated comments. This is to avoid ambiguity and help on-board new features in #131.
@2bndy5 2bndy5 added the enhancement New feature or request label Dec 7, 2024
@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2024

Warning

Rate limit exceeded

@maoliver-amd has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 2 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 005b25e and 3891180.

📒 Files selected for processing (1)
  • cpp_linter/cli.py (2 hunks)

Walkthrough

The changes introduced in this pull request enhance the functionality of the cpp_linter by adding two boolean attributes, delete_review_comments and reuse_review_comments, to the Args class. These attributes control the management of pull request review comments. The GithubApiClient class is also updated with new GraphQL queries and methods for handling review comments, including fetching, closing, and hiding comments. Additionally, a new JSON file is added to represent review threads, and the test suite is updated to mock GraphQL interactions for more comprehensive testing.

Changes

File Change Summary
cpp_linter/cli.py Added attributes delete_review_comments and reuse_review_comments to Args class; updated _parser_args with new CLI options -C and -U.
cpp_linter/rest_api/github_api.py Updated post_review method to include delete_review_comments; added methods for managing review comments and updating existing logic.
tests/reviews/pr_reviews_graphql.json Introduced a new JSON file containing structured data for review threads, including details about comments and suggestions.
tests/reviews/test_pr_review.py Enhanced test_post_review with a mock GraphQL request handling mechanism to simulate GitHub API interactions for review comments.
cpp_linter/clang_tools/patcher.py Added tool_reused attribute to track reused suggestions; introduced remove_reused_suggestions method to manage reused comments.

Possibly related PRs

  • feat: capture and output clang version used #124: The changes in this PR directly relate to the management of review comments, specifically adding parameters for delete_review_comments and reuse_review_comments in the post_review method, which aligns with the new attributes introduced in the main PR.
  • prefix every review comment #132: This PR modifies the serialization of review comments, which could be relevant to how comments are handled in conjunction with the new boolean attributes introduced in the main PR for managing review comments.

Suggested labels

bug

🐰 In the meadow, comments sway,
New options bloom, bright as day.
Delete or reuse, take your pick,
With GraphQL magic, it's all quite slick!
Review threads dance, in JSON they play,
Hopping along, we code away! 🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

coderabbitai[bot]

This comment was marked as resolved.

@2bndy5 2bndy5 dismissed their stale review December 8, 2024 02:23

outdated review

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 13, 2024

So basically dont dismiss a previous review if not all its review thread comments have been resolved? while still posting a new review with any additional issues?

Yes. If there are unresolved suggestions in old reviews, then dismissing them can prevent those unresolved suggestions getting addressed.

So should the new review summary be modified so that it only shows the count of new suggestions (ignoring the reused ones) or should it be updated so that the summary contains all the combined suggestions reused and new?

Good question. Let me propose an example as a goal:

Only 5 of 7 new concerns fit within this pull request's diff.

and after another commit where 1 concern is addressed but 2 new ones pop up

Only 2 of 2 new concerns fit within this pull request's diff. 4 concerns were suppressed as duplicates.

I don't think we should be updating old reviews' summary comment when posting a new review. That would seem superfluous.

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 13, 2024

Today, I'm going to tackle using pagination when getting the review threads with graphql. I'll be using the upstream branch (hide-reuse-pr-reviews) instead of this one though.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
cpp_linter/clang_tools/patcher.py (1)

132-143: Simplify string concatenation for readability

Consider using a single f-string to construct the summary message instead of concatenating multiple strings. This enhances readability and maintains consistency.

Apply this diff to improve the code:

-                summary += (
-                    f"Only {posted_tool_advice[tool_name]} out of "
-                    + f"{self.tool_total[tool_name]} {tool_name}"
-                    + " new concerns fit within this pull request's diff."
-                )
+                summary += f"Only {posted_tool_advice[tool_name]} out of {self.tool_total[tool_name]} {tool_name} new concerns fit within this pull request's diff."
cpp_linter/rest_api/github_api.py (1)

507-574: Improve logging for clarity in _close_review_comment

When deleting a comment, the logging message references thread_id, which may not correspond to the operation being performed. Update the logging to reference the correct ID based on the operation.

Apply this diff to enhance the logging:

             response = self.api_request(
                 url=f"{self.api_url}/graphql",
                 method="POST",
                 data=json.dumps({"query": mutation, "variables": variables}),
                 strict=False,
             )
-            logger.debug(
-                "%s review comment thread %s (thread_id: %s)",
-                operation.title(),
-                "failed" if response.status_code != 200 else "succeeded",
-                thread_id,
-            )
+            logger.debug(
+                "%s review comment %s (%s: %s)",
+                operation.title(),
+                "failed" if response.status_code != 200 else "succeeded",
+                "comment_id" if delete else "thread_id",
+                comment_id if delete else thread_id,
+            )

This ensures that the log message accurately reflects the operation and references the correct identifier.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3374bc6 and a911d69.

📒 Files selected for processing (2)
  • cpp_linter/clang_tools/patcher.py (4 hunks)
  • cpp_linter/rest_api/github_api.py (7 hunks)
🔇 Additional comments (4)
cpp_linter/clang_tools/patcher.py (1)

75-80: Initialization of self.tool_reused is appropriate

The new attribute self.tool_reused is correctly initialized as a dictionary to track reused concerns from previous reviews.

cpp_linter/rest_api/github_api.py (3)

40-69: GraphQL queries are well-defined with proper variable usage

The GraphQL query QUERY_REVIEW_COMMENTS is correctly defined using variables, enhancing security and preventing injection risks.


336-337: Method signature updates align with new functionality

The addition of delete_review_comments and reuse_review_comments parameters to the post_review method appropriately extends functionality.


735-765: Ensure ignored_reviews contains valid review node IDs

In the _hide_stale_reviews method, confirm that the ignored_reviews list contains valid node_id strings to prevent unintended hiding of active reviews.

Run the following script to validate the ignored_reviews:

This script checks that each node_id in ignored_reviews exists in the list of current reviews.

@maoliver-amd
Copy link
Author

OK I have added code to not dismiss old reviews if they are reused and to correct the suggestion count in new reviews

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
cpp_linter/rest_api/github_api.py (2)

474-475: Update method docstring to include new parameters

The method has new parameters but the docstring hasn't been updated to reflect these changes. Consider adding parameter descriptions for delete_review_comments and reuse_review_comments.

     def post_review(
         self,
         files: List[FileObj],
         tidy_review: bool,
         format_review: bool,
         no_lgtm: bool,
         passive_reviews: bool,
         clang_versions: ClangVersions,
         delete_review_comments: bool = True,
         reuse_review_comments: bool = True,
+    ):
+        """Post a review for the pull request.
+
+        :param files: List of files to review
+        :param tidy_review: Flag to enable clang-tidy review
+        :param format_review: Flag to enable clang-format review
+        :param no_lgtm: Flag to control LGTM comments
+        :param passive_reviews: Flag for passive review mode
+        :param clang_versions: Clang tool versions
+        :param delete_review_comments: Flag to delete rather than resolve outdated comments
+        :param reuse_review_comments: Flag to reuse existing comments if they match
+        """
     ):

713-778: Consider breaking down the complex review comment checking logic

The _check_reused_comments method is quite long and handles multiple responsibilities. Consider breaking it down into smaller, more focused methods for better maintainability.

Suggested structure:

def _check_reused_comments(self, delete_review_comments: bool, reuse_review_comments: bool, review_comments: ReviewComments) -> List[str]:
    """Main orchestrator method for handling review comments."""
    ignored_reviews = []
    found_threads = self._get_existing_review_comments(
        no_dismissed=reuse_review_comments and not delete_review_comments
    )
    if not found_threads:
        return ignored_reviews
    
    if reuse_review_comments:
        return self._handle_reusable_comments(found_threads, review_comments)
    else:
        self._close_all_comments(found_threads, delete_review_comments)
        return ignored_reviews

def _handle_reusable_comments(self, found_threads: List[Dict], review_comments: ReviewComments) -> List[str]:
    """Handle reusable comments logic."""
    ignored_reviews = []
    existing_review_comments = []
    for thread in found_threads:
        self._process_thread_comments(thread, review_comments, ignored_reviews, existing_review_comments)
    review_comments.remove_reused_suggestions(existing_review_comments=existing_review_comments)
    return ignored_reviews

def _process_thread_comments(self, thread: Dict, review_comments: ReviewComments, ignored_reviews: List[str], existing_review_comments: List):
    """Process individual thread comments."""
    for comment in thread["comments"]["nodes"]:
        if self._is_comment_reusable(comment, thread):
            self._try_reuse_comment(comment, thread, review_comments, ignored_reviews, existing_review_comments)
        else:
            self._close_review_comment(thread["id"], comment["id"], delete_review_comments)
cpp_linter/clang_tools/patcher.py (2)

132-134: Consider improving readability of the condition

The condition could be more readable by breaking it down into smaller parts or using intermediate variables.

Consider this refactor:

-            if len(comments) and (
-                posted_tool_advice[tool_name] != self.tool_total[tool_name]
-                or self.tool_reused[tool_name] != 0
-            ):
+            has_comments = len(comments) > 0
+            has_unposted_concerns = posted_tool_advice[tool_name] != self.tool_total[tool_name]
+            has_reused_concerns = self.tool_reused[tool_name] != 0
+            if has_comments and (has_unposted_concerns or has_reused_concerns):

154-178: Consider adding input validation for existing review comments

The remove_reused_suggestions method processes existing review comments without explicit validation. Consider adding validation to ensure the safety of processing user-provided content.

Consider:

  1. Validating the structure and content of existing review comments
  2. Adding length limits for comments
  3. Sanitizing or escaping special characters in comments
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a911d69 and e72ddd6.

📒 Files selected for processing (2)
  • cpp_linter/clang_tools/patcher.py (4 hunks)
  • cpp_linter/rest_api/github_api.py (7 hunks)
🧰 Additional context used
📓 Learnings (1)
cpp_linter/rest_api/github_api.py (1)
Learnt from: maoliver-amd
PR: cpp-linter/cpp-linter#131
File: cpp_linter/rest_api/github_api.py:0-0
Timestamp: 2024-12-09T09:50:38.136Z
Learning: In `cpp_linter/rest_api/github_api.py`, when using the GitHub GraphQL API, the maximum allowable pagination limit for `first` and `last` parameters is 100.
🔇 Additional comments (3)
cpp_linter/rest_api/github_api.py (1)

40-92: Well-structured GraphQL queries with proper pagination limits!

The implementation follows GraphQL best practices with proper variable usage and pagination limits. The maximum limit of 100 is correctly used for both review threads and comments, which aligns with GitHub's API limitations.

cpp_linter/clang_tools/patcher.py (2)

75-80: LGTM! Well-structured addition of reused concerns tracking

The new tool_reused dictionary follows the established pattern and is properly documented.


168-177: Correct the condition when updating 'clang-format' counts

The condition for updating the clang-format counts incorrectly checks clang_tidy_comments. It should check clang_format_comments to ensure accurate tracking.

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 17, 2024

Awesome! I'm just now falling asleep, so I'll take a look tomorrow. I also implemented paginated graphql on the upstream branch, but I haven't finished updating the tests to validate it.

Updating the test may be harder than I thought. This PR depends on the state of the PR being reviewed (first review, second review, etc). It might be easier to rewrite several simpler tests instead of 1 heavily parametrized test.

2bndy5
2bndy5 previously requested changes Dec 17, 2024
Copy link
Contributor

@2bndy5 2bndy5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maoliver-amd I'm curious. What is your preferred programming language?

I ask because if you enable pre-commit for this repo (in your local clone) or just run mypy, you'd see that there are typing errors. The reasons these errors go unnoticed here is because

  1. The CI workflow that runs pre-commit is not triggered by PR sync events (yet -- I will be changing that)
  2. The tests do not actually invoke code with typing errors or the dynamic runtime types happen to work in the tests.

@maoliver-amd
Copy link
Author

@maoliver-amd I'm curious. What is your preferred programming language?

Very much a C/C++ programmer, hence the interest in clang CI

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
cpp_linter/rest_api/github_api.py (1)

748-754: Simplify line number handling logic

The current implementation for handling line numbers is a bit complex. Consider using the null coalescing pattern for better readability.

Apply this diff:

-                        line_start = (
-                            comment.get("startLine", None)
-                            or comment.get("originalStartLine", None)
-                            or -1
-                        )
-                        line_end = comment.get("line", None) or comment["originalLine"]
+                        line_start = next((val for val in [
+                            comment.get("startLine"),
+                            comment.get("originalStartLine"),
+                            -1
+                        ] if val is not None), -1)
+                        line_end = comment.get("line") or comment["originalLine"]
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e72ddd6 and b8c08f2.

📒 Files selected for processing (2)
  • cpp_linter/clang_tools/patcher.py (4 hunks)
  • cpp_linter/rest_api/github_api.py (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cpp_linter/clang_tools/patcher.py
🧰 Additional context used
📓 Learnings (1)
cpp_linter/rest_api/github_api.py (1)
Learnt from: maoliver-amd
PR: cpp-linter/cpp-linter#131
File: cpp_linter/rest_api/github_api.py:0-0
Timestamp: 2024-12-09T09:50:38.136Z
Learning: In `cpp_linter/rest_api/github_api.py`, when using the GitHub GraphQL API, the maximum allowable pagination limit for `first` and `last` parameters is 100.
🔇 Additional comments (4)
cpp_linter/rest_api/github_api.py (4)

40-92: Well-structured GraphQL operations!

The GraphQL queries and mutations are well-defined with proper parameterization and pagination limits. The code follows GraphQL best practices and maintains good readability.


474-475: Clean implementation of review comment management!

The new parameters and logic for handling existing comments are well-implemented. The code maintains a clear flow and proper handling of review states.

Also applies to: 507-516


Line range hint 573-611: Good error handling and documentation!

The updated _dismiss_stale_reviews method has proper error handling and clear documentation. The addition of the ignored_reviews parameter is well-implemented.


624-629: 🛠️ Refactor suggestion

Consider using parameterized GraphQL queries

The GraphQL query construction should use variables to prevent potential injection risks.

Apply this diff:

-            data=json.dumps({"query": query, "variables": variables}),
+            data=json.dumps({
+                "query": query,
+                "variables": variables,
+                "operationName": "GetReviewComments"
+            }),

Likely invalid or redundant comment.

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 18, 2024

@maoliver-amd I'm curious. What is your preferred programming language?

Very much a C/C++ programmer, hence the interest in clang CI

Ah yes. I should've guessed, but its better not to assume things about people. At least you understand the importance of static typing, even though python is a dynamically typed language.

FWIW, we'll be migrating to cpp-linter-rs, a rust port of this python project. Hopefully in the future, C/C++ aficionados will feel more at home tinkering with rust. I wouldn't have learned rust as easily as I did if I didn't understand the woes of C/C++ pointers beforehand.

I've also started porting this feature into cpp-linter-rs to maintain feature parity. We're pretty close to making the switch in cpp-linter-action v3.

@2bndy5 2bndy5 dismissed their stale review December 18, 2024 07:27

resolved

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 18, 2024

I'm beginning to think the new CLI option reuse-review-comments is unnecessary. I can't think of a use case where a user would actually want to allow duplicate comments in subsequent reviews. I understand it was added for backward compatibility, but the PR review feature (tidy-review specifically) has been rather experimental because I had not implemented a way to reuse the old/duplicate/unresolved comments. I think we should force enable the reuse of existing review comments because that would be a sane expected behavior.

The delete-review-comments option does make sense though. We don't want to impose destructive defaults on the user.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
cpp_linter/cli.py (1)

368-369: Fix grammatical error in help text.

The word "effects" should be "affects" as it's being used as a verb.

Apply this change:

-This only effects review comments made when either
+This only affects review comments made when either
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8c08f2 and 3b3cf1a.

📒 Files selected for processing (1)
  • cpp_linter/cli.py (2 hunks)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
cpp_linter/rest_api/github_api.py (1)

725-781: Consider breaking down the complex logic into smaller functions

While the implementation is correct, the method's complexity could be reduced by extracting some logic into helper functions:

  • Comment matching logic (lines 750-761)
  • Line number handling (lines 744-749)

Example refactor:

    def _check_reused_comments(
        self,
        delete_review_comments: bool,
        review_comments: ReviewComments,
    ) -> List[str]:
+       def _get_line_numbers(comment: Dict[str, Any]) -> Tuple[int, int]:
+           line_start = (
+               comment.get("startLine", None)
+               or comment.get("originalStartLine", None)
+               or -1
+           )
+           line_end = comment.get("line", None) or comment["originalLine"]
+           return line_start, line_end
+
+       def _is_matching_comment(
+           suggestion: Any,
+           comment: Dict[str, Any],
+           thread: Dict[str, Any],
+           line_start: int,
+           line_end: int,
+           existing_review_comments: List[Any]
+       ) -> bool:
+           return (
+               suggestion.file_name == comment["path"]
+               and suggestion.line_start == line_start
+               and suggestion.line_end == line_end
+               and f"{COMMENT_MARKER}{suggestion.comment}" == comment["body"]
+               and suggestion not in existing_review_comments
+               and thread["isResolved"] is False
+               and thread["isCollapsed"] is False
+               and comment["pullRequestReview"]["isMinimized"] is False
+           )

        ignored_reviews = []
        found_threads = self._get_existing_review_comments(
            no_dismissed=not delete_review_comments
        )
        if found_threads:
            existing_review_comments = []
            for thread in found_threads:
                for comment in thread["comments"]["nodes"]:
                    found = False
                    if "originalLine" not in comment:
                        raise ValueError(
                            "GraphQL response malformed: 'originalLine' missing in comment"
                        )
-                   line_start = (
-                       comment.get("startLine", None)
-                       or comment.get("originalStartLine", None)
-                       or -1
-                   )
-                   line_end = comment.get("line", None) or comment["originalLine"]
+                   line_start, line_end = _get_line_numbers(comment)
                    for suggestion in review_comments.suggestions:
-                       if (
-                           suggestion.file_name == comment["path"]
-                           and suggestion.line_start == line_start
-                           and suggestion.line_end == line_end
-                           and f"{COMMENT_MARKER}{suggestion.comment}"
-                           == comment["body"]
-                           and suggestion not in existing_review_comments
-                           and thread["isResolved"] is False
-                           and thread["isCollapsed"] is False
-                           and comment["pullRequestReview"]["isMinimized"] is False
-                       ):
+                       if _is_matching_comment(
+                           suggestion,
+                           comment,
+                           thread,
+                           line_start,
+                           line_end,
+                           existing_review_comments
+                       ):
                            found = True
                            logger.info(
                                "Using existing review comment: path='%s', line_start='%s', line_end='%s'",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b3cf1a and 005b25e.

📒 Files selected for processing (1)
  • cpp_linter/rest_api/github_api.py (7 hunks)
🧰 Additional context used
📓 Learnings (1)
cpp_linter/rest_api/github_api.py (1)
Learnt from: maoliver-amd
PR: cpp-linter/cpp-linter#131
File: cpp_linter/rest_api/github_api.py:0-0
Timestamp: 2024-12-09T09:50:38.136Z
Learning: In `cpp_linter/rest_api/github_api.py`, when using the GitHub GraphQL API, the maximum allowable pagination limit for `first` and `last` parameters is 100.
🔇 Additional comments (5)
cpp_linter/rest_api/github_api.py (5)

40-92: Well-structured GraphQL queries with proper parameterization

The implementation follows best practices with:

  • Proper parameterization using GraphQL variables
  • Correct pagination limits (100 is GitHub's maximum)
  • Clear separation of concerns between different operations (query vs mutations)

473-473: Well-documented method signature updates

The parameter additions are properly typed and documented:

  • delete_review_comments: bool = True in post_review
  • ignored_reviews: Optional[List[str]] = None in _dismiss_stale_reviews

Also applies to: 571-579


610-656: Robust implementation with proper error handling

The method effectively retrieves review comments with:

  • Proper GraphQL error handling using try-except
  • Clear documentation of parameters
  • Efficient filtering of comments

658-690: Clean implementation with proper logging

The method effectively handles both resolving and deleting comments with:

  • Clear parameter documentation
  • Proper error handling
  • Consistent logging format

692-724: Effective implementation for hiding stale reviews

The method properly handles:

  • Pagination of review comments
  • GraphQL mutation for minimizing comments
  • Proper logging of operations

@2bndy5
Copy link
Contributor

2bndy5 commented Dec 18, 2024

Going forward

The current state of this PR looks good except for the tests. I can take care of the tests, but I will do so from the hide-reuse-reviews branch upstream. This upstream branch retains the git history of this PR plus my modifications:

  • rebased on upstream main.
  • fixing the current tests. The PR review tests will have to be rewritten for complete patch coverage.
  • introduce paginated GraphQL requests. I also serialized the response data into data structures to avoid repeatedly type checking the raw JSON.

@maoliver-amd I cannot merge this into main without rewriting the PR reviews test. Therefore, I'll close this PR and open a new one using the hide-reuse-reviews branch. I don't expect you to help with the test rewrite, but you can (if you want) by submitting a PR to the hide-reuse-reviews branch.

Thank you for putting us on the right path here! 😍

@2bndy5 2bndy5 closed this Dec 18, 2024
@2bndy5 2bndy5 mentioned this pull request Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants