Merge "Fix bug about persisting copied votes on submit"
diff --git a/java/com/google/gerrit/server/change/PatchSetInserter.java b/java/com/google/gerrit/server/change/PatchSetInserter.java
index f093958..209901d 100644
--- a/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -104,6 +104,7 @@
private boolean allowClosed;
private boolean sendEmail = true;
private String topic;
+ private boolean storeCopiedVotes = true;
// Fields set during some phase of BatchUpdate.Op.
private Change change;
@@ -203,6 +204,17 @@
return this;
}
+ /**
+ * We always want to store copied votes except when the change is getting submitted and a new
+ * patch-set is created on submit (using submit strategies such as "REBASE_ALWAYS"). In such
+ * cases, we already store the votes of the new patch-sets in SubmitStrategyOp#saveApprovals. We
+ * should not also store the copied votes.
+ */
+ public PatchSetInserter setStoreCopiedVotes(boolean storeCopiedVotes) {
+ this.storeCopiedVotes = storeCopiedVotes;
+ return this;
+ }
+
public Change getChange() {
checkState(change != null, "getChange() only valid after executing update");
return change;
@@ -288,7 +300,9 @@
// Approvals that are being set in the new patch-set during this operation are not available yet
// outside of the scope of this method. Only copied approvals are set here.
- approvalsUtil.byPatchSet(ctx.getNotes(), patchSet).forEach(a -> update.putCopiedApproval(a));
+ if (storeCopiedVotes) {
+ approvalsUtil.byPatchSet(ctx.getNotes(), patchSet).forEach(a -> update.putCopiedApproval(a));
+ }
return true;
}
diff --git a/java/com/google/gerrit/server/change/RebaseChangeOp.java b/java/com/google/gerrit/server/change/RebaseChangeOp.java
index 4952464..3e67cca 100644
--- a/java/com/google/gerrit/server/change/RebaseChangeOp.java
+++ b/java/com/google/gerrit/server/change/RebaseChangeOp.java
@@ -92,6 +92,7 @@
private boolean detailedCommitMessage;
private boolean postMessage = true;
private boolean sendEmail = true;
+ private boolean storeCopiedVotes = true;
private boolean matchAuthorToCommitterDate = false;
private CodeReviewCommit rebasedCommit;
@@ -169,6 +170,17 @@
return this;
}
+ /**
+ * We always want to store copied votes except when the change is getting submitted and a new
+ * patch-set is created on submit (using submit strategies such as "REBASE_ALWAYS"). In such
+ * cases, we already store the votes of the new patch-sets in SubmitStrategyOp#saveApprovals. We
+ * should not also store the copied votes.
+ */
+ public RebaseChangeOp setStoreCopiedVotes(boolean storeCopiedVotes) {
+ this.storeCopiedVotes = storeCopiedVotes;
+ return this;
+ }
+
public RebaseChangeOp setSendEmail(boolean sendEmail) {
this.sendEmail = sendEmail;
return this;
@@ -219,7 +231,10 @@
.setFireRevisionCreated(fireRevisionCreated)
.setCheckAddPatchSetPermission(checkAddPatchSetPermission)
.setValidate(validate)
- .setSendEmail(sendEmail);
+ .setSendEmail(sendEmail)
+ // The votes are automatically copied and they don't count as copied votes. See
+ // method's javadoc.
+ .setStoreCopiedVotes(storeCopiedVotes);
if (!rebasedCommit.getFilesWithGitConflicts().isEmpty()
&& !notes.getChange().isWorkInProgress()) {
diff --git a/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java b/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
index cc3b75d..355d25f 100644
--- a/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
+++ b/java/com/google/gerrit/server/submit/RebaseSubmitStrategy.java
@@ -211,7 +211,10 @@
.setPostMessage(false)
.setSendEmail(false)
.setMatchAuthorToCommitterDate(
- args.project.is(BooleanProjectConfig.MATCH_AUTHOR_TO_COMMITTER_DATE));
+ args.project.is(BooleanProjectConfig.MATCH_AUTHOR_TO_COMMITTER_DATE))
+ // The votes are automatically copied and they don't count as copied votes. See
+ // method's javadoc.
+ .setStoreCopiedVotes(/* storeCopiedVotes = */ false);
try {
rebaseOp.updateRepo(ctx);
} catch (MergeConflictException | NoSuchChangeException e) {
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
index fff3cb6..b3592e3 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SubmitByCherryPickIT.java
@@ -14,9 +14,11 @@
package com.google.gerrit.acceptance.rest.change;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.extensions.client.ListChangesOption.MESSAGES;
+import static java.util.Comparator.comparing;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.ExtensionRegistry;
@@ -26,6 +28,10 @@
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.entities.BranchNameKey;
+import com.google.gerrit.entities.LabelId;
+import com.google.gerrit.entities.PatchSetApproval;
+import com.google.gerrit.entities.Project.NameKey;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.SubmitInput;
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.client.InheritableBoolean;
@@ -403,4 +409,54 @@
assertSubmittable(change2Result.getChangeId());
}
+
+ @Test
+ public void stickyVoteStoredOnSubmitOnNewPatchset_withoutCopyCondition() throws Exception {
+ try (ProjectConfigUpdate u = updateProject(NameKey.parse("All-Projects"))) {
+ u.getConfig()
+ .updateLabelType(
+ LabelId.CODE_REVIEW, b -> b.setCopyAllScoresIfListOfFilesDidNotChange(true));
+ u.save();
+ }
+ stickyVoteStoredOnSubmitOnNewPatchset();
+ }
+
+ @Test
+ public void stickyVoteStoredOnSubmitOnNewPatchset_withCopyCondition() throws Exception {
+ // Code-Review will be sticky.
+ try (ProjectConfigUpdate u = updateProject(NameKey.parse("All-Projects"))) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+ stickyVoteStoredOnSubmitOnNewPatchset();
+ }
+
+ private void stickyVoteStoredOnSubmitOnNewPatchset() throws Exception {
+ PushOneCommit.Result r = createChange();
+
+ // Add a new vote.
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 2);
+ gApi.changes().id(r.getChangeId()).current().review(input);
+
+ // Submit, also keeping the Code-Review +2 vote.
+ gApi.changes().id(r.getChangeId()).current().submit();
+
+ // The last approval is stored on the submitted patch-set which was created by cherry-pick
+ // during submit.
+ PatchSetApproval patchSetApprovals =
+ Iterables.getLast(
+ r.getChange().notes().getApprovalsWithCopied().values().stream()
+ .filter(a -> a.labelId().equals(LabelId.create(LabelId.CODE_REVIEW)))
+ .sorted(comparing(a -> a.patchSetId().get()))
+ .collect(toImmutableList()));
+
+ assertThat(patchSetApprovals.patchSetId().get()).isEqualTo(2);
+ assertThat(patchSetApprovals.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(patchSetApprovals.value()).isEqualTo((short) 2);
+
+ // The approval is not copied since we don't need to persist copied votes on submit, only
+ // persist votes normally.
+ assertThat(patchSetApprovals.copied()).isFalse();
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/SubmitByRebaseAlwaysIT.java b/javatests/com/google/gerrit/acceptance/rest/change/SubmitByRebaseAlwaysIT.java
index eeeac2a..aa93815 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/SubmitByRebaseAlwaysIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/SubmitByRebaseAlwaysIT.java
@@ -14,20 +14,27 @@
package com.google.gerrit.acceptance.rest.change;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.extensions.client.ListChangesOption.CURRENT_REVISION;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static java.util.Comparator.comparing;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.ExtensionRegistry;
import com.google.gerrit.acceptance.ExtensionRegistry.Registration;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.common.FooterConstants;
+import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.PatchSetApproval;
+import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.exceptions.InternalServerWithUserMessageException;
+import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ChangeInfo;
@@ -159,6 +166,56 @@
}
}
+ @Test
+ public void stickyVoteStoredOnSubmitOnNewPatchset_withoutCopyCondition() throws Exception {
+ try (ProjectConfigUpdate u = updateProject(NameKey.parse("All-Projects"))) {
+ u.getConfig()
+ .updateLabelType(
+ LabelId.CODE_REVIEW, b -> b.setCopyAllScoresIfListOfFilesDidNotChange(true));
+ u.save();
+ }
+ stickyVoteStoredOnSubmitOnNewPatchset();
+ }
+
+ @Test
+ public void stickyVoteStoredOnSubmitOnNewPatchset_withCopyCondition() throws Exception {
+ // Code-Review will be sticky.
+ try (ProjectConfigUpdate u = updateProject(NameKey.parse("All-Projects"))) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+ stickyVoteStoredOnSubmitOnNewPatchset();
+ }
+
+ private void stickyVoteStoredOnSubmitOnNewPatchset() throws Exception {
+ PushOneCommit.Result r = createChange();
+
+ // Add a new vote.
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 2);
+ gApi.changes().id(r.getChangeId()).current().review(input);
+
+ // Submit, also keeping the Code-Review +2 vote.
+ gApi.changes().id(r.getChangeId()).current().submit();
+
+ // The last approval is stored on the submitted patch-set which was created by rebase during
+ // submit.
+ PatchSetApproval patchSetApprovals =
+ Iterables.getLast(
+ r.getChange().notes().getApprovalsWithCopied().values().stream()
+ .filter(a -> a.labelId().equals(LabelId.create(LabelId.CODE_REVIEW)))
+ .sorted(comparing(a -> a.patchSetId().get()))
+ .collect(toImmutableList()));
+
+ assertThat(patchSetApprovals.patchSetId().get()).isEqualTo(2);
+ assertThat(patchSetApprovals.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(patchSetApprovals.value()).isEqualTo((short) 2);
+
+ // The approval is not copied since we don't need to persist copied votes on submit, only
+ // persist votes normally.
+ assertThat(patchSetApprovals.copied()).isFalse();
+ }
+
private void assertLatestRevisionHasFooters(PushOneCommit.Result change) throws Throwable {
RevCommit c = getCurrentCommit(change);
assertThat(c.getFooterLines(FooterConstants.CHANGE_ID)).isNotEmpty();