Send email notifications and fire Gerrit event if comments are posted via email

Change-Id: I4121b8d8b13f9a675fc227a81f6543501b3084f6
This commit is contained in:
Patrick Hiesel
2017-02-07 08:41:32 +01:00
parent c76731bbef
commit 1fce31c863
3 changed files with 93 additions and 11 deletions

View File

@@ -208,6 +208,35 @@ public class MailProcessorIT extends AbstractDaemonTest {
gApi.accounts().id("user").setActive(true);
}
@Test
public void sendNotificationAfterPersistingComments() throws Exception {
String changeId = createChangeWithReview();
ChangeInfo changeInfo = gApi.changes().id(changeId).get();
List<CommentInfo> comments = gApi.changes().id(changeId).current().commentsAsList();
assertThat(comments).hasSize(2);
String ts =
MailUtil.rfcDateformatter.format(
ZonedDateTime.ofInstant(comments.get(0).updated.toInstant(), ZoneId.of("UTC")));
// Build Message
String txt =
newPlaintextBody(
canonicalWebUrl.get() + "#/c/" + changeInfo._number + "/1",
"Test Message",
null,
null,
null);
MailMessage.Builder b =
messageBuilderWithDefaultFields()
.from(user.emailAddress)
.textContent(txt + textFooterForChange(changeId, ts));
sender.clear();
mailProcessor.process(b.build());
assertNotifyTo(admin);
}
private static CommentInput newComment(String path, Side side, int line, String message) {
CommentInput c = new CommentInput();
c.path = path;

View File

@@ -49,7 +49,7 @@ import org.slf4j.LoggerFactory;
public class EmailReviewComments implements Runnable, RequestContext {
private static final Logger log = LoggerFactory.getLogger(EmailReviewComments.class);
interface Factory {
public interface Factory {
EmailReviewComments create(
NotifyHandling notify,
ListMultimap<RecipientType, Account.Id> accountsToNotify,
@@ -111,7 +111,7 @@ public class EmailReviewComments implements Runnable, RequestContext {
this.labels = labels;
}
void sendAsync() {
public void sendAsync() {
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError = sendEmailsExecutor.submit(this);
}

View File

@@ -15,7 +15,10 @@
package com.google.gerrit.server.mail.receive;
import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestApiException;
@@ -28,16 +31,19 @@ import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.CommentsUtil;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.account.AccountByEmailCache;
import com.google.gerrit.server.change.EmailReviewComments;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.extensions.events.CommentAdded;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.mail.MailFilter;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.server.util.ManualRequestContext;
@@ -48,8 +54,10 @@ import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
@@ -69,6 +77,9 @@ public class MailProcessor {
private final Provider<InternalChangeQuery> queryProvider;
private final Provider<ReviewDb> reviewDb;
private final DynamicMap<MailFilter> mailFilters;
private final EmailReviewComments.Factory outgoingMailFactory;
private final CommentAdded commentAdded;
private final ApprovalsUtil approvalsUtil;
private final Provider<String> canonicalUrl;
@Inject
@@ -83,6 +94,9 @@ public class MailProcessor {
Provider<InternalChangeQuery> queryProvider,
Provider<ReviewDb> reviewDb,
DynamicMap<MailFilter> mailFilters,
EmailReviewComments.Factory outgoingMailFactory,
ApprovalsUtil approvalsUtil,
CommentAdded commentAdded,
@CanonicalWebUrl Provider<String> canonicalUrl) {
this.accountByEmailCache = accountByEmailCache;
this.buf = buf;
@@ -94,6 +108,9 @@ public class MailProcessor {
this.queryProvider = queryProvider;
this.reviewDb = reviewDb;
this.mailFilters = mailFilters;
this.outgoingMailFactory = outgoingMailFactory;
this.commentAdded = commentAdded;
this.approvalsUtil = approvalsUtil;
this.canonicalUrl = canonicalUrl;
}
@@ -192,6 +209,10 @@ public class MailProcessor {
private final PatchSet.Id psId;
private final List<MailComment> parsedComments;
private final String tag;
private ChangeMessage changeMessage;
private List<Comment> comments;
private PatchSet patchSet;
private ChangeControl changeControl;
private Op(PatchSet.Id psId, List<MailComment> parsedComments, String messageId) {
this.psId = psId;
@@ -200,10 +221,11 @@ public class MailProcessor {
}
@Override
public boolean updateChange(ChangeContext ctx)
public boolean updateChange(BatchUpdate.ChangeContext ctx)
throws OrmException, UnprocessableEntityException {
PatchSet ps = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
if (ps == null) {
changeControl = ctx.getControl();
patchSet = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
if (patchSet == null) {
throw new OrmException("patch set not found: " + psId);
}
@@ -217,10 +239,9 @@ public class MailProcessor {
changeMsg += "\n" + numComments(parsedComments.size());
}
ChangeMessage msg = ChangeMessagesUtil.newMessage(ctx, changeMsg, tag);
changeMessagesUtil.addChangeMessage(ctx.getDb(), ctx.getUpdate(psId), msg);
List<Comment> comments = new ArrayList<>();
changeMessage = ChangeMessagesUtil.newMessage(ctx, changeMsg, tag);
changeMessagesUtil.addChangeMessage(ctx.getDb(), ctx.getUpdate(psId), changeMessage);
comments = new ArrayList<>();
for (MailComment c : parsedComments) {
if (c.type == MailComment.CommentType.CHANGE_MESSAGE) {
continue;
@@ -241,7 +262,7 @@ public class MailProcessor {
side = Side.fromShort(c.inReplyTo.side);
} else {
fileName = c.fileName;
psForComment = ps;
psForComment = patchSet;
side = Side.REVISION;
}
@@ -272,6 +293,38 @@ public class MailProcessor {
return true;
}
@Override
public void postUpdate(BatchUpdate.Context ctx) throws Exception {
// Send email notifications
outgoingMailFactory
.create(
NotifyHandling.ALL,
ArrayListMultimap.create(),
changeControl.getNotes(),
patchSet,
ctx.getUser().asIdentifiedUser(),
changeMessage,
comments,
null,
ImmutableList.of())
.sendAsync();
// Get previous approvals from this user
Map<String, Short> approvals = new HashMap<>();
approvalsUtil
.byPatchSetUser(ctx.getDb(), changeControl, psId, ctx.getAccountId())
.forEach(a -> approvals.put(a.getLabel(), a.getValue()));
// Fire Gerrit event. Note that approvals can't be granted via email, so old and new approvals
// are always the same here.
commentAdded.fire(
changeControl.getChange(),
patchSet,
ctx.getAccount(),
changeMessage.getMessage(),
approvals,
approvals,
ctx.getWhen());
}
}
private static boolean useHtmlParser(MailMessage m) {