PostReviewOp: check all comments for stream events, including drafts
When checking what type of comments notification to perform to
stream-events, consider *ALL* published comments and not just the
ones passed as input.
This allows to fix a regression in v3.7 where the GUI stores
the patchset-level comments first as drafts and then publishes them.
Bug: Issue 16475
Release-Notes: Fix stream events message including comments created as draft
Change-Id: I2ac40bd8235fea5c0059e8ca4111d3b6bf266f5a
diff --git a/java/com/google/gerrit/server/restapi/change/PostReviewOp.java b/java/com/google/gerrit/server/restapi/change/PostReviewOp.java
index 5ff0968..9274f52 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReviewOp.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReviewOp.java
@@ -193,14 +193,14 @@
// TODO(davido): Remove this workaround when patch set level comments are exposed in comment
// added event. For backwards compatibility, patchset level comment has a higher priority
// than change message and should be used as comment in comment added event.
- if (in.comments != null && in.comments.containsKey(PATCHSET_LEVEL)) {
- List<CommentInput> patchSetLevelComments = in.comments.get(PATCHSET_LEVEL);
- if (patchSetLevelComments != null && !patchSetLevelComments.isEmpty()) {
- CommentInput firstComment = patchSetLevelComments.get(0);
- if (!Strings.isNullOrEmpty(firstComment.message)) {
- comment = String.format("Patch Set %s:\n\n%s", psId.get(), firstComment.message);
- }
- }
+ String patchSetLevelComment =
+ comments.stream()
+ .filter(c -> c.key.filename.equals(PATCHSET_LEVEL))
+ .map(c -> Strings.nullToEmpty(c.message))
+ .collect(Collectors.joining("\n"))
+ .trim();
+ if (!patchSetLevelComment.isEmpty()) {
+ comment = String.format("Patch Set %s:\n\n%s", psId.get(), patchSetLevelComment);
}
}
commentAdded.fire(
diff --git a/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java b/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java
index 13a9e0c..80b8ff0 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java
@@ -15,6 +15,7 @@
package com.google.gerrit.acceptance.ssh;
import static com.google.gerrit.acceptance.WaitUtil.waitUntil;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import com.google.common.base.Splitter;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -22,13 +23,17 @@
import com.google.gerrit.acceptance.Sandboxed;
import com.google.gerrit.acceptance.UseSsh;
import com.google.gerrit.extensions.api.changes.ChangeApi;
+import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
+import com.google.gerrit.server.query.change.ChangeData;
import java.io.IOException;
import java.io.Reader;
import java.time.Duration;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.junit.After;
import org.junit.Before;
@@ -40,7 +45,9 @@
public class StreamEventsIT extends AbstractDaemonTest {
private static final Duration MAX_DURATION_FOR_RECEIVING_EVENTS = Duration.ofSeconds(2);
private static final String TEST_REVIEW_COMMENT = "any comment";
+ private static final String TEST_REVIEW_DRAFT_COMMENT = "any draft comment";
private Reader streamEventsReader;
+ private ChangeData change;
@Before
public void setup() throws Exception {
@@ -59,6 +66,23 @@
}
@Test
+ public void publishedDraftPatchSetLevelCommentShowsUpInStreamEvents() throws Exception {
+ change = createChange().getChange();
+
+ String firstDraftComment = String.format("%s 1", TEST_REVIEW_DRAFT_COMMENT);
+ String secondDraftComment = String.format("%s 2", TEST_REVIEW_DRAFT_COMMENT);
+
+ draftReviewChange(PATCHSET_LEVEL, firstDraftComment);
+ draftReviewChange(PATCHSET_LEVEL, secondDraftComment);
+ publishDraftReviews();
+
+ waitForEvent(
+ () ->
+ pollEventsContaining("comment-added", firstDraftComment, secondDraftComment).size()
+ == 1);
+ }
+
+ @Test
public void batchRefsUpdatedShowSeparatelyInStreamEvents() throws Exception {
String refName = createChange().getChange().currentPatchSet().refName();
waitForEvent(
@@ -77,7 +101,22 @@
changeApi.current().review(reviewInput);
}
- private List<String> pollEventsContaining(String eventType, String expectedContent) {
+ private void draftReviewChange(String path, String reviewMessage) throws Exception {
+ DraftInput draftInput = new DraftInput();
+ draftInput.message = reviewMessage;
+ draftInput.path = path;
+ ChangeApi changeApi = gApi.changes().id(change.getId().get());
+ changeApi.current().createDraft(draftInput).get();
+ }
+
+ private void publishDraftReviews() throws Exception {
+ ReviewInput reviewInput = new ReviewInput();
+ reviewInput.tag = "new_tag";
+ reviewInput.drafts = DraftHandling.PUBLISH;
+ gApi.changes().id(change.getId().get()).current().review(reviewInput);
+ }
+
+ private List<String> pollEventsContaining(String eventType, String... expectedContent) {
try {
char[] cbuf = new char[2048];
StringBuilder eventsOutput = new StringBuilder();
@@ -90,7 +129,7 @@
.filter(
event ->
event.contains(String.format("\"type\":\"%s\"", eventType))
- && event.contains(expectedContent))
+ && Stream.of(expectedContent).allMatch(event::contains))
.collect(Collectors.toList());
} catch (IOException e) {
throw new IllegalStateException(e);