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
This commit is contained in:
@@ -93,13 +93,6 @@ The `NewChange.vm` template will determine the contents of the email related
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@@ -95,7 +95,6 @@ public class SitePathInitializer {
|
||||
extractMailExample("Merged.vm");
|
||||
extractMailExample("MergeFail.vm");
|
||||
extractMailExample("NewChange.vm");
|
||||
extractMailExample("RebasedPatchSet.vm");
|
||||
extractMailExample("RegisterNewEmail.vm");
|
||||
extractMailExample("ReplacePatchSet.vm");
|
||||
extractMailExample("Restored.vm");
|
||||
|
@@ -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.ObjectId;
|
||||
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 @@ public class RebaseChange {
|
||||
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 @@ public class RebaseChange {
|
||||
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 @@ public class RebaseChange {
|
||||
*
|
||||
* 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 class RebaseChange {
|
||||
*/
|
||||
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 @@ public class RebaseChange {
|
||||
|
||||
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());
|
||||
|
||||
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);
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
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());
|
||||
PatchSetInserter patchSetinserter = patchSetInserterFactory
|
||||
.create(git, revWalk, changeControl.getRefControl(), change, rebasedCommit)
|
||||
.setCopyLabels(true)
|
||||
.setDraft(originalPatchSet.isDraft())
|
||||
.setSendMail(sendMail)
|
||||
.setRunHooks(runHooks);
|
||||
|
||||
final ChangeMessage cmsg =
|
||||
new ChangeMessage(new ChangeMessage.Key(change.getId(),
|
||||
ChangeUtil.messageUUID(db)), uploader, patchSetId);
|
||||
ChangeUtil.messageUUID(db)), uploader.getAccountId(), 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;
|
||||
Change newChange = patchSetinserter
|
||||
.setMessage(cmsg)
|
||||
.insert();
|
||||
|
||||
return db.patchSets().get(newChange.currentPatchSetId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -87,7 +87,6 @@ import com.google.gerrit.server.mail.FromAddressGenerator;
|
||||
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 @@ public class GerritGlobalModule extends FactoryModule {
|
||||
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);
|
||||
|
@@ -18,6 +18,7 @@ import com.google.common.collect.Lists;
|
||||
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 @@ public class RebaseIfNecessary extends SubmitStrategy {
|
||||
|
||||
} 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));
|
||||
|
@@ -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"));
|
||||
}
|
||||
}
|
@@ -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
|
Reference in New Issue
Block a user