Fix NPE when deleting current patch set and previous patch set doesn't exist
When the current patch set was deleted we used patch set ID - 1 as ID for the previous patch set but this patch set may not exist (e.g. it was a draft that was deleted). Change-Id: Ief0776d131d805ed403fb45bb6112d953dc5564d Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
@@ -187,6 +187,26 @@ public class DeleteDraftPatchSetIT extends AbstractDaemonTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteCurrentDraftPatchSetWhenPreviousPatchSetDoesNotExist() throws Exception {
|
||||
PushOneCommit push = pushFactory.create(db, admin.getIdent(), testRepo);
|
||||
String changeId = push.to("refs/for/master").getChangeId();
|
||||
pushFactory
|
||||
.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT, "b.txt", "foo", changeId)
|
||||
.to("refs/drafts/master");
|
||||
pushFactory
|
||||
.create(db, admin.getIdent(), testRepo, PushOneCommit.SUBJECT, "b.txt", "bar", changeId)
|
||||
.to("refs/drafts/master");
|
||||
|
||||
deletePatchSet(changeId, 2);
|
||||
deletePatchSet(changeId, 3);
|
||||
|
||||
ChangeData cd = getChange(changeId);
|
||||
assertThat(cd.patchSets()).hasSize(1);
|
||||
assertThat(Iterables.getOnlyElement(cd.patchSets()).getId().get()).isEqualTo(1);
|
||||
assertThat(cd.currentPatchSet().getId().get()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteDraftPatchSetAndPushNewDraftPatchSet() throws Exception {
|
||||
String ref = "refs/drafts/master";
|
||||
@@ -263,6 +283,10 @@ public class DeleteDraftPatchSetIT extends AbstractDaemonTest {
|
||||
}
|
||||
|
||||
private void deletePatchSet(String changeId, PatchSet ps) throws Exception {
|
||||
gApi.changes().id(changeId).revision(ps.getId().get()).delete();
|
||||
deletePatchSet(changeId, ps.getId().get());
|
||||
}
|
||||
|
||||
private void deletePatchSet(String changeId, int ps) throws Exception {
|
||||
gApi.changes().id(changeId).revision(ps).delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package com.google.gerrit.server.change;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.gerrit.common.TimeUtil;
|
||||
import com.google.gerrit.extensions.registration.DynamicItem;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
@@ -45,6 +47,7 @@ import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
@@ -106,7 +109,8 @@ public class DeleteDraftPatchSet
|
||||
@Override
|
||||
public boolean updateChange(ChangeContext ctx)
|
||||
throws RestApiException, OrmException, IOException, NoSuchChangeException {
|
||||
patchSet = psUtil.get(ctx.getDb(), ctx.getNotes(), psId);
|
||||
Map<PatchSet.Id, PatchSet> patchSets = psUtil.byChangeAsMap(db.get(), ctx.getNotes());
|
||||
patchSet = patchSets.get(psId);
|
||||
if (patchSet == null) {
|
||||
return false; // Nothing to do.
|
||||
}
|
||||
@@ -120,9 +124,9 @@ public class DeleteDraftPatchSet
|
||||
throw new AuthException("Not permitted to delete this draft patch set");
|
||||
}
|
||||
|
||||
patchSetsBeforeDeletion = psUtil.byChange(ctx.getDb(), ctx.getNotes());
|
||||
patchSetsBeforeDeletion = patchSets.values();
|
||||
deleteDraftPatchSet(patchSet, ctx);
|
||||
deleteOrUpdateDraftChange(ctx);
|
||||
deleteOrUpdateDraftChange(ctx, patchSets);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -152,7 +156,7 @@ public class DeleteDraftPatchSet
|
||||
db.patchSetApprovals().delete(db.patchSetApprovals().byPatchSet(psId));
|
||||
}
|
||||
|
||||
private void deleteOrUpdateDraftChange(ChangeContext ctx)
|
||||
private void deleteOrUpdateDraftChange(ChangeContext ctx, Map<PatchSet.Id, PatchSet> patchSets)
|
||||
throws OrmException, RestApiException, IOException, NoSuchChangeException {
|
||||
Change c = ctx.getChange();
|
||||
if (deletedOnlyPatchSet()) {
|
||||
@@ -161,7 +165,7 @@ public class DeleteDraftPatchSet
|
||||
return;
|
||||
}
|
||||
if (c.currentPatchSetId().equals(psId)) {
|
||||
c.setCurrentPatchSet(previousPatchSetInfo(ctx));
|
||||
c.setCurrentPatchSet(previousPatchSetInfo(ctx, patchSets));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,12 +174,22 @@ public class DeleteDraftPatchSet
|
||||
&& patchSetsBeforeDeletion.iterator().next().getId().equals(psId);
|
||||
}
|
||||
|
||||
private PatchSetInfo previousPatchSetInfo(ChangeContext ctx) throws OrmException {
|
||||
private PatchSetInfo previousPatchSetInfo(
|
||||
ChangeContext ctx, Map<PatchSet.Id, PatchSet> patchSets) throws OrmException {
|
||||
PatchSet.Id prevPsId = null;
|
||||
for (PatchSet.Id id : patchSets.keySet()) {
|
||||
if (id.get() < psId.get() && (prevPsId == null || id.get() > prevPsId.get())) {
|
||||
prevPsId = id;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO(dborowitz): Get this in a way that doesn't involve re-opening
|
||||
// the repo after the updateRepo phase.
|
||||
return patchSetInfoFactory.get(
|
||||
ctx.getDb(), ctx.getNotes(), new PatchSet.Id(psId.getParentKey(), psId.get() - 1));
|
||||
ctx.getDb(),
|
||||
ctx.getNotes(),
|
||||
new PatchSet.Id(psId.getParentKey(), checkNotNull(prevPsId).get()));
|
||||
} catch (PatchSetInfoNotAvailableException e) {
|
||||
throw new OrmException(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user