Hide low-scoring review comments
Implemented a filter to hide positive or neutral review comments. The
filter is controlled by the `filterNegativeComments` configuration
setting, with the threshold for filtering customizable through the
`filterCommentsBelowScore` setting.
Jira-Id: IT-103
Change-Id: Iafb898d1fd35caa1a0579c0be1c78ed1a9ace227
Signed-off-by: Patrizio <patrizio.gelosi@amarulasolutions.com>
diff --git a/README.md b/README.md
index efd50d2..d18357e 100644
--- a/README.md
+++ b/README.md
@@ -149,6 +149,11 @@
.sh, .vb, .bat".
- `enabledVoting`: Initially disabled (false). If set to true, allows ChatGPT to cast a vote on each reviewed Patch Set
by assigning a score.
+- `filterNegativeComments`: Activated by default (true), ensuring only negative review comments (scored below the
+ `filterCommentsBelowScore` threshold outlined further) are displayed initially. Disabling this setting (false) will
+ also show positive and neutral comments.
+- `filterCommentsBelowScore`: With `filterNegativeComments` active, review comments with a score at or above this
+ setting's value are hidden (default is 0).
- `patchSetCommentsAsResolved`: Initially set to false, this option leaves ChatGPT's Patch Set comments as unresolved,
inviting further discussion. If activated, it marks ChatGPT's Patch Set comments as resolved.
- `inlineCommentsAsResolved`: Initially set to false, this option leaves ChatGPT's inline comments as unresolved,
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
index 22a6464..4c3b2a5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
@@ -27,6 +27,7 @@
private final GerritClient gerritClient;
private final ChatGptClient chatGptClient;
+ private Configuration config;
private GerritCommentRange gerritCommentRange;
private List<ReviewBatch> reviewBatches;
private List<GerritComment> commentProperties;
@@ -39,6 +40,7 @@
}
public void review(Configuration config, GerritChange change) throws Exception {
+ this.config = config;
reviewBatches = new ArrayList<>();
reviewScores = new ArrayList<>();
commentProperties = gerritClient.getClientData(change).getCommentProperties();
@@ -51,11 +53,11 @@
}
DynamicSettings.update(config, change, gerritClient);
- String reviewReply = getReviewReply(config, change, patchSet);
+ String reviewReply = getReviewReply(change, patchSet);
log.debug("ChatGPT response: {}", reviewReply);
retrieveReviewBatches(reviewReply, change);
- gerritClientReview.setReview(change.getFullChangeId(), reviewBatches, getReviewScore(config));
+ gerritClientReview.setReview(change.getFullChangeId(), reviewBatches, getReviewScore());
}
private void setCommentBatchMap(ReviewBatch batchMap, Integer batchID) {
@@ -94,7 +96,9 @@
if (!replyItem.isConflicting() && score != null) {
reviewScores.add(score);
}
- if (shouldFilterReplies && (replyItem.isRepeated() || replyItem.isConflicting())) {
+ if (shouldFilterReplies && (replyItem.isRepeated() || replyItem.isConflicting() ||
+ config.getFilterNegativeComments() && score != null &&
+ score >= config.getFilterCommentsBelowScore())) {
continue;
}
ReviewBatch batchMap = new ReviewBatch();
@@ -109,7 +113,7 @@
}
}
- private String getReviewReply(Configuration config, GerritChange change, String patchSet) throws Exception {
+ private String getReviewReply(GerritChange change, String patchSet) throws Exception {
List<String> patchLines = Arrays.asList(patchSet.split("\n"));
if (patchLines.size() > config.getMaxReviewLines()) {
log.warn("Patch set too large. Skipping review. changeId: {}", change.getFullChangeId());
@@ -118,7 +122,7 @@
return chatGptClient.ask(config, change, patchSet);
}
- private Integer getReviewScore(Configuration config) {
+ private Integer getReviewScore() {
return config.isVotingEnabled() && !reviewScores.isEmpty() ? Collections.min(reviewScores) : null;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java
index 29c37e8..f151fe3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java
@@ -83,7 +83,7 @@
public String getPatchSetReviewUserPrompt() {
List<String> attributes = new ArrayList<>(PATCH_SET_REVIEW_REPLY_ATTRIBUTES);
- if (config.isVotingEnabled()) {
+ if (config.isVotingEnabled() || config.getFilterNegativeComments()) {
updateScoreDescription();
}
else {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/config/Configuration.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/config/Configuration.java
index c71b3ee..1593e98 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/config/Configuration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/config/Configuration.java
@@ -63,6 +63,8 @@
private static final int DEFAULT_MAX_REVIEW_LINES = 1000;
private static final int DEFAULT_MAX_REVIEW_FILE_SIZE = 10000;
private static final boolean DEFAULT_ENABLED_VOTING = false;
+ private static final boolean DEFAULT_FILTER_NEGATIVE_COMMENTS = true;
+ private static final int DEFAULT_FILTER_COMMENTS_BELOW_SCORE = 0;
private static final int DEFAULT_VOTING_MIN_SCORE = -1;
private static final int DEFAULT_VOTING_MAX_SCORE = 1;
private static final boolean DEFAULT_INLINE_COMMENTS_AS_RESOLVED = false;
@@ -99,6 +101,8 @@
private static final String KEY_MAX_REVIEW_FILE_SIZE = "maxReviewFileSize";
private static final String KEY_ENABLED_FILE_EXTENSIONS = "enabledFileExtensions";
private static final String KEY_ENABLED_VOTING = "enabledVoting";
+ private static final String KEY_FILTER_NEGATIVE_COMMENTS = "filterNegativeComments";
+ private static final String KEY_FILTER_COMMENTS_BELOW_SCORE = "filterCommentsBelowScore";
private static final String KEY_INLINE_COMMENTS_AS_RESOLVED = "inlineCommentsAsResolved";
private static final String KEY_PATCH_SET_COMMENTS_AS_RESOLVED = "patchSetCommentsAsResolved";
private static final String KEY_IGNORE_OUTDATED_INLINE_COMMENTS = "ignoreOutdatedInlineComments";
@@ -206,6 +210,14 @@
return getBoolean(KEY_ENABLED_VOTING, DEFAULT_ENABLED_VOTING);
}
+ public boolean getFilterNegativeComments() {
+ return getBoolean(KEY_FILTER_NEGATIVE_COMMENTS, DEFAULT_FILTER_NEGATIVE_COMMENTS);
+ }
+
+ public int getFilterCommentsBelowScore() {
+ return getInt(KEY_FILTER_COMMENTS_BELOW_SCORE, DEFAULT_FILTER_COMMENTS_BELOW_SCORE);
+ }
+
public int getVotingMinScore() {
return getInt(KEY_VOTING_MIN_SCORE, DEFAULT_VOTING_MIN_SCORE);
}
diff --git a/src/test/resources/__files/gerritPatchSetReview.json b/src/test/resources/__files/gerritPatchSetReview.json
index ba22fe5..bf5f29a 100644
--- a/src/test/resources/__files/gerritPatchSetReview.json
+++ b/src/test/resources/__files/gerritPatchSetReview.json
@@ -1 +1 @@
-{"comments":{"test_file.py":[{"unresolved":true,"line":19,"range":{"start_line":19,"end_line":20,"start_character":4,"end_character":60},"message":"Confirm that the method \u0027importclass\u0027 is meant to change its behavior when \u0027class_name\u0027 is None. The new lines suggest \u0027class_name\u0027 will be derived from the \u0027module_name\u0027 in such cases, which can have unintended effects if not explicitly intended."},{"unresolved":true,"line":20,"range":{"start_line":20,"end_line":20,"start_character":8,"end_character":60},"message":"The added check to determine if \u0027class_name\u0027 is None seems to modify the \u0027module_name\u0027 by splitting it and taking the last element. There should be an assignment to \u0027class_name\u0027 since the class to be imported is meant to be the last part of \u0027module_name\u0027 after splitting. Additionally, it would be beneficial to include a comment like:\n\\# last element is..."},{"unresolved":true,"line":1,"range":{"start_line":1,"end_line":1,"start_character":0,"end_character":17},"message":"The code line \u0027from types import Any, Callable, ...\u0027 should use \u0027typing\u0027 for imports instead of \u0027types\u0027."},{"unresolved":true,"line":21,"range":{"start_line":21,"end_line":21,"start_character":4,"end_character":67},"message":"There is a typo in the import statement. The correct function should be \u0027\\__import\\__\u0027 from the \u0027importlib\u0027 module, not \u0027importclass\u0027 which does not exist. Correct code:\n\n```\nloaded_module \u003d import_module(module_name, fromlist\u003d[class_name])\n```\n"}],"/PATCHSET_LEVEL":[{"unresolved":true,"message":"The commit message \u0027Test Commit Message\u0027 is too vague and does not provide information about the specific changes made. A more detailed message is necessary to understand what has been fixed."}]},"labels":{"Code-Review":-1}}
\ No newline at end of file
+{"comments":{"test_file.py":[{"unresolved":true,"line":20,"range":{"start_line":20,"end_line":20,"start_character":8,"end_character":60},"message":"The added check to determine if \u0027class_name\u0027 is None seems to modify the \u0027module_name\u0027 by splitting it and taking the last element. There should be an assignment to \u0027class_name\u0027 since the class to be imported is meant to be the last part of \u0027module_name\u0027 after splitting. Additionally, it would be beneficial to include a comment like:\n\\# last element is..."},{"unresolved":true,"line":1,"range":{"start_line":1,"end_line":1,"start_character":0,"end_character":17},"message":"The code line \u0027from types import Any, Callable, ...\u0027 should use \u0027typing\u0027 for imports instead of \u0027types\u0027."},{"unresolved":true,"line":21,"range":{"start_line":21,"end_line":21,"start_character":4,"end_character":67},"message":"There is a typo in the import statement. The correct function should be \u0027\\__import\\__\u0027 from the \u0027importlib\u0027 module, not \u0027importclass\u0027 which does not exist. Correct code:\n\n```\nloaded_module \u003d import_module(module_name, fromlist\u003d[class_name])\n```\n"}],"/PATCHSET_LEVEL":[{"unresolved":true,"message":"The commit message \u0027Test Commit Message\u0027 is too vague and does not provide information about the specific changes made. A more detailed message is necessary to understand what has been fixed."}]},"labels":{"Code-Review":-1}}
\ No newline at end of file