Delete draft changes and patchsets

Adds ability to delete draft changes and patchsets that are not meant
or fit for code review. Deleting a draft patchset also deletes the
corresponding ref from the repository and decrements the next patch
set number for the change if necessary. Deleting a draft change
deletes all of its (draft) patchsets.

Change-Id: I04abeb67b64dd2366514e74d23f83066d409904e
This commit is contained in:
Jason Tsay
2011-08-12 16:02:36 -07:00
committed by Mohan Zhang
parent 61cdb499e6
commit 5a59261dc3
19 changed files with 364 additions and 6 deletions

View File

@@ -15,6 +15,7 @@ SYNOPSIS
[--submit]
[--abandon | --restore]
[--publish]
[--delete]
[--verified <N>] [--code-review <N>]
{COMMIT | CHANGEID,PATCHSET}...
@@ -82,7 +83,11 @@ successfully, even if the label could not be changed.
--publish::
Publish the specified draft patch set(s).
(option is mutually exclusive with --submit, --restore, and --abandon)
(option is mutually exclusive with --submit, --restore, --abandon, and --delete)
--delete::
Delete the specified draft patch set(s).
(option is mutually exclusive with --submit, --restore, --abandon, and --publish)
--code-review::
--verified::

View File

@@ -30,6 +30,7 @@ public class ChangeDetail {
protected boolean canAbandon;
protected boolean canRestore;
protected boolean canRevert;
protected boolean canDeleteDraft;
protected Change change;
protected boolean starred;
protected List<ChangeInfo> dependsOn;
@@ -94,6 +95,14 @@ public class ChangeDetail {
canSubmit = a;
}
public boolean canDeleteDraft() {
return canDeleteDraft;
}
public void setCanDeleteDraft(boolean a) {
canDeleteDraft = a;
}
public Change getChange() {
return change;
}

View File

@@ -20,6 +20,7 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtjsonrpc.client.RemoteJsonService;
import com.google.gwtjsonrpc.client.RpcImpl;
import com.google.gwtjsonrpc.client.RpcImpl.Version;
import com.google.gwtjsonrpc.client.VoidResult;
@RpcImpl(version = Version.V2_0)
public interface ChangeManageService extends RemoteJsonService {
@@ -40,4 +41,7 @@ public interface ChangeManageService extends RemoteJsonService {
@SignInRequired
void publish(PatchSet.Id patchSetId, AsyncCallback<ChangeDetail> callback);
@SignInRequired
void deleteDraftChange(PatchSet.Id patchSetId, AsyncCallback<VoidResult> callback);
}

View File

@@ -44,6 +44,9 @@ public interface PatchDetailService extends RemoteJsonService {
@SignInRequired
void deleteDraft(PatchLineComment.Key key, AsyncCallback<VoidResult> callback);
@SignInRequired
void deleteDraftPatchSet(PatchSet.Id psid, AsyncCallback<VoidResult> callback);
@SignInRequired
void publishComments(PatchSet.Id psid, String message,
Set<ApprovalCategoryValue.Id> approvals,

View File

@@ -140,6 +140,9 @@ public interface ChangeConstants extends Constants {
String buttonPublishPatchSet();
String buttonDeleteDraftChange();
String buttonDeleteDraftPatchSet();
String pagedChangeListPrev();
String pagedChangeListNext();

View File

@@ -117,6 +117,9 @@ headingPatchComments = Patch Comments:
buttonPublishPatchSet = Publish
buttonDeleteDraftChange = Delete Draft Change
buttonDeleteDraftPatchSet = Delete Draft Patch Set
pagedChangeListPrev = &#x21e6;Prev
pagedChangeListNext = Next&#x21e8;

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.client.changes;
import com.google.gerrit.client.Dispatcher;
import com.google.gerrit.client.FormatUtil;
import com.google.gerrit.client.Gerrit;
import com.google.gerrit.client.patches.PatchUtil;
import com.google.gerrit.client.rpc.GerritCallback;
import com.google.gerrit.client.ui.AccountDashboardLink;
import com.google.gerrit.client.ui.ComplexDisclosurePanel;
@@ -49,10 +50,11 @@ import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
import com.google.gwtexpui.clippy.client.CopyableLabel;
import com.google.gwtjsonrpc.client.VoidResult;
import java.util.HashSet;
import java.util.List;
@@ -179,6 +181,9 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
if (detail.getPatchSet().isDraft()) {
populatePublishAction();
}
if (canDeletePatchSet(detail)) {
populateDeleteDraftPatchSetAction();
}
}
populateDiffAllActions(detail);
body.add(patchTable);
@@ -490,6 +495,29 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
actionsPanel.add(b);
}
if (changeDetail.canDeleteDraft()) {
final Button b = new Button(Util.C.buttonDeleteDraftChange());
b.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
b.setEnabled(false);
Util.MANAGE_SVC.deleteDraftChange(patchSet.getId(),
new GerritCallback<VoidResult>() {
public void onSuccess(VoidResult result) {
Gerrit.display(PageLinks.MINE);
}
@Override
public void onFailure(Throwable caught) {
b.setEnabled(true);
super.onFailure(caught);
}
});
}
});
actionsPanel.add(b);
}
if (changeDetail.canRestore()) {
final Button b = new Button(Util.C.buttonRestoreChangeBegin());
b.addClickHandler(new ClickHandler() {
@@ -572,6 +600,29 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
actionsPanel.add(b);
}
private void populateDeleteDraftPatchSetAction() {
final Button b = new Button(Util.C.buttonDeleteDraftPatchSet());
b.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
b.setEnabled(false);
PatchUtil.DETAIL_SVC.deleteDraftPatchSet(patchSet.getId(),
new GerritCallback<VoidResult>() {
public void onSuccess(VoidResult result) {
Gerrit.display(PageLinks.MINE);
}
@Override
public void onFailure(Throwable caught) {
b.setEnabled(true);
super.onFailure(caught);
}
});
}
});
actionsPanel.add(b);
}
public void refresh() {
AccountDiffPreference diffPrefs;
if (patchTable == null) {
@@ -654,6 +705,17 @@ class PatchSetComplexDisclosurePanel extends ComplexDisclosurePanel implements O
changeScreen.update(result);
}
private boolean canDeletePatchSet(PatchSetDetail detail) {
if (!detail.getPatchSet().isDraft()) {
return false;
}
// If the draft PS is the only one in a draft change, just delete the change.
if (changeDetail.getPatchSets().size() <= 1) {
return false;
}
return true;
}
public PatchSet getPatchSet() {
return patchSet;
}

View File

@@ -121,8 +121,9 @@ public class ChangeDetailFactory extends Handler<ChangeDetail> {
detail.setChange(change);
detail.setAllowsAnonymous(control.forUser(anonymousUser).isVisible(db));
detail.setCanAbandon(change.getStatus().isOpen() && control.canAbandon());
detail.setCanAbandon(change.getStatus() != Change.Status.DRAFT && change.getStatus().isOpen() && control.canAbandon());
detail.setCanRestore(change.getStatus() == Change.Status.ABANDONED && control.canRestore());
detail.setCanDeleteDraft(change.getStatus() == Change.Status.DRAFT && control.isOwner());
detail.setStarred(control.getCurrentUser().getStarredChanges().contains(
changeId));

View File

@@ -18,6 +18,7 @@ import com.google.gerrit.common.data.ChangeDetail;
import com.google.gerrit.common.data.ChangeManageService;
import com.google.gerrit.reviewdb.PatchSet;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtjsonrpc.client.VoidResult;
import com.google.inject.Inject;
class ChangeManageServiceImpl implements ChangeManageService {
@@ -26,18 +27,21 @@ class ChangeManageServiceImpl implements ChangeManageService {
private final RestoreChange.Factory restoreChangeFactory;
private final RevertChange.Factory revertChangeFactory;
private final PublishAction.Factory publishAction;
private final DeleteDraftChange.Factory deleteDraftChangeFactory;
@Inject
ChangeManageServiceImpl(final SubmitAction.Factory patchSetAction,
final AbandonChange.Factory abandonChangeFactory,
final RestoreChange.Factory restoreChangeFactory,
final RevertChange.Factory revertChangeFactory,
final PublishAction.Factory publishAction) {
final PublishAction.Factory publishAction,
final DeleteDraftChange.Factory deleteDraftChangeFactory) {
this.submitAction = patchSetAction;
this.abandonChangeFactory = abandonChangeFactory;
this.restoreChangeFactory = restoreChangeFactory;
this.revertChangeFactory = revertChangeFactory;
this.publishAction = publishAction;
this.deleteDraftChangeFactory = deleteDraftChangeFactory;
}
public void submit(final PatchSet.Id patchSetId,
@@ -64,4 +68,9 @@ class ChangeManageServiceImpl implements ChangeManageService {
final AsyncCallback<ChangeDetail> callback) {
publishAction.create(patchSetId).to(callback);
}
}
public void deleteDraftChange(final PatchSet.Id patchSetId,
final AsyncCallback<VoidResult> callback) {
deleteDraftChangeFactory.create(patchSetId).to(callback);
}
}

View File

@@ -37,6 +37,7 @@ public class ChangeModule extends RpcServletModule {
factory(PatchSetPublishDetailFactory.Factory.class);
factory(SubmitAction.Factory.class);
factory(PublishAction.Factory.class);
factory(DeleteDraftChange.Factory.class);
}
});
rpc(ChangeDetailServiceImpl.class);

View File

@@ -0,0 +1,71 @@
// Copyright (C) 2011 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.httpd.rpc.changedetail;
import com.google.gerrit.httpd.rpc.Handler;
import com.google.gerrit.reviewdb.Change;
import com.google.gerrit.reviewdb.PatchSet;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gwtjsonrpc.client.VoidResult;
import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
class DeleteDraftChange extends Handler<VoidResult> {
interface Factory {
DeleteDraftChange create(PatchSet.Id patchSetId);
}
private final ChangeControl.Factory changeControlFactory;
private final ReviewDb db;
private final GitRepositoryManager gitManager;
private final ReplicationQueue replication;
private final PatchSet.Id patchSetId;
@Inject
DeleteDraftChange(final ReviewDb db,
final ChangeControl.Factory changeControlFactory,
final GitRepositoryManager gitManager,
final ReplicationQueue replication,
@Assisted final PatchSet.Id patchSetId) {
this.changeControlFactory = changeControlFactory;
this.db = db;
this.gitManager = gitManager;
this.replication = replication;
this.patchSetId = patchSetId;
}
@Override
public VoidResult call() throws NoSuchChangeException, OrmException, IOException {
final Change.Id changeId = patchSetId.getParentKey();
final ChangeControl control = changeControlFactory.validateFor(changeId);
if (!control.isOwner()) {
throw new NoSuchChangeException(changeId);
}
ChangeUtil.deleteDraftChange(patchSetId, gitManager, replication, db);
return VoidResult.INSTANCE;
}
}

View File

@@ -35,8 +35,13 @@ import com.google.gerrit.reviewdb.PatchSet;
import com.google.gerrit.reviewdb.PatchSetApproval;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.reviewdb.Patch.Key;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.account.AccountInfoCacheFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.patch.PublishComments;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.NoSuchChangeException;
@@ -47,6 +52,7 @@ import com.google.gwtorm.client.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -65,6 +71,9 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
private final PublishComments.Factory publishCommentsFactory;
private final PatchScriptFactory.Factory patchScriptFactoryFactory;
private final SaveDraft.Factory saveDraftFactory;
private final PatchSetInfoFactory patchSetInfoFactory;
private final GitRepositoryManager gitManager;
private final ReplicationQueue replication;
@Inject
PatchDetailServiceImpl(final Provider<ReviewDb> schema,
@@ -77,7 +86,10 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
final FunctionState.Factory functionStateFactory,
final PatchScriptFactory.Factory patchScriptFactoryFactory,
final PublishComments.Factory publishCommentsFactory,
final SaveDraft.Factory saveDraftFactory) {
final SaveDraft.Factory saveDraftFactory,
final PatchSetInfoFactory patchSetInfoFactory,
final GitRepositoryManager gitManager,
final ReplicationQueue replication) {
super(schema, currentUser);
this.approvalTypes = approvalTypes;
@@ -89,6 +101,9 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
this.patchScriptFactoryFactory = patchScriptFactoryFactory;
this.publishCommentsFactory = publishCommentsFactory;
this.saveDraftFactory = saveDraftFactory;
this.patchSetInfoFactory = patchSetInfoFactory;
this.gitManager = gitManager;
this.replication = replication;
}
public void patchScript(final Patch.Key patchKey, final PatchSet.Id psa,
@@ -133,6 +148,28 @@ class PatchDetailServiceImpl extends BaseServiceImplementation implements
});
}
public void deleteDraftPatchSet(final PatchSet.Id psid,
final AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() {
public VoidResult run(ReviewDb db) throws OrmException, Failure {
try {
final ChangeControl cc = changeControlFactory.validateFor(psid.getParentKey());
if (!cc.isOwner()) {
throw new Failure(new NoSuchEntityException());
}
ChangeUtil.deleteDraftPatchSet(psid, gitManager, replication, patchSetInfoFactory, db);
} catch (NoSuchChangeException e) {
throw new Failure(new NoSuchChangeException(psid.getParentKey()));
} catch (PatchSetInfoNotAvailableException e) {
throw new Failure(e);
} catch (IOException e) {
throw new Failure(e);
}
return VoidResult.INSTANCE;
}
});
}
public void publishComments(final PatchSet.Id psid, final String msg,
final Set<ApprovalCategoryValue.Id> tags,
final AsyncCallback<VoidResult> cb) {

View File

@@ -28,4 +28,6 @@ public interface AccountPatchReviewAccess
@Query("WHERE key.accountId = ? AND key.patchKey.patchSetId = ?")
ResultSet<AccountPatchReview> byReviewer(Account.Id who, PatchSet.Id ps) throws OrmException;
@Query("WHERE key.patchKey.patchSetId = ?")
ResultSet<AccountPatchReview> byPatchSet(PatchSet.Id ps) throws OrmException;
}

View File

@@ -478,6 +478,15 @@ public final class Change {
++nbrPatchSets;
}
/**
* Reverts to an older PatchSet id within this change.
* <p>
* <b>Note: This makes the change dirty. Call update() after.</b>
*/
public void removeLastPatchSetId() {
--nbrPatchSets;
}
public PatchSet.Id currPatchSetId() {
return new PatchSet.Id(changeId, nbrPatchSets);
}

View File

@@ -28,6 +28,9 @@ public interface ChangeMessageAccess extends
@Query("WHERE key.changeId = ? ORDER BY writtenOn")
ResultSet<ChangeMessage> byChange(Change.Id id) throws OrmException;
@Query("WHERE patchset = ?")
ResultSet<ChangeMessage> byPatchSet(PatchSet.Id id) throws OrmException;
@Query
ResultSet<ChangeMessage> all() throws OrmException;
}

View File

@@ -28,6 +28,13 @@ public interface PatchLineCommentAccess extends
@Query("WHERE key.patchKey.patchSetId.changeId = ?")
ResultSet<PatchLineComment> byChange(Change.Id id) throws OrmException;
@Query("WHERE key.patchKey.patchSetId = ?")
ResultSet<PatchLineComment> byPatchSet(PatchSet.Id id) throws OrmException;
@Query("WHERE key.patchKey = ? AND status = '"
+ PatchLineComment.STATUS_PUBLISHED + "' ORDER BY lineNbr,writtenOn")
ResultSet<PatchLineComment> published(Patch.Key patch) throws OrmException;
@Query("WHERE key.patchKey.patchSetId.changeId = ?"
+ " AND key.patchKey.fileName = ? AND status = '"
+ PatchLineComment.STATUS_PUBLISHED + "' ORDER BY lineNbr,writtenOn")

View File

@@ -28,6 +28,9 @@ public interface PatchSetAncestorAccess extends
@Query("WHERE key.patchSetId = ? ORDER BY key.position")
ResultSet<PatchSetAncestor> ancestorsOf(PatchSet.Id id) throws OrmException;
@Query("WHERE key.patchSetId = ?")
ResultSet<PatchSetAncestor> byPatchSet(PatchSet.Id id) throws OrmException;
@Query("WHERE ancestorRevision = ?")
ResultSet<PatchSetAncestor> descendantsOf(RevId revision)
throws OrmException;

View File

@@ -52,6 +52,7 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FooterLine;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -440,6 +441,96 @@ public class ChangeUtil {
}
}
public static void deleteDraftChange(final PatchSet.Id patchSetId,
GitRepositoryManager gitManager,
final ReplicationQueue replication, final ReviewDb db)
throws NoSuchChangeException, OrmException, IOException {
final Change.Id changeId = patchSetId.getParentKey();
final Change change = db.changes().get(changeId);
if (change == null || change.getStatus() != Change.Status.DRAFT) {
throw new NoSuchChangeException(changeId);
}
for (PatchSet ps : db.patchSets().byChange(changeId)) {
// These should all be draft patch sets.
deleteOnlyDraftPatchSet(ps, change, gitManager, replication, db);
}
db.changeMessages().delete(db.changeMessages().byChange(changeId));
db.starredChanges().delete(db.starredChanges().byChange(changeId));
db.trackingIds().delete(db.trackingIds().byChange(changeId));
db.changes().delete(Collections.singleton(change));
}
public static void deleteDraftPatchSet(final PatchSet.Id patchSetId,
GitRepositoryManager gitManager,
final ReplicationQueue replication,
final PatchSetInfoFactory patchSetInfoFactory,
final ReviewDb db) throws NoSuchChangeException, OrmException,
PatchSetInfoNotAvailableException, IOException {
final Change.Id changeId = patchSetId.getParentKey();
final Change change = db.changes().get(changeId);
final PatchSet patch = db.patchSets().get(patchSetId);
deleteOnlyDraftPatchSet(patch, change, gitManager, replication, db);
List<PatchSet> restOfPatches = db.patchSets().byChange(changeId).toList();
if (restOfPatches.size() == 0) {
deleteDraftChange(patchSetId, gitManager, replication, db);
} else {
PatchSet.Id highestId = null;
for (PatchSet ps : restOfPatches) {
if (highestId == null || ps.getPatchSetId() > highestId.get()) {
highestId = ps.getId();
}
}
if (change.currentPatchSetId().equals(patchSetId)) {
change.removeLastPatchSetId();
change.setCurrentPatchSet(patchSetInfoFactory.get(db, change.currPatchSetId()));
db.changes().update(Collections.singleton(change));
}
}
}
private static void deleteOnlyDraftPatchSet(final PatchSet patch,
final Change change, GitRepositoryManager gitManager,
final ReplicationQueue replication, final ReviewDb db)
throws NoSuchChangeException, OrmException, IOException {
final PatchSet.Id patchSetId = patch.getId();
if (patch == null || !patch.isDraft()) {
throw new NoSuchChangeException(patchSetId.getParentKey());
}
Repository repo = gitManager.openRepository(change.getProject());
try {
RefUpdate update = repo.updateRef(patch.getRefName());
update.setForceUpdate(true);
update.disableRefLog();
switch (update.delete()) {
case NEW:
case FAST_FORWARD:
case FORCED:
case NO_CHANGE:
// Successful deletion.
break;
default:
throw new IOException("Failed to delete ref " + patch.getRefName() +
" in " + repo.getDirectory() + ": " + update.getResult());
}
replication.scheduleUpdate(change.getProject(), update.getName());
} finally {
repo.close();
}
db.accountPatchReviews().delete(db.accountPatchReviews().byPatchSet(patchSetId));
db.changeMessages().delete(db.changeMessages().byPatchSet(patchSetId));
db.patchComments().delete(db.patchComments().byPatchSet(patchSetId));
db.patchSetApprovals().delete(db.patchSetApprovals().byPatchSet(patchSetId));
db.patchSetAncestors().delete(db.patchSetAncestors().byPatchSet(patchSetId));
db.patchSets().delete(Collections.singleton(patch));
}
private static <T extends ReplyToChangeSender> void updatedChange(
final ReviewDb db, final IdentifiedUser user, final Change change,
final ChangeMessage cmsg, ReplyToChangeSender.Factory<T> senderFactory,

View File

@@ -28,11 +28,15 @@ import com.google.gerrit.reviewdb.RevId;
import com.google.gerrit.reviewdb.ReviewDb;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeOp;
import com.google.gerrit.server.git.MergeQueue;
import com.google.gerrit.server.git.ReplicationQueue;
import com.google.gerrit.server.mail.AbandonedSender;
import com.google.gerrit.server.mail.EmailException;
import com.google.gerrit.server.mail.RestoredSender;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.patch.PublishComments;
import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException;
@@ -107,6 +111,9 @@ public class ReviewCommand extends BaseCommand {
@Option(name = "--publish", usage = "publish a draft patch set")
private boolean publishPatchSet;
@Option(name = "--delete", usage = "delete a draft patch set")
private boolean deleteDraftPatchSet;
@Inject
private ReviewDb db;
@@ -140,6 +147,15 @@ public class ReviewCommand extends BaseCommand {
@Inject
private ChangeHookRunner hooks;
@Inject
private GitRepositoryManager gitManager;
@Inject
private ReplicationQueue replication;
@Inject
private PatchSetInfoFactory patchSetInfoFactory;
private List<ApproveOption> optionList;
private Set<PatchSet.Id> toSubmit = new HashSet<PatchSet.Id>();
@@ -161,6 +177,9 @@ public class ReviewCommand extends BaseCommand {
if (publishPatchSet) {
throw error("abandon and publish actions are mutually exclusive");
}
if (deleteDraftPatchSet) {
throw error("abandon and delete actions are mutually exclusive");
}
}
if (publishPatchSet) {
if (restoreChange) {
@@ -169,6 +188,9 @@ public class ReviewCommand extends BaseCommand {
if (submitChange) {
throw error("publish and submit actions are mutually exclusive");
}
if (deleteDraftPatchSet) {
throw error("publish and delete actions are mutually exclusive");
}
}
boolean ok = true;
@@ -336,6 +358,19 @@ public class ReviewCommand extends BaseCommand {
throw error("Not permitted to publish draft patchset");
}
}
if (deleteDraftPatchSet) {
if (changeControl.isOwner() && changeControl.isVisible(db)) {
try {
ChangeUtil.deleteDraftPatchSet(patchSetId, gitManager, replication, patchSetInfoFactory, db);
} catch (PatchSetInfoNotAvailableException e) {
throw error("Error retrieving draft patchset: " + patchSetId);
} catch (IOException e) {
throw error("Error deleting draft patchset: " + patchSetId);
}
} else {
throw error("Not permitted to delete draft patchset");
}
}
}
private Set<PatchSet.Id> parsePatchSetId(final String patchIdentity)