Fix exception in rejectEmptyCommit check on root commit Ied0c501a assumed that the commit always has one parent, which resulted in ArrayIndexOutOfBoundsException. There happened to be no test coverage for submitting a root commit with rejectEmptyCommit=true. Fix this by skipping the empty-commit check on the root commit, even when rejectEmptyCommit=true. This mirrors the fact that an empty commit is created when createEmptyCommit=true even when rejectEmptyCommit=true, and it provides a way to initialize the branch even if there should be no real data there yet. Change-Id: Ife12c2c472482d4602e85f5d350acc4a49d83c0d
diff --git a/Documentation/config-project-config.txt b/Documentation/config-project-config.txt index ac303e9..c3244cc 100644 --- a/Documentation/config-project-config.txt +++ b/Documentation/config-project-config.txt
@@ -256,7 +256,8 @@ - 'rejectEmptyCommit': Defines whether empty commits should be rejected when a change is merged. Changes might not seem empty at first but when attempting to merge, rebasing can lead to an empty -commit. If this option is set to 'true' the merge would fail. +commit. If this option is set to 'true' the merge would fail. An empty commit is still allowed as +the initial commit on a branch. Merge strategy
diff --git a/java/com/google/gerrit/server/submit/FastForwardOp.java b/java/com/google/gerrit/server/submit/FastForwardOp.java index f1749f4..08f5abb 100644 --- a/java/com/google/gerrit/server/submit/FastForwardOp.java +++ b/java/com/google/gerrit/server/submit/FastForwardOp.java
@@ -28,6 +28,7 @@ @Override protected void updateRepoImpl(RepoContext ctx) throws IntegrationException { if (args.project.is(BooleanProjectConfig.REJECT_EMPTY_COMMIT) + && toMerge.getParentCount() > 0 && toMerge.getTree().equals(toMerge.getParent(0).getTree())) { toMerge.setStatusCode(EMPTY_COMMIT); return;
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java index 61a2d84..5580279 100644 --- a/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java +++ b/javatests/com/google/gerrit/acceptance/rest/change/AbstractSubmit.java
@@ -27,6 +27,7 @@ import static java.util.stream.Collectors.toList; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -154,11 +155,12 @@ @Test @TestProjectInput(createEmptyCommit = false) public void submitToEmptyRepo() throws Exception { - RevCommit initialHead = getRemoteHead(); + assertThat(getRemoteHead()).isNull(); PushOneCommit.Result change = createChange(); + assertThat(change.getCommit().getParents()).isEmpty(); Map<Branch.NameKey, ObjectId> actual = fetchFromSubmitPreview(change.getChangeId()); RevCommit headAfterSubmitPreview = getRemoteHead(); - assertThat(headAfterSubmitPreview).isEqualTo(initialHead); + assertThat(headAfterSubmitPreview).isNull(); assertThat(actual).hasSize(1); submit(change.getChangeId()); @@ -1070,6 +1072,45 @@ change.current().submit(); } + @Test + @TestProjectInput(createEmptyCommit = false, rejectEmptyCommit = InheritableBoolean.TRUE) + public void submitNonemptyCommitToEmptyRepoWithRejectEmptyCommit_allowed() throws Exception { + assertThat(getRemoteHead()).isNull(); + PushOneCommit.Result change = createChange(); + assertThat(change.getCommit().getParents()).isEmpty(); + Map<Branch.NameKey, ObjectId> actual = fetchFromSubmitPreview(change.getChangeId()); + RevCommit headAfterSubmitPreview = getRemoteHead(); + assertThat(headAfterSubmitPreview).isNull(); + assertThat(actual).hasSize(1); + + submit(change.getChangeId()); + assertThat(getRemoteHead().getId()).isEqualTo(change.getCommit()); + assertTrees(project, actual); + } + + @Test + @TestProjectInput(createEmptyCommit = false, rejectEmptyCommit = InheritableBoolean.TRUE) + public void submitEmptyCommitToEmptyRepoWithRejectEmptyCommit_allowed() throws Exception { + assertThat(getRemoteHead()).isNull(); + PushOneCommit.Result change = + pushFactory + .create(db, admin.getIdent(), testRepo, "Change 1", ImmutableMap.of()) + .to("refs/for/master"); + change.assertOkStatus(); + // TODO(dborowitz): Use EMPTY_TREE_ID after upgrading to https://git.eclipse.org/r/127473 + assertThat(change.getCommit().getTree()) + .isEqualTo(ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")); + + Map<Branch.NameKey, ObjectId> actual = fetchFromSubmitPreview(change.getChangeId()); + RevCommit headAfterSubmitPreview = getRemoteHead(); + assertThat(headAfterSubmitPreview).isNull(); + assertThat(actual).hasSize(1); + + submit(change.getChangeId()); + assertThat(getRemoteHead().getId()).isEqualTo(change.getCommit()); + assertTrees(project, actual); + } + private void setChangeStatusToNew(PushOneCommit.Result... changes) throws Exception { for (PushOneCommit.Result change : changes) { try (BatchUpdate bu =