summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarija Savtchouk <mariasavtchouk@google.com>2020-11-26 14:21:57 +0000
committerNasser Grainawi <quic_nasserg@quicinc.com>2022-03-30 20:37:00 -0600
commit46b036279c33827f223fcfa63202b006c4f85a6b (patch)
tree2c1d1722207e6e3d473bd87226015007537b82bc
parent2e6ae84d1e60c69a2485f9c284b2c5f2d7a04257 (diff)
Update existing change on cherry-pick with CommitApi
CommitAPI: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#cherry-pick-commit When the user tries to cherry pick a change onto an already existing change in a different branch with CommitAPI (Change-ID is provided in the commit message, and the change with this Change-ID exists in the destination branch), it results in NPE. Instead, this operation should just create a new patch set on the existing change. When using CommitAPI, the source commit is not associated with the change, but the existing destination change might have cherryPickOf already set. Reset cherryPickOf in NoteDb for this case. Bug: Issue 14109 Release-Notes: Fix NPE with cherry pick CommitAPI onto an existing change in a different branch Change-Id: I11beb7de9be4aa60a3c5e6a045b46156d9b310da (cherry picked from commit b9608bef91cd7418117f2fbaf0889601ed09e124)
-rw-r--r--java/com/google/gerrit/server/change/ResetCherryPickOp.java37
-rw-r--r--java/com/google/gerrit/server/notedb/ChangeNotesParser.java40
-rw-r--r--java/com/google/gerrit/server/notedb/ChangeUpdate.java18
-rw-r--r--java/com/google/gerrit/server/restapi/change/CherryPickChange.java11
-rw-r--r--javatests/com/google/gerrit/acceptance/api/project/CommitIT.java243
-rw-r--r--javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java28
6 files changed, 320 insertions, 57 deletions
diff --git a/java/com/google/gerrit/server/change/ResetCherryPickOp.java b/java/com/google/gerrit/server/change/ResetCherryPickOp.java
new file mode 100644
index 0000000000..d1177d498c
--- /dev/null
+++ b/java/com/google/gerrit/server/change/ResetCherryPickOp.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2020 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.change;
+
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.server.notedb.ChangeUpdate;
+import com.google.gerrit.server.update.BatchUpdateOp;
+import com.google.gerrit.server.update.ChangeContext;
+
+/** Reset cherryPickOf to an empty value. */
+public class ResetCherryPickOp implements BatchUpdateOp {
+
+ @Override
+ public boolean updateChange(ChangeContext ctx) throws RestApiException {
+ Change change = ctx.getChange();
+ if (change.getCherryPickOf() == null) {
+ return false;
+ }
+
+ ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
+ update.resetCherryPickOf();
+ return true;
+ }
+}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index 78ba243777..6f9f7e8a30 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -55,6 +55,7 @@ import com.google.common.collect.Table;
import com.google.common.collect.Tables;
import com.google.common.flogger.FluentLogger;
import com.google.common.primitives.Ints;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Address;
import com.google.gerrit.entities.AttentionSetUpdate;
@@ -153,7 +154,10 @@ class ChangeNotesParser {
private ReviewerByEmailSet pendingReviewersByEmail;
private Change.Id revertOf;
private int updateCount;
- private PatchSet.Id cherryPickOf;
+ // Null indicates that the field was not parsed (yet).
+ // We only set the value once, based on the latest update (the actual value or Optional.empty() if
+ // the latest record unsets the field).
+ private Optional<PatchSet.Id> cherryPickOf;
ChangeNotesParser(
Change.Id changeId,
@@ -254,7 +258,7 @@ class ChangeNotesParser {
firstNonNull(workInProgress, false),
firstNonNull(hasReviewStarted, true),
revertOf,
- cherryPickOf,
+ cherryPickOf != null ? cherryPickOf.orElse(null) : null,
updateCount);
}
@@ -999,15 +1003,31 @@ class ChangeNotesParser {
return Change.id(revertOf);
}
- private PatchSet.Id parseCherryPickOf(ChangeNotesCommit commit) throws ConfigInvalidException {
- String cherryPickOf = parseOneFooter(commit, FOOTER_CHERRY_PICK_OF);
- if (cherryPickOf == null) {
+ /**
+ * Parses {@link ChangeNoteUtil#FOOTER_CHERRY_PICK_OF} of the commit.
+ *
+ * @param commit the commit to parse.
+ * @return {@link Optional} value of the parsed footer or {@code null} if the footer is missing in
+ * this commit.
+ * @throws ConfigInvalidException if the footer value could not be parsed as a valid {@link
+ * PatchSet.Id}.
+ */
+ @Nullable
+ private Optional<PatchSet.Id> parseCherryPickOf(ChangeNotesCommit commit)
+ throws ConfigInvalidException {
+ String footer = parseOneFooter(commit, FOOTER_CHERRY_PICK_OF);
+ if (footer == null) {
+ // The footer is missing, nothing to parse.
return null;
- }
- try {
- return PatchSet.Id.parse(cherryPickOf);
- } catch (IllegalArgumentException e) {
- throw new ConfigInvalidException("\"" + cherryPickOf + "\" is not a valid patchset", e);
+ } else if (footer.equals("")) {
+ // Empty footer value, cherryPickOf was unset at this commit.
+ return Optional.empty();
+ } else {
+ try {
+ return Optional.of(PatchSet.Id.parse(footer));
+ } catch (IllegalArgumentException e) {
+ throw new ConfigInvalidException("\"" + footer + "\" is not a valid patchset", e);
+ }
}
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeUpdate.java b/java/com/google/gerrit/server/notedb/ChangeUpdate.java
index 3312d6cfc9..52c551ef0e 100644
--- a/java/com/google/gerrit/server/notedb/ChangeUpdate.java
+++ b/java/com/google/gerrit/server/notedb/ChangeUpdate.java
@@ -152,7 +152,9 @@ public class ChangeUpdate extends AbstractChangeUpdate {
private Boolean isPrivate;
private Boolean workInProgress;
private Integer revertOf;
- private String cherryPickOf;
+ // If null, the update does not modify the field. Otherwise, it updates the field with the
+ // new value or resets if cherryPickOf == Optional.empty().
+ private Optional<String> cherryPickOf;
private ChangeDraftUpdate draftUpdate;
private RobotCommentUpdate robotCommentUpdate;
@@ -473,7 +475,12 @@ public class ChangeUpdate extends AbstractChangeUpdate {
}
public void setCherryPickOf(String cherryPickOf) {
- this.cherryPickOf = cherryPickOf;
+ checkArgument(cherryPickOf != null, "use resetCherryPickOf");
+ this.cherryPickOf = Optional.of(cherryPickOf);
+ }
+
+ public void resetCherryPickOf() {
+ this.cherryPickOf = Optional.empty();
}
/** @return the tree id for the updated tree */
@@ -753,7 +760,12 @@ public class ChangeUpdate extends AbstractChangeUpdate {
}
if (cherryPickOf != null) {
- addFooter(msg, FOOTER_CHERRY_PICK_OF, cherryPickOf);
+ if (cherryPickOf.isPresent()) {
+ addFooter(msg, FOOTER_CHERRY_PICK_OF, cherryPickOf.get());
+ } else {
+ // Update cherryPickOf with an empty value.
+ addFooter(msg, FOOTER_CHERRY_PICK_OF).append('\n');
+ }
}
if (plannedAttentionSetUpdates != null) {
diff --git a/java/com/google/gerrit/server/restapi/change/CherryPickChange.java b/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
index fdac552edf..6ee3284c5d 100644
--- a/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
+++ b/java/com/google/gerrit/server/restapi/change/CherryPickChange.java
@@ -42,6 +42,7 @@ import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.NotifyResolver;
import com.google.gerrit.server.change.PatchSetInserter;
+import com.google.gerrit.server.change.ResetCherryPickOp;
import com.google.gerrit.server.change.SetCherryPickOp;
import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.git.CodeReviewCommit;
@@ -371,7 +372,7 @@ public class CherryPickChange {
git,
destChanges.get(0).notes(),
cherryPickCommit,
- sourceChange.currentPatchSetId(),
+ sourceChange,
newTopic,
workInProgress);
} else {
@@ -456,7 +457,7 @@ public class CherryPickChange {
Repository git,
ChangeNotes destNotes,
CodeReviewCommit cherryPickCommit,
- PatchSet.Id sourcePatchSetId,
+ @Nullable Change sourceChange,
String topic,
@Nullable Boolean workInProgress)
throws IOException {
@@ -469,7 +470,11 @@ public class CherryPickChange {
inserter.setWorkInProgress(workInProgress);
}
bu.addOp(destChange.getId(), inserter);
- if (destChange.getCherryPickOf() == null
+ PatchSet.Id sourcePatchSetId = sourceChange == null ? null : sourceChange.currentPatchSetId();
+ // If sourceChange is not provided, reset cherryPickOf to avoid stale value.
+ if (sourcePatchSetId == null) {
+ bu.addOp(destChange.getId(), new ResetCherryPickOp());
+ } else if (destChange.getCherryPickOf() == null
|| !destChange.getCherryPickOf().equals(sourcePatchSetId)) {
SetCherryPickOp cherryPickOfUpdater = setCherryPickOfFactory.create(sourcePatchSetId);
bu.addOp(destChange.getId(), cherryPickOfUpdater);
diff --git a/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java b/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java
index 23563275b8..3b5ac78b26 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java
@@ -24,6 +24,7 @@ import static org.eclipse.jgit.lib.Constants.R_TAGS;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.PushOneCommit.Result;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
@@ -147,77 +148,237 @@ public class CommitIT extends AbstractDaemonTest {
}
@Test
- public void cherryPickWithoutMessage() throws Exception {
- String branch = "foo";
+ public void cherryPickWithoutMessageSameBranch() throws Exception {
+ String destBranch = "master";
// Create change to cherry-pick
- RevCommit revCommit = createChange().getCommit();
-
- // Create target branch to cherry-pick to.
- gApi.projects().name(project.get()).branch(branch).create(new BranchInput());
+ PushOneCommit.Result r = createChange();
+ ChangeInfo changeToCherryPick = info(r.getChangeId());
+ RevCommit commitToCherryPick = r.getCommit();
// Cherry-pick without message.
CherryPickInput input = new CherryPickInput();
- input.destination = branch;
- String changeId =
- gApi.projects().name(project.get()).commit(revCommit.name()).cherryPick(input).get().id;
+ input.destination = destBranch;
+ ChangeInfo cherryPickResult =
+ gApi.projects()
+ .name(project.get())
+ .commit(commitToCherryPick.name())
+ .cherryPick(input)
+ .get();
+
+ // Expect that the Change-Id of the cherry-picked commit was used for the cherry-pick change.
+ // New patch-set to existing change was uploaded.
+ assertThat(cherryPickResult._number).isEqualTo(changeToCherryPick._number);
+ assertThat(cherryPickResult.revisions).hasSize(2);
+ assertThat(cherryPickResult.changeId).isEqualTo(changeToCherryPick.changeId);
+ assertThat(cherryPickResult.messages).hasSize(2);
+
+ // Cherry-pick of is not set, because the source change was not provided.
+ assertThat(cherryPickResult.cherryPickOfChange).isNull();
+ assertThat(cherryPickResult.cherryPickOfPatchSet).isNull();
+ // Expect that the message of the cherry-picked commit was used for the cherry-pick change.
+ RevisionInfo revInfo = cherryPickResult.revisions.get(cherryPickResult.currentRevision);
+ assertThat(revInfo).isNotNull();
+ assertThat(revInfo.commit.message).isEqualTo(commitToCherryPick.getFullMessage());
+ }
+ @Test
+ public void cherryPickWithoutMessageOtherBranch() throws Exception {
+ String destBranch = "foo";
+ createBranch(BranchNameKey.create(project, destBranch));
+
+ // Create change to cherry-pick
+ PushOneCommit.Result r = createChange();
+ ChangeInfo changeToCherryPick = info(r.getChangeId());
+ RevCommit commitToCherryPick = r.getCommit();
+
+ // Cherry-pick without message.
+ CherryPickInput input = new CherryPickInput();
+ input.destination = destBranch;
+ ChangeInfo cherryPickResult =
+ gApi.projects()
+ .name(project.get())
+ .commit(commitToCherryPick.name())
+ .cherryPick(input)
+ .get();
+
+ // Expect that the Change-Id of the cherry-picked commit was used for the cherry-pick change.
+ // New change in destination branch was created.
+ assertThat(cherryPickResult._number).isGreaterThan(changeToCherryPick._number);
+ assertThat(cherryPickResult.revisions).hasSize(1);
+ assertThat(cherryPickResult.changeId).isEqualTo(changeToCherryPick.changeId);
+ assertThat(cherryPickResult.messages).hasSize(1);
+
+ // Cherry-pick of is not set, because the source change was not provided.
+ assertThat(cherryPickResult.cherryPickOfChange).isNull();
+ assertThat(cherryPickResult.cherryPickOfPatchSet).isNull();
// Expect that the message of the cherry-picked commit was used for the cherry-pick change.
- ChangeInfo changeInfo = gApi.changes().id(changeId).get();
- RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision);
+ RevisionInfo revInfo = cherryPickResult.revisions.get(cherryPickResult.currentRevision);
assertThat(revInfo).isNotNull();
- assertThat(revInfo.commit.message).isEqualTo(revCommit.getFullMessage());
+ assertThat(revInfo.commit.message).isEqualTo(commitToCherryPick.getFullMessage());
}
@Test
- public void cherryPickCommitWithoutChangeId() throws Exception {
+ public void cherryPickCommitWithoutChangeIdCreateNewChange() throws Exception {
+ String destBranch = "foo";
+ createBranch(BranchNameKey.create(project, destBranch));
+
CherryPickInput input = new CherryPickInput();
- input.destination = "foo";
+ input.destination = destBranch;
input.message = "it goes to foo branch";
- gApi.projects().name(project.get()).branch(input.destination).create(new BranchInput());
-
- RevCommit revCommit = createNewCommitWithoutChangeId("refs/heads/master", "a.txt", "content");
- ChangeInfo changeInfo =
- gApi.projects().name(project.get()).commit(revCommit.getName()).cherryPick(input).get();
- assertThat(changeInfo.messages).hasSize(1);
- Iterator<ChangeMessageInfo> messageIterator = changeInfo.messages.iterator();
+ RevCommit commitToCherryPick =
+ createNewCommitWithoutChangeId("refs/heads/master", "a.txt", "content");
+ ChangeInfo cherryPickResult =
+ gApi.projects()
+ .name(project.get())
+ .commit(commitToCherryPick.getName())
+ .cherryPick(input)
+ .get();
+
+ assertThat(cherryPickResult.messages).hasSize(1);
+ Iterator<ChangeMessageInfo> messageIterator = cherryPickResult.messages.iterator();
String expectedMessage =
- String.format("Patch Set 1: Cherry Picked from commit %s.", revCommit.getName());
+ String.format("Patch Set 1: Cherry Picked from commit %s.", commitToCherryPick.getName());
assertThat(messageIterator.next().message).isEqualTo(expectedMessage);
- RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision);
+ RevisionInfo revInfo = cherryPickResult.revisions.get(cherryPickResult.currentRevision);
assertThat(revInfo).isNotNull();
CommitInfo commitInfo = revInfo.commit;
assertThat(commitInfo.message)
- .isEqualTo(input.message + "\n\nChange-Id: " + changeInfo.changeId + "\n");
+ .isEqualTo(input.message + "\n\nChange-Id: " + cherryPickResult.changeId + "\n");
}
@Test
- public void cherryPickCommitWithChangeId() throws Exception {
- CherryPickInput input = new CherryPickInput();
- input.destination = "foo";
-
- RevCommit revCommit = createChange().getCommit();
- List<String> footers = revCommit.getFooterLines("Change-Id");
+ public void cherryPickCommitWithChangeIdCreateNewChange() throws Exception {
+ String destBranch = "foo";
+ createBranch(BranchNameKey.create(project, destBranch));
+
+ PushOneCommit.Result r = createChange();
+ ChangeInfo changeToCherryPick = info(r.getChangeId());
+ RevCommit commitToCherryPick = r.getCommit();
+ List<String> footers = commitToCherryPick.getFooterLines("Change-Id");
assertThat(footers).hasSize(1);
String changeId = footers.get(0);
- input.message = "it goes to foo branch\n\nChange-Id: " + changeId;
- gApi.projects().name(project.get()).branch(input.destination).create(new BranchInput());
-
- ChangeInfo changeInfo =
- gApi.projects().name(project.get()).commit(revCommit.getName()).cherryPick(input).get();
-
- assertThat(changeInfo.messages).hasSize(1);
- Iterator<ChangeMessageInfo> messageIterator = changeInfo.messages.iterator();
+ CherryPickInput input = new CherryPickInput();
+ input.destination = destBranch;
+ input.message =
+ String.format(
+ "it goes to foo branch\n\nChange-Id: Ideadbeefdeadbeefdeadbeefdeadbeefdeadbeef\n\nChange-Id: %s\n",
+ changeId);
+
+ ChangeInfo cherryPickResult =
+ gApi.projects()
+ .name(project.get())
+ .commit(commitToCherryPick.getName())
+ .cherryPick(input)
+ .get();
+
+ // No change was found in destination branch with the provided Change-Id.
+ assertThat(cherryPickResult._number).isGreaterThan(changeToCherryPick._number);
+ assertThat(cherryPickResult.changeId).isEqualTo(changeId);
+ assertThat(cherryPickResult.revisions).hasSize(1);
+ assertThat(cherryPickResult.messages).hasSize(1);
+ Iterator<ChangeMessageInfo> messageIterator = cherryPickResult.messages.iterator();
String expectedMessage =
- String.format("Patch Set 1: Cherry Picked from commit %s.", revCommit.getName());
+ String.format("Patch Set 1: Cherry Picked from commit %s.", commitToCherryPick.getName());
assertThat(messageIterator.next().message).isEqualTo(expectedMessage);
- RevisionInfo revInfo = changeInfo.revisions.get(changeInfo.currentRevision);
+ // Cherry-pick of is not set, because the source change was not provided.
+ assertThat(cherryPickResult.cherryPickOfChange).isNull();
+ assertThat(cherryPickResult.cherryPickOfPatchSet).isNull();
+ RevisionInfo revInfo = cherryPickResult.revisions.get(cherryPickResult.currentRevision);
+ assertThat(revInfo).isNotNull();
+ assertThat(revInfo.commit.message).isEqualTo(input.message);
+ }
+
+ @Test
+ public void cherryPickCommitToExistingChange() throws Exception {
+ String destBranch = "foo";
+ createBranch(BranchNameKey.create(project, destBranch));
+
+ PushOneCommit.Result r = createChange("refs/for/" + destBranch);
+ ChangeInfo existingDestChange = info(r.getChangeId());
+
+ String commitToCherryPick = createChange().getCommit().getName();
+
+ CherryPickInput input = new CherryPickInput();
+ input.destination = destBranch;
+ input.message =
+ String.format(
+ "it goes to foo branch\n\nChange-Id: Ideadbeefdeadbeefdeadbeefdeadbeefdeadbeef\n\nChange-Id: %s\n",
+ existingDestChange.changeId);
+ input.allowConflicts = true;
+ input.allowEmpty = true;
+
+ ChangeInfo cherryPickResult =
+ gApi.projects().name(project.get()).commit(commitToCherryPick).cherryPick(input).get();
+
+ // New patch-set to existing change was uploaded.
+ assertThat(cherryPickResult._number).isEqualTo(existingDestChange._number);
+ assertThat(cherryPickResult.changeId).isEqualTo(existingDestChange.changeId);
+ assertThat(cherryPickResult.messages).hasSize(2);
+ assertThat(cherryPickResult.revisions).hasSize(2);
+ Iterator<ChangeMessageInfo> messageIterator = cherryPickResult.messages.iterator();
+
+ assertThat(messageIterator.next().message).isEqualTo("Uploaded patch set 1.");
+ assertThat(messageIterator.next().message).isEqualTo("Uploaded patch set 2.");
+ // Cherry-pick of is not set, because the source change was not provided.
+ assertThat(cherryPickResult.cherryPickOfChange).isNull();
+ assertThat(cherryPickResult.cherryPickOfPatchSet).isNull();
+ RevisionInfo revInfo = cherryPickResult.revisions.get(cherryPickResult.currentRevision);
+ assertThat(revInfo).isNotNull();
+ assertThat(revInfo.commit.message).isEqualTo(input.message);
+ }
+
+ @Test
+ public void cherryPickCommitToExistingCherryPickedChange() throws Exception {
+ String destBranch = "foo";
+ createBranch(BranchNameKey.create(project, destBranch));
+
+ PushOneCommit.Result r = createChange("refs/for/" + destBranch);
+ ChangeInfo existingDestChange = info(r.getChangeId());
+
+ r = createChange();
+ ChangeInfo changeToCherryPick = info(r.getChangeId());
+ RevCommit commitToCherryPick = r.getCommit();
+
+ CherryPickInput input = new CherryPickInput();
+ input.destination = destBranch;
+ input.message =
+ String.format("it goes to foo branch\n\nChange-Id: %s\n", existingDestChange.changeId);
+ input.allowConflicts = true;
+ input.allowEmpty = true;
+ // Use RevisionAPI to submit initial cherryPick.
+ ChangeInfo cherryPickResult =
+ gApi.changes().id(changeToCherryPick.changeId).current().cherryPick(input).get();
+ assertThat(cherryPickResult.changeId).isEqualTo(existingDestChange.changeId);
+ // Cherry-pick was set.
+ assertThat(cherryPickResult.cherryPickOfChange).isEqualTo(changeToCherryPick._number);
+ assertThat(cherryPickResult.cherryPickOfPatchSet).isEqualTo(1);
+ RevisionInfo revInfo = cherryPickResult.revisions.get(cherryPickResult.currentRevision);
assertThat(revInfo).isNotNull();
- assertThat(revInfo.commit.message).isEqualTo(input.message + "\n");
+ assertThat(revInfo.commit.message).isEqualTo(input.message);
+ // Use CommitApi to update the cherryPick change.
+ cherryPickResult =
+ gApi.projects()
+ .name(project.get())
+ .commit(commitToCherryPick.getName())
+ .cherryPick(input)
+ .get();
+
+ assertThat(cherryPickResult.changeId).isEqualTo(existingDestChange.changeId);
+ assertThat(cherryPickResult.messages).hasSize(3);
+ Iterator<ChangeMessageInfo> messageIterator = cherryPickResult.messages.iterator();
+
+ assertThat(messageIterator.next().message).isEqualTo("Uploaded patch set 1.");
+ assertThat(messageIterator.next().message).isEqualTo("Uploaded patch set 2.");
+ assertThat(messageIterator.next().message).isEqualTo("Uploaded patch set 3.");
+ // Cherry-pick was reset to empty value.
+ assertThat(cherryPickResult._number).isEqualTo(existingDestChange._number);
+ assertThat(cherryPickResult.cherryPickOfChange).isNull();
+ assertThat(cherryPickResult.cherryPickOfPatchSet).isNull();
}
@Test
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
index 938fffc443..6b9859f4e3 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -3146,6 +3146,34 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
}
@Test
+ public void resetCherryPickOf() throws Exception {
+ Change destinationChange = newChange();
+ Change cherryPickChange = newChange();
+ assertThat(newNotes(destinationChange).getChange().getCherryPickOf()).isNull();
+
+ ChangeUpdate update = newUpdate(destinationChange, changeOwner);
+ update.setCherryPickOf(
+ cherryPickChange.currentPatchSetId().getCommaSeparatedChangeAndPatchSetId());
+ update.commit();
+ assertThat(newNotes(destinationChange).getChange().getCherryPickOf())
+ .isEqualTo(cherryPickChange.currentPatchSetId());
+
+ update = newUpdate(destinationChange, changeOwner);
+ update.resetCherryPickOf();
+ update.commit();
+ assertThat(newNotes(destinationChange).getChange().getCherryPickOf()).isNull();
+
+ // Can set again after reset.
+ cherryPickChange = newChange();
+ update = newUpdate(destinationChange, changeOwner);
+ update.setCherryPickOf(
+ cherryPickChange.currentPatchSetId().getCommaSeparatedChangeAndPatchSetId());
+ update.commit();
+ assertThat(newNotes(destinationChange).getChange().getCherryPickOf())
+ .isEqualTo(cherryPickChange.currentPatchSetId());
+ }
+
+ @Test
public void updateCount() throws Exception {
Change c = newChange();
assertThat(newNotes(c).getUpdateCount()).isEqualTo(1);