Count unresolved threads within thread groups rather than by leaves
This is a partial cherry-pick of I2788fdb22. This only ports over the
Java part of the original change, which drives the Prolog fact. It
doesn't port the UI fix because of significant restructuring of the
gr-comment-api webcomponent.
Diff comments are threaded together based on the in_reply_to relation
(which potentially expresses a tree structure) but are always displayed
linearly in the UI. This means that some comments in the middle of a
linear thread may be actually stored as leaves of a tree.
For example, the following thread of comments can be created if comments
two and three are created at nearly the same time.
Comment 1: thread root, unresolved,
┣ Comment 2: in reply to comment 1, unresolved,
┗ Comment 3: also in reply to comment 1, unresolved,
┗ Comment 4: in reply to comment 3, resolved
Because the thread is flattened, the resolved state of the thread should
be determined by the state of the chronologically latest comment (#4),
resulting in this thread being considered as resolved.
However, in a couple of locations, the resolved state is counted
differently. Namely, it finds the "leaf" comments -- that is, the
comments that are not marked as the parent of any other comment -- and
the number of unresolved threads is determined as the number of
unresolved leaves.
This fixes the logic used in ChangeData#unresolvedCommentCount in the
Java server code, which determines, among other things, the value of the
unresolved_comment_count change detail property, as well as the Prolog
fact used by the Prolog recipe that requires all comments to be resolved
before a change can be submitted.
With this change, the unresolved thread logic is modified to group
comments into flat threads, and consider the resolved state of each one
based on the chronologically final comment, irregardless of the leaves.
Bug: Issue 8472
Change-Id: I2788fdb22ecfd56f0b3da763790a7732ec73be33
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index dfcc999..ba182d2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -18,7 +18,6 @@
import static com.google.gerrit.server.ApprovalsUtil.sortApprovals;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
-import static java.util.stream.Collectors.toSet;
import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
@@ -882,15 +881,48 @@
List<Comment> comments =
Stream.concat(publishedComments().stream(), robotComments().stream()).collect(toList());
- Set<String> nonLeafSet = comments.stream().map(c -> c.parentUuid).collect(toSet());
- Long count =
- comments.stream().filter(c -> (c.unresolved && !nonLeafSet.contains(c.key.uuid))).count();
- unresolvedCommentCount = count.intValue();
+ // Build a map of uuid to list of direct descendants.
+ Map<String, List<Comment>> forest = new HashMap<>();
+ for (Comment comment : comments) {
+ List<Comment> siblings = forest.get(comment.parentUuid);
+ if (siblings == null) {
+ siblings = new ArrayList<>();
+ forest.put(comment.parentUuid, siblings);
+ }
+ siblings.add(comment);
+ }
+
+ // Find latest comment in each thread and apply to unresolved counter.
+ int unresolved = 0;
+ if (forest.containsKey(null)) {
+ for (Comment root : forest.get(null)) {
+ if (getLatestComment(forest, root).unresolved) {
+ unresolved++;
+ }
+ }
+ }
+ unresolvedCommentCount = unresolved;
}
+
return unresolvedCommentCount;
}
+ protected Comment getLatestComment(Map<String, List<Comment>> forest, Comment root) {
+ List<Comment> children = forest.get(root.key.uuid);
+ if (children == null) {
+ return root;
+ }
+ Comment latest = null;
+ for (Comment comment : children) {
+ Comment branchLatest = getLatestComment(forest, comment);
+ if (latest == null || branchLatest.writtenOn.after(latest.writtenOn)) {
+ latest = branchLatest;
+ }
+ }
+ return latest;
+ }
+
public void setUnresolvedCommentCount(Integer count) {
this.unresolvedCommentCount = count;
}