diff options
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.java | 149 |
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) { |