Support setting current patch set in NoteDb
Until now, NoteDb was not explicitly recording the current patch set, and instead just assuming that the highest-numbered non-deleted patch set was current. This is usually fine, but there is at least one corner case where it's not. Specifically, when pushing an old patch set of a change directly to a branch: * The change moves to state MERGED. * The currentPatchSetId field gets set to the corresponding patch set ID of the merged commit, even if this is less than the maximum patch set in the database. Teach NoteDb to handle this case with a footer "Current: true" indicating the patch set mentioned in the "Patch-set" footer is the current patch set. Creating a new patch set also implicitly sets it to current, matching existing data. Various parts of the code in ChangeRebuilderImpl and ChangeBundle were assuming that any entities referring to patch sets greater than the current patch set were ignorable. Remove this assumption, and ensure we're handling these entities properly. Add a test for the above case. Change-Id: I099fd703458ffd63a31009ceaaa1c1d2c59d4669
This commit is contained in:
@@ -769,39 +769,6 @@ public class ChangeBundleTest extends GerritBaseTests {
|
||||
+ "Only in B:\n " + cm1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void diffChangeMessagesIgnoresMessagesOnPatchSetGreaterThanCurrent()
|
||||
throws Exception {
|
||||
Change c = TestChanges.newChange(project, accountId);
|
||||
|
||||
PatchSet ps1 = new PatchSet(new PatchSet.Id(c.getId(), 1));
|
||||
ps1.setRevision(new RevId("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"));
|
||||
ps1.setUploader(accountId);
|
||||
ps1.setCreatedOn(TimeUtil.nowTs());
|
||||
PatchSet ps2 = new PatchSet(new PatchSet.Id(c.getId(), 2));
|
||||
ps2.setRevision(new RevId("badc0feebadc0feebadc0feebadc0feebadc0fee"));
|
||||
ps2.setUploader(accountId);
|
||||
ps2.setCreatedOn(TimeUtil.nowTs());
|
||||
|
||||
assertThat(c.currentPatchSetId()).isEqualTo(ps1.getId());
|
||||
|
||||
ChangeMessage cm1 = new ChangeMessage(
|
||||
new ChangeMessage.Key(c.getId(), "uuid1"),
|
||||
accountId, TimeUtil.nowTs(), ps1.getId());
|
||||
cm1.setMessage("a message");
|
||||
ChangeMessage cm2 = new ChangeMessage(
|
||||
new ChangeMessage.Key(c.getId(), "uuid2"),
|
||||
accountId, TimeUtil.nowTs(), ps2.getId());
|
||||
cm2.setMessage("other message");
|
||||
|
||||
ChangeBundle b1 = new ChangeBundle(c, messages(cm1, cm2),
|
||||
patchSets(ps1, ps2), approvals(), comments(), reviewers(), REVIEW_DB);
|
||||
ChangeBundle b2 = new ChangeBundle(c, messages(cm1), patchSets(ps1),
|
||||
approvals(), comments(), reviewers(), NOTE_DB);
|
||||
assertNoDiffs(b1, b2);
|
||||
assertNoDiffs(b2, b1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void diffPatchSetIdSets() throws Exception {
|
||||
Change c = TestChanges.newChange(project, accountId);
|
||||
@@ -919,7 +886,7 @@ public class ChangeBundleTest extends GerritBaseTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void diffIgnoresPatchSetsGreaterThanCurrent() throws Exception {
|
||||
public void diffPatchSetsGreaterThanCurrent() throws Exception {
|
||||
Change c = TestChanges.newChange(project, accountId);
|
||||
|
||||
PatchSet ps1 = new PatchSet(new PatchSet.Id(c.getId(), 1));
|
||||
@@ -932,6 +899,13 @@ public class ChangeBundleTest extends GerritBaseTests {
|
||||
ps2.setCreatedOn(TimeUtil.nowTs());
|
||||
assertThat(ps2.getId().get()).isGreaterThan(c.currentPatchSetId().get());
|
||||
|
||||
ChangeMessage cm1 = new ChangeMessage(
|
||||
new ChangeMessage.Key(c.getId(), "uuid1"),
|
||||
accountId, TimeUtil.nowTs(), c.currentPatchSetId());
|
||||
ChangeMessage cm2 = new ChangeMessage(
|
||||
new ChangeMessage.Key(c.getId(), "uuid2"),
|
||||
accountId, TimeUtil.nowTs(), c.currentPatchSetId());
|
||||
|
||||
PatchSetApproval a1 = new PatchSetApproval(
|
||||
new PatchSetApproval.Key(
|
||||
ps1.getId(), accountId, new LabelId("Code-Review")),
|
||||
@@ -944,26 +918,44 @@ public class ChangeBundleTest extends GerritBaseTests {
|
||||
TimeUtil.nowTs());
|
||||
|
||||
// Both ReviewDb.
|
||||
ChangeBundle b1 = new ChangeBundle(c, messages(), patchSets(ps1),
|
||||
ChangeBundle b1 = new ChangeBundle(c, messages(cm1), patchSets(ps1),
|
||||
approvals(a1), comments(), reviewers(), REVIEW_DB);
|
||||
ChangeBundle b2 = new ChangeBundle(c, messages(), patchSets(ps1, ps2),
|
||||
approvals(a1, a2), comments(), reviewers(), REVIEW_DB);
|
||||
assertNoDiffs(b1, b2);
|
||||
ChangeBundle b2 = new ChangeBundle(c, messages(cm1, cm2),
|
||||
patchSets(ps1, ps2), approvals(a1, a2), comments(), reviewers(),
|
||||
REVIEW_DB);
|
||||
assertDiffs(b1, b2,
|
||||
"ChangeMessage.Key sets differ: [] only in A; [" + cm2.getKey()
|
||||
+ "] only in B",
|
||||
"PatchSet.Id sets differ:"
|
||||
+ " [] only in A; [" + ps2.getId() + "] only in B",
|
||||
"PatchSetApproval.Key sets differ:"
|
||||
+ " [] only in A; [" + a2.getKey() + "] only in B");
|
||||
|
||||
// One NoteDb.
|
||||
b1 = new ChangeBundle(c, messages(), patchSets(ps1), approvals(a1),
|
||||
b1 = new ChangeBundle(c, messages(cm1), patchSets(ps1), approvals(a1),
|
||||
comments(), reviewers(), NOTE_DB);
|
||||
b2 = new ChangeBundle(c, messages(), patchSets(ps1, ps2), approvals(a1, a2),
|
||||
b2 = new ChangeBundle(c, messages(cm1, cm2), patchSets(ps1, ps2), approvals(a1, a2),
|
||||
comments(), reviewers(), REVIEW_DB);
|
||||
assertNoDiffs(b1, b2);
|
||||
assertNoDiffs(b2, b1);
|
||||
assertDiffs(b1, b2,
|
||||
"ChangeMessages differ for Change.Id " + c.getId() + "\n"
|
||||
+ "Only in B:\n " + cm2,
|
||||
"PatchSet.Id sets differ:"
|
||||
+ " [] only in A; [" + ps2.getId() + "] only in B",
|
||||
"PatchSetApproval.Key sets differ:"
|
||||
+ " [] only in A; [" + a2.getKey() + "] only in B");
|
||||
|
||||
// Both NoteDb.
|
||||
b1 = new ChangeBundle(c, messages(), patchSets(ps1), approvals(a1),
|
||||
b1 = new ChangeBundle(c, messages(cm1), patchSets(ps1), approvals(a1),
|
||||
comments(), reviewers(), NOTE_DB);
|
||||
b2 = new ChangeBundle(c, messages(), patchSets(ps1, ps2), approvals(a1, a2),
|
||||
b2 = new ChangeBundle(c, messages(cm1, cm2), patchSets(ps1, ps2), approvals(a1, a2),
|
||||
comments(), reviewers(), NOTE_DB);
|
||||
assertNoDiffs(b1, b2);
|
||||
assertDiffs(b1, b2,
|
||||
"ChangeMessages differ for Change.Id " + c.getId() + "\n"
|
||||
+ "Only in B:\n " + cm2,
|
||||
"PatchSet.Id sets differ:"
|
||||
+ " [] only in A; [" + ps2.getId() + "] only in B",
|
||||
"PatchSetApproval.Key sets differ:"
|
||||
+ " [] only in A; [" + a2.getKey() + "] only in B");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -448,6 +448,26 @@ public class ChangeNotesParserTest extends AbstractChangeNotesTest {
|
||||
+ "subject: This is a test change\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentPatchSet() throws Exception {
|
||||
assertParseSucceeds("Update change\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Current: true");
|
||||
assertParseSucceeds("Update change\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Current: tRUe");
|
||||
assertParseFails("Update change\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Current: false");
|
||||
assertParseFails("Update change\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Current: blah");
|
||||
}
|
||||
|
||||
private RevCommit writeCommit(String body) throws Exception {
|
||||
ChangeNoteUtil noteUtil = injector.getInstance(ChangeNoteUtil.class);
|
||||
return writeCommit(body, noteUtil.newIdent(
|
||||
|
||||
@@ -2631,6 +2631,38 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
assertThat(notes.getComments()).hasSize(numComments);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentPatchSet() throws Exception {
|
||||
Change c = newChange();
|
||||
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
|
||||
|
||||
incrementPatchSet(c);
|
||||
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
|
||||
|
||||
ChangeUpdate update = newUpdate(c, changeOwner);
|
||||
update.setPatchSetId(new PatchSet.Id(c.getId(), 1));
|
||||
update.setCurrentPatchSet();
|
||||
update.commit();
|
||||
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
|
||||
|
||||
incrementPatchSet(c);
|
||||
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(3);
|
||||
|
||||
// Delete PS3, PS1 becomes current, as the most recent event explicitly set
|
||||
// it to current.
|
||||
update = newUpdate(c, changeOwner);
|
||||
update.setPatchSetState(PatchSetState.DELETED);
|
||||
update.commit();
|
||||
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(1);
|
||||
|
||||
// Delete PS1, PS2 becomes current.
|
||||
update = newUpdate(c, changeOwner);
|
||||
update.setPatchSetId(new PatchSet.Id(c.getId(), 1));
|
||||
update.setPatchSetState(PatchSetState.DELETED);
|
||||
update.commit();
|
||||
assertThat(newNotes(c).getChange().currentPatchSetId().get()).isEqualTo(2);
|
||||
}
|
||||
|
||||
private boolean testJson() {
|
||||
return noteUtil.getWriteJson();
|
||||
}
|
||||
|
||||
@@ -356,6 +356,20 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
commit);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentPatchSet() throws Exception {
|
||||
Change c = newChange();
|
||||
ChangeUpdate update = newUpdate(c, changeOwner);
|
||||
update.setCurrentPatchSet();
|
||||
update.commit();
|
||||
|
||||
assertBodyEquals("Update patch set 1\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Current: true\n",
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
private RevCommit parseCommit(ObjectId id) throws Exception {
|
||||
if (id instanceof RevCommit) {
|
||||
return (RevCommit) id;
|
||||
|
||||
Reference in New Issue
Block a user