summaryrefslogtreecommitdiffstats
path: root/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java')
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java149
1 files changed, 106 insertions, 43 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
index f3e28902e1..fdabcaaedb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PublishComments.java
@@ -14,26 +14,30 @@
package com.google.gerrit.server.patch;
-import com.google.gerrit.common.ChangeHookRunner;
+import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.data.ApprovalType;
import com.google.gerrit.common.data.ApprovalTypes;
-import com.google.gerrit.reviewdb.ApprovalCategory;
-import com.google.gerrit.reviewdb.ApprovalCategoryValue;
-import com.google.gerrit.reviewdb.Change;
-import com.google.gerrit.reviewdb.ChangeMessage;
-import com.google.gerrit.reviewdb.PatchLineComment;
-import com.google.gerrit.reviewdb.PatchSet;
-import com.google.gerrit.reviewdb.PatchSetApproval;
-import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.reviewdb.client.ApprovalCategory;
+import com.google.gerrit.reviewdb.client.ApprovalCategoryValue;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.ChangeMessage;
+import com.google.gerrit.reviewdb.client.PatchLineComment;
+import com.google.gerrit.reviewdb.client.PatchSet;
+import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.reviewdb.client.PatchSetInfo;
+import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.mail.CommentSender;
-import com.google.gerrit.server.mail.EmailException;
import com.google.gerrit.server.project.ChangeControl;
+import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException;
+import com.google.gerrit.server.util.RequestScopePropagator;
import com.google.gerrit.server.workflow.FunctionState;
-import com.google.gwtjsonrpc.client.VoidResult;
-import com.google.gwtorm.client.OrmException;
+import com.google.gwtjsonrpc.common.VoidResult;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -56,9 +60,10 @@ public class PublishComments implements Callable<VoidResult> {
public interface Factory {
PublishComments create(PatchSet.Id patchSetId, String messageText,
- Set<ApprovalCategoryValue.Id> approvals);
+ Set<ApprovalCategoryValue.Id> approvals, boolean forceMessage);
}
+ private final SchemaFactory<ReviewDb> schemaFactory;
private final ReviewDb db;
private final IdentifiedUser user;
private final ApprovalTypes types;
@@ -66,11 +71,14 @@ public class PublishComments implements Callable<VoidResult> {
private final PatchSetInfoFactory patchSetInfoFactory;
private final ChangeControl.Factory changeControlFactory;
private final FunctionState.Factory functionStateFactory;
- private final ChangeHookRunner hooks;
+ private final ChangeHooks hooks;
+ private final WorkQueue workQueue;
+ private final RequestScopePropagator requestScopePropagator;
private final PatchSet.Id patchSetId;
private final String messageText;
private final Set<ApprovalCategoryValue.Id> approvals;
+ private final boolean forceMessage;
private Change change;
private PatchSet patchSet;
@@ -78,17 +86,22 @@ public class PublishComments implements Callable<VoidResult> {
private List<PatchLineComment> drafts;
@Inject
- PublishComments(final ReviewDb db, final IdentifiedUser user,
+ PublishComments(final SchemaFactory<ReviewDb> sf, final ReviewDb db,
+ final IdentifiedUser user,
final ApprovalTypes approvalTypes,
final CommentSender.Factory commentSenderFactory,
final PatchSetInfoFactory patchSetInfoFactory,
final ChangeControl.Factory changeControlFactory,
final FunctionState.Factory functionStateFactory,
- final ChangeHookRunner hooks,
+ final ChangeHooks hooks,
+ final WorkQueue workQueue,
+ final RequestScopePropagator requestScopePropagator,
@Assisted final PatchSet.Id patchSetId,
@Assisted final String messageText,
- @Assisted final Set<ApprovalCategoryValue.Id> approvals) {
+ @Assisted final Set<ApprovalCategoryValue.Id> approvals,
+ @Assisted final boolean forceMessage) {
+ this.schemaFactory = sf;
this.db = db;
this.user = user;
this.types = approvalTypes;
@@ -97,14 +110,18 @@ public class PublishComments implements Callable<VoidResult> {
this.changeControlFactory = changeControlFactory;
this.functionStateFactory = functionStateFactory;
this.hooks = hooks;
+ this.workQueue = workQueue;
+ this.requestScopePropagator = requestScopePropagator;
this.patchSetId = patchSetId;
this.messageText = messageText;
this.approvals = approvals;
+ this.forceMessage = forceMessage;
}
@Override
- public VoidResult call() throws NoSuchChangeException, OrmException {
+ public VoidResult call() throws NoSuchChangeException,
+ InvalidChangeOperationException, OrmException {
final Change.Id changeId = patchSetId.getParentKey();
final ChangeControl ctl = changeControlFactory.validateFor(changeId);
change = ctl.getChange();
@@ -114,16 +131,25 @@ public class PublishComments implements Callable<VoidResult> {
}
drafts = drafts();
- publishDrafts();
+ db.changes().beginTransaction(changeId);
+ try {
+ publishDrafts();
+
+ final boolean isCurrent = patchSetId.equals(change.currentPatchSetId());
+ if (isCurrent && change.getStatus().isOpen()) {
+ publishApprovals(ctl);
+ } else if (approvals.isEmpty() || forceMessage) {
+ publishMessageOnly();
+ } else {
+ throw new InvalidChangeOperationException("Change is closed");
+ }
- final boolean isCurrent = patchSetId.equals(change.currentPatchSetId());
- if (isCurrent && change.getStatus().isOpen()) {
- publishApprovals();
- } else {
- publishMessageOnly();
+ touchChange();
+ db.commit();
+ } finally {
+ db.rollback();
}
- touchChange();
email();
fireHook();
return VoidResult.INSTANCE;
@@ -137,7 +163,8 @@ public class PublishComments implements Callable<VoidResult> {
db.patchComments().update(drafts);
}
- private void publishApprovals() throws OrmException {
+ private void publishApprovals(ChangeControl ctl)
+ throws InvalidChangeOperationException, OrmException {
ChangeUtil.updated(change);
final Set<ApprovalCategory.Id> dirty = new HashSet<ApprovalCategory.Id>();
@@ -165,13 +192,20 @@ public class PublishComments implements Callable<VoidResult> {
// Normalize all of the items the user is changing.
//
final FunctionState functionState =
- functionStateFactory.create(change, patchSetId, all);
+ functionStateFactory.create(ctl, patchSetId, all);
for (final ApprovalCategoryValue.Id want : approvals) {
final PatchSetApproval a = mine.get(want.getParentKey());
final short o = a.getValue();
a.setValue(want.get());
a.cache(change);
- functionState.normalize(types.getApprovalType(a.getCategoryId()), a);
+ if (!ApprovalCategory.SUBMIT.equals(a.getCategoryId())) {
+ functionState.normalize(types.byId(a.getCategoryId()), a);
+ }
+ if (want.get() != a.getValue()) {
+ throw new InvalidChangeOperationException(
+ types.byId(a.getCategoryId()).getCategory().getLabelName()
+ + "=" + want.get() + " not permitted");
+ }
if (o != a.getValue()) {
// Value changed, ensure we update the database.
//
@@ -249,7 +283,7 @@ public class PublishComments implements Callable<VoidResult> {
msgbuf.append(messageText != null ? messageText : "");
message = new ChangeMessage(new ChangeMessage.Key(change.getId(),//
- ChangeUtil.messageUUID(db)), user.getAccountId());
+ ChangeUtil.messageUUID(db)), user.getAccountId(), patchSetId);
message.setMessage(msgbuf.toString());
db.changeMessages().insert(Collections.singleton(message));
}
@@ -274,32 +308,61 @@ public class PublishComments implements Callable<VoidResult> {
}
private List<PatchLineComment> drafts() throws OrmException {
- return db.patchComments().draft(patchSetId, user.getAccountId()).toList();
+ return db.patchComments().draftByPatchSetAuthor(patchSetId, user.getAccountId()).toList();
}
private void email() {
- try {
- final CommentSender cm = commentSenderFactory.create(change);
- cm.setFrom(user.getAccountId());
- cm.setPatchSet(patchSet, patchSetInfoFactory.get(patchSetId));
- cm.setChangeMessage(message);
- cm.setPatchLineComments(drafts);
- cm.send();
- } catch (EmailException e) {
- log.error("Cannot send comments by email for patch set " + patchSetId, e);
- } catch (PatchSetInfoNotAvailableException e) {
- log.error("Failed to obtain PatchSetInfo for patch set " + patchSetId, e);
+ if (message == null) {
+ return;
}
+
+ workQueue.getDefaultQueue()
+ .submit(requestScopePropagator.wrap(new Runnable() {
+ @Override
+ public void run() {
+ PatchSetInfo patchSetInfo;
+ try {
+ ReviewDb reviewDb = schemaFactory.open();
+ try {
+ patchSetInfo = patchSetInfoFactory.get(reviewDb, patchSetId);
+ } finally {
+ reviewDb.close();
+ }
+ } catch (PatchSetInfoNotAvailableException e) {
+ log.error("Cannot read PatchSetInfo of " + patchSetId, e);
+ return;
+ } catch (Exception e) {
+ log.error("Cannot email comments for " + patchSetId, e);
+ return;
+ }
+
+ try {
+ final CommentSender cm = commentSenderFactory.create(change);
+ cm.setFrom(user.getAccountId());
+ cm.setPatchSet(patchSet, patchSetInfo);
+ cm.setChangeMessage(message);
+ cm.setPatchLineComments(drafts);
+ cm.send();
+ } catch (Exception e) {
+ log.error("Cannot email comments for " + patchSetId, e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "send-email comments";
+ }
+ }));
}
- private void fireHook() {
+ private void fireHook() throws OrmException {
final Map<ApprovalCategory.Id, ApprovalCategoryValue.Id> changed =
new HashMap<ApprovalCategory.Id, ApprovalCategoryValue.Id>();
for (ApprovalCategoryValue.Id v : approvals) {
changed.put(v.getParentKey(), v);
}
- hooks.doCommentAddedHook(change, user.getAccount(), patchSet, messageText, changed);
+ hooks.doCommentAddedHook(change, user.getAccount(), patchSet, messageText, changed, db);
}
private void summarizeInlineComments(StringBuilder in) {