Refactor Rebase to use PatchSetInserter
Refactor the rebase to use the PatchSetInserter class.
The PatchSetInserter takes care of sending email notifications about
new patch sets, so remove the rebase-specific sender.
Change-Id: I1e05db299d03d6b4a9eec4ae5bca4cd62cf01a4f
diff --git a/Documentation/config-mail.txt b/Documentation/config-mail.txt
index 53c9750..6e333db 100644
--- a/Documentation/config-mail.txt
+++ b/Documentation/config-mail.txt
@@ -93,13 +93,6 @@
to a user submitting a new change for review. It is a `ChangeEmail`: see
`ChangeSubject.vm` and `ChangeFooter.vm`.
-RebasedPatchSet.vm
-~~~~~~~~~~~~~~~~~~
-
-The `RebasedPatchSet.vm` template will determine the contents of the email
-related to a user rebasing a patchset for a change through the Gerrit UI.
-It is a `ChangeEmail`: see `ChangeSubject.vm` and `ChangeFooter.vm`.
-
RegisterNewEmail.vm
~~~~~~~~~~~~~~~~~~~
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
index 415c55a..e71f3d1 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/SitePathInitializer.java
@@ -95,7 +95,6 @@
extractMailExample("Merged.vm");
extractMailExample("MergeFail.vm");
extractMailExample("NewChange.vm");
- extractMailExample("RebasedPatchSet.vm");
extractMailExample("RegisterNewEmail.vm");
extractMailExample("ReplacePatchSet.vm");
extractMailExample("Restored.vm");
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
index abba89f..ccbe365 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java
@@ -14,36 +14,25 @@
package com.google.gerrit.server.changedetail;
-import com.google.common.collect.Sets;
-import com.google.gerrit.common.ChangeHookRunner;
import com.google.gerrit.common.errors.EmailException;
-import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.client.ChangeMessage;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetAncestor;
-import com.google.gerrit.reviewdb.client.PatchSetApproval;
-import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.change.PatchSetInserter;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.index.ChangeIndexer;
-import com.google.gerrit.server.mail.RebasedPatchSetSender;
-import com.google.gerrit.server.mail.ReplacePatchSetSender;
-import com.google.gerrit.server.patch.PatchSetInfoFactory;
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.project.ProjectCache;
-import com.google.gwtorm.server.AtomicUpdate;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -53,53 +42,36 @@
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.merge.ThreeWayMerger;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import java.io.IOException;
-import java.sql.Timestamp;
-import java.util.Collections;
import java.util.List;
-import java.util.Set;
public class RebaseChange {
private final ChangeControl.GenericFactory changeControlFactory;
- private final PatchSetInfoFactory patchSetInfoFactory;
private final ReviewDb db;
private final GitRepositoryManager gitManager;
private final PersonIdent myIdent;
- private final GitReferenceUpdated gitRefUpdated;
- private final RebasedPatchSetSender.Factory rebasedPatchSetSenderFactory;
- private final ChangeHookRunner hooks;
private final MergeUtil.Factory mergeUtilFactory;
- private final ProjectCache projectCache;
- private final ChangeIndexer indexer;
+ private final PatchSetInserter.Factory patchSetInserterFactory;
@Inject
RebaseChange(final ChangeControl.GenericFactory changeControlFactory,
- final PatchSetInfoFactory patchSetInfoFactory, final ReviewDb db,
+ final ReviewDb db,
@GerritPersonIdent final PersonIdent myIdent,
final GitRepositoryManager gitManager,
- final GitReferenceUpdated gitRefUpdated,
- final RebasedPatchSetSender.Factory rebasedPatchSetSenderFactory,
- final ChangeHookRunner hooks,
final MergeUtil.Factory mergeUtilFactory,
- final ProjectCache projectCache,
- final ChangeIndexer changeIndexer) {
+ final ChangeIndexer changeIndexer,
+ final PatchSetInserter.Factory patchSetInserterFactory) {
this.changeControlFactory = changeControlFactory;
- this.patchSetInfoFactory = patchSetInfoFactory;
this.db = db;
this.gitManager = gitManager;
this.myIdent = myIdent;
- this.gitRefUpdated = gitRefUpdated;
- this.rebasedPatchSetSenderFactory = rebasedPatchSetSenderFactory;
- this.hooks = hooks;
this.mergeUtilFactory = mergeUtilFactory;
- this.projectCache = projectCache;
- this.indexer = changeIndexer;
+ this.patchSetInserterFactory = patchSetInserterFactory;
}
/**
@@ -148,9 +120,6 @@
rw = new RevWalk(git);
inserter = git.newObjectInserter();
- final List<PatchSetApproval> oldPatchSetApprovals =
- db.patchSetApprovals().byChange(change.getId()).toList();
-
final String baseRev = findBaseRevision(patchSetId, db,
change.getDest(), git, null, null, null);
final RevCommit baseCommit =
@@ -160,29 +129,10 @@
uploader.newCommitterIdent(myIdent.getWhen(),
myIdent.getTimeZone());
- final PatchSet newPatchSet = rebase(git, rw, inserter, patchSetId, change,
- uploader.getAccountId(), baseCommit, mergeUtilFactory.create(
+ rebase(git, rw, inserter, patchSetId, change,
+ uploader, baseCommit, mergeUtilFactory.create(
changeControl.getProjectControl().getProjectState(), true),
- committerIdent, indexer);
-
- final Set<Account.Id> oldReviewers = Sets.newHashSet();
- final Set<Account.Id> oldCC = Sets.newHashSet();
- for (PatchSetApproval a : oldPatchSetApprovals) {
- if (a.getValue() != 0) {
- oldReviewers.add(a.getAccountId());
- } else {
- oldCC.add(a.getAccountId());
- }
- }
- final ReplacePatchSetSender cm =
- rebasedPatchSetSenderFactory.create(change);
- cm.setFrom(uploader.getAccountId());
- cm.setPatchSet(newPatchSet);
- cm.addReviewers(oldReviewers);
- cm.addExtraCC(oldCC);
- cm.send();
-
- hooks.doPatchsetCreatedHook(change, newPatchSet, db);
+ committerIdent, true, true);
} catch (PathConflictException e) {
throw new IOException(e.getMessage());
} finally {
@@ -294,18 +244,20 @@
*
* The rebased commit is added as new patch set to the change.
*
- * E-mail notification and triggering of hooks is NOT done for the creation of
- * the new patch set.
+ * E-mail notification and triggering of hooks is only done for the creation of
+ * the new patch set if `sendEmail` and `runHooks` are set to true.
*
* @param git the repository
* @param revWalk the RevWalk
* @param inserter the object inserter
* @param patchSetId the id of the patch set
- * @param chg the change that should be rebased
+ * @param change the change that should be rebased
* @param uploader the user that creates the rebased patch set
* @param baseCommit the commit that should be the new base
* @param mergeUtil merge utilities for the destination project
- * @param indexer helper for indexing the change
+ * @param committerIdent the committer's identity
+ * @param sendMail if a mail notification should be sent for the new patch set
+ * @param runHooks if hooks should be run for the new patch set
* @return the new patch set which is based on the given base commit
* @throws NoSuchChangeException thrown if the change to which the patch set
* belongs does not exist or is not visible to the user
@@ -315,13 +267,13 @@
*/
public PatchSet rebase(final Repository git, final RevWalk revWalk,
final ObjectInserter inserter, final PatchSet.Id patchSetId,
- final Change chg, final Account.Id uploader, final RevCommit baseCommit,
+ final Change change, final IdentifiedUser uploader, final RevCommit baseCommit,
final MergeUtil mergeUtil, PersonIdent committerIdent,
- final ChangeIndexer indexer) throws NoSuchChangeException,
+ boolean sendMail, boolean runHooks)
+ throws NoSuchChangeException,
OrmException, IOException, InvalidChangeOperationException,
PathConflictException {
- Change change = chg;
- if (!chg.currentPatchSetId().equals(patchSetId)) {
+ if (!change.currentPatchSetId().equals(patchSetId)) {
throw new InvalidChangeOperationException("patch set is not current");
}
final PatchSet originalPatchSet = db.patchSets().get(patchSetId);
@@ -333,81 +285,27 @@
rebasedCommit = revWalk.parseCommit(newId);
- PatchSet.Id id = ChangeUtil.nextPatchSetId(git, change.currentPatchSetId());
- final PatchSet newPatchSet = new PatchSet(id);
- newPatchSet.setCreatedOn(new Timestamp(System.currentTimeMillis()));
- newPatchSet.setUploader(uploader);
- newPatchSet.setRevision(new RevId(rebasedCommit.name()));
- newPatchSet.setDraft(originalPatchSet.isDraft());
+ final ChangeControl changeControl =
+ changeControlFactory.validateFor(change.getId(), uploader);
- final PatchSetInfo info =
- patchSetInfoFactory.get(rebasedCommit, newPatchSet.getId());
+ PatchSetInserter patchSetinserter = patchSetInserterFactory
+ .create(git, revWalk, changeControl.getRefControl(), change, rebasedCommit)
+ .setCopyLabels(true)
+ .setDraft(originalPatchSet.isDraft())
+ .setSendMail(sendMail)
+ .setRunHooks(runHooks);
- final RefUpdate ru = git.updateRef(newPatchSet.getRefName());
- ru.setExpectedOldObjectId(ObjectId.zeroId());
- ru.setNewObjectId(rebasedCommit);
- ru.disableRefLog();
- if (ru.update(revWalk) != RefUpdate.Result.NEW) {
- throw new IOException(String.format("Failed to create ref %s in %s: %s",
- newPatchSet.getRefName(), change.getDest().getParentKey().get(),
- ru.getResult()));
- }
- gitRefUpdated.fire(change.getProject(), ru);
+ final ChangeMessage cmsg =
+ new ChangeMessage(new ChangeMessage.Key(change.getId(),
+ ChangeUtil.messageUUID(db)), uploader.getAccountId(), patchSetId);
+ cmsg.setMessage("Patch Set " + change.currentPatchSetId().get()
+ + ": Patch Set " + patchSetId.get() + " was rebased");
- db.changes().beginTransaction(change.getId());
- try {
- Change updatedChange = db.changes().get(change.getId());
- if (updatedChange != null && change.getStatus().isOpen()) {
- change = updatedChange;
- } else {
- throw new InvalidChangeOperationException(String.format(
- "Change %s is closed", change.getId()));
- }
+ Change newChange = patchSetinserter
+ .setMessage(cmsg)
+ .insert();
- ChangeUtil.insertAncestors(db, newPatchSet.getId(), rebasedCommit);
- db.patchSets().insert(Collections.singleton(newPatchSet));
- updatedChange =
- db.changes().atomicUpdate(change.getId(), new AtomicUpdate<Change>() {
- @Override
- public Change update(Change change) {
- if (change.getStatus().isClosed()) {
- return null;
- }
- if (!change.currentPatchSetId().equals(patchSetId)) {
- return null;
- }
- if (change.getStatus() != Change.Status.DRAFT) {
- change.setStatus(Change.Status.NEW);
- }
- change.setLastSha1MergeTested(null);
- change.setCurrentPatchSet(info);
- ChangeUtil.updated(change);
- return change;
- }
- });
- if (updatedChange != null) {
- change = updatedChange;
- } else {
- throw new InvalidChangeOperationException(String.format(
- "Change %s was modified", change.getId()));
- }
-
- indexer.index(change);
- ApprovalsUtil.copyLabels(db, projectCache.get(change.getProject())
- .getLabelTypes(), patchSetId, change.currentPatchSetId());
-
- final ChangeMessage cmsg =
- new ChangeMessage(new ChangeMessage.Key(change.getId(),
- ChangeUtil.messageUUID(db)), uploader, patchSetId);
- cmsg.setMessage("Patch Set " + change.currentPatchSetId().get()
- + ": Patch Set " + patchSetId.get() + " was rebased");
- db.changeMessages().insert(Collections.singleton(cmsg));
- db.commit();
- } finally {
- db.rollback();
- }
-
- return newPatchSet;
+ return db.patchSets().get(newChange.currentPatchSetId());
}
/**
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 2e69ff0..56f13be 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -87,7 +87,6 @@
import com.google.gerrit.server.mail.FromAddressGeneratorProvider;
import com.google.gerrit.server.mail.MergeFailSender;
import com.google.gerrit.server.mail.MergedSender;
-import com.google.gerrit.server.mail.RebasedPatchSetSender;
import com.google.gerrit.server.mail.RegisterNewEmailSender;
import com.google.gerrit.server.mail.ReplacePatchSetSender;
import com.google.gerrit.server.mail.VelocityRuntimeProvider;
@@ -191,7 +190,6 @@
factory(PluginUser.Factory.class);
factory(ProjectNode.Factory.class);
factory(ProjectState.Factory.class);
- factory(RebasedPatchSetSender.Factory.class);
factory(RegisterNewEmailSender.Factory.class);
factory(ReplacePatchSetSender.Factory.class);
factory(PerformCreateProject.Factory.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseIfNecessary.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseIfNecessary.java
index 0518349..d237f49 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseIfNecessary.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/RebaseIfNecessary.java
@@ -18,6 +18,7 @@
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.changedetail.PathConflictException;
import com.google.gerrit.server.changedetail.RebaseChange;
import com.google.gerrit.server.project.InvalidChangeOperationException;
@@ -76,11 +77,14 @@
} else {
try {
+ final IdentifiedUser uploader =
+ args.identifiedUserFactory.create(
+ args.mergeUtil.getSubmitter(n.patchsetId).getAccountId());
final PatchSet newPatchSet =
rebaseChange.rebase(args.repo, args.rw, args.inserter,
- n.patchsetId, n.change,
- args.mergeUtil.getSubmitter(n.patchsetId).getAccountId(),
- newMergeTip, args.mergeUtil, committerIdent, args.indexer);
+ n.patchsetId, n.change, uploader,
+ newMergeTip, args.mergeUtil, committerIdent,
+ false, false);
List<PatchSetApproval> approvals = Lists.newArrayList();
for (PatchSetApproval a : args.mergeUtil.getApprovalsForCommit(n)) {
approvals.add(new PatchSetApproval(newPatchSet.getId(), a));
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RebasedPatchSetSender.java b/gerrit-server/src/main/java/com/google/gerrit/server/mail/RebasedPatchSetSender.java
deleted file mode 100644
index f9a85b9..0000000
--- a/gerrit-server/src/main/java/com/google/gerrit/server/mail/RebasedPatchSetSender.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.server.mail;
-
-import com.google.gerrit.common.errors.EmailException;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.inject.Inject;
-import com.google.inject.assistedinject.Assisted;
-
-/** Send notice to reviewers that a change has been rebased. */
-public class RebasedPatchSetSender extends ReplacePatchSetSender {
- public static interface Factory {
- RebasedPatchSetSender create(Change change);
- }
-
- @Inject
- public RebasedPatchSetSender(EmailArguments ea, @Assisted Change c) {
- super(ea, c);
- }
-
- @Override
- protected void formatChange() throws EmailException {
- appendText(velocifyFile("RebasedPatchSet.vm"));
- }
-}
diff --git a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/RebasedPatchSet.vm b/gerrit-server/src/main/resources/com/google/gerrit/server/mail/RebasedPatchSet.vm
deleted file mode 100644
index e761627..0000000
--- a/gerrit-server/src/main/resources/com/google/gerrit/server/mail/RebasedPatchSet.vm
+++ /dev/null
@@ -1,54 +0,0 @@
-## Copyright (C) 2012 The Android Open Source Project
-##
-## Licensed under the Apache License, Version 2.0 (the "License");
-## you may not use this file except in compliance with the License.
-## You may obtain a copy of the License at
-##
-## http://www.apache.org/licenses/LICENSE-2.0
-##
-## Unless required by applicable law or agreed to in writing, software
-## distributed under the License is distributed on an "AS IS" BASIS,
-## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-## See the License for the specific language governing permissions and
-## limitations under the License.
-##
-##
-## Template Type:
-## -------------
-## This is a velocity mail template, see: http://velocity.apache.org and the
-## gerrit-docs:config-mail.txt for more info on modifying gerrit mail templates.
-##
-## Template File Names and extensions:
-## ----------------------------------
-## Gerrit will use templates ending in ".vm" but will ignore templates ending
-## in ".vm.example". If a .vm template does not exist, the default internal
-## gerrit template which is the same as the .vm.example will be used. If you
-## want to override the default template, copy the .vm.example file to a .vm
-## file and edit it appropriately.
-##
-## This Template:
-## --------------
-## The RebasedPatchSet.vm template will determine the contents of the email
-## related to a user rebasing a patchset for a change through the Gerrit UI.
-## It is a ChangeEmail: see ChangeSubject.vm and ChangeFooter.vm.
-##
-#if($email.reviewerNames)
-Hello $email.joinStrings($email.reviewerNames, ', '),
-
-I'd like you to reexamine a rebased change.#if($email.changeUrl) Please visit
-
- $email.changeUrl
-
-to look at the new rebased patch set (#$patchSet.patchSetId).
-#end
-#else
-$fromName has created a new patch set by issuing a rebase in Gerrit (#$patchSet.patchSetId).
-#end
-
-Change subject: $change.subject
-......................................................................
-
-$email.changeDetail
-#if($email.sshHost)
- git pull ssh://$email.sshHost/$projectName $patchSet.refName
-#end