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:
@@ -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::
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -140,6 +140,9 @@ public interface ChangeConstants extends Constants {
|
||||
|
||||
String buttonPublishPatchSet();
|
||||
|
||||
String buttonDeleteDraftChange();
|
||||
String buttonDeleteDraftPatchSet();
|
||||
|
||||
String pagedChangeListPrev();
|
||||
String pagedChangeListNext();
|
||||
|
||||
|
@@ -117,6 +117,9 @@ headingPatchComments = Patch Comments:
|
||||
|
||||
buttonPublishPatchSet = Publish
|
||||
|
||||
buttonDeleteDraftChange = Delete Draft Change
|
||||
buttonDeleteDraftPatchSet = Delete Draft Patch Set
|
||||
|
||||
pagedChangeListPrev = ⇦Prev
|
||||
pagedChangeListNext = Next⇨
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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));
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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")
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user