From f5a46a41096da6b3af81ad6719309b08ac3702a5 Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Fri, 18 Aug 2017 12:50:46 +0200 Subject: [PATCH] Allow to create a change for the initial commit of refs/meta/config Normally you can only push commits for review to branches that exist. But there is an exception for the branch to which HEAD in the remote repository points (usually master). The same is true on submit, changes can only be submitted if the destination branch exists, except if the destination branch is the branch to which HEAD points. Relax this further and also allow to push an initial commit for review to the refs/meta/config branch and also allow to submit such a change. This is useful to setup an initial project configuration when the refs/meta/config branch is missing. Actually already today it is possible to create a change with an initial commit for the refs/meta/config branch, but then this change is not submittable because the destination branch is missing. The creation of such a change is possible by editing the access rights in the WebUI and then clicking on the 'Save for Review' button. This creates a change for the refs/meta/config branch regardless of whether the branch exists. Change-Id: I2e28fdd5384149d0ee32b10641652803c73842ab Signed-off-by: Edwin Kempin --- .../acceptance/git/AbstractPushForReview.java | 67 +++++++++++++++++++ .../com/google/gerrit/server/ProjectUtil.java | 4 +- .../gerrit/server/git/MergeOpRepoManager.java | 4 +- .../server/git/receive/ReceiveCommits.java | 4 +- 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java index 9e4cc67852..44e5eb0e5f 100644 --- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/git/AbstractPushForReview.java @@ -62,6 +62,7 @@ import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.ChangeMessage; import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.receive.ReceiveConstants; @@ -83,8 +84,11 @@ import java.util.regex.Pattern; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteRefUpdate; @@ -182,6 +186,69 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest { } } + @Test + public void pushInitialCommitForRefsMetaConfigBranch() throws Exception { + // delete refs/meta/config + try (Repository repo = repoManager.openRepository(project); + RevWalk rw = new RevWalk(repo)) { + RefUpdate u = repo.updateRef(RefNames.REFS_CONFIG); + u.setForceUpdate(true); + u.setExpectedOldObjectId(repo.resolve(RefNames.REFS_CONFIG)); + assertThat(u.delete(rw)).isEqualTo(Result.FORCED); + } + + RevCommit c = + testRepo + .commit() + .message("Initial commit") + .author(admin.getIdent()) + .committer(admin.getIdent()) + .insertChangeId() + .create(); + String id = GitUtil.getChangeId(testRepo, c).get(); + testRepo.reset(c); + + String r = "refs/for/" + RefNames.REFS_CONFIG; + PushResult pr = pushHead(testRepo, r, false); + assertPushOk(pr, r); + + ChangeInfo change = gApi.changes().id(id).info(); + assertThat(change.branch).isEqualTo(RefNames.REFS_CONFIG); + assertThat(change.status).isEqualTo(ChangeStatus.NEW); + + try (Repository repo = repoManager.openRepository(project)) { + assertThat(repo.resolve(RefNames.REFS_CONFIG)).isNull(); + } + + gApi.changes().id(change.id).current().review(ReviewInput.approve()); + gApi.changes().id(change.id).current().submit(); + + try (Repository repo = repoManager.openRepository(project)) { + assertThat(repo.resolve(RefNames.REFS_CONFIG)).isEqualTo(c); + } + } + + @Test + public void pushInitialCommitForNormalNonExistingBranchFails() throws Exception { + RevCommit c = + testRepo + .commit() + .message("Initial commit") + .author(admin.getIdent()) + .committer(admin.getIdent()) + .insertChangeId() + .create(); + testRepo.reset(c); + + String r = "refs/for/foo"; + PushResult pr = pushHead(testRepo, r, false); + assertPushRejected(pr, r, "branch foo not found"); + + try (Repository repo = repoManager.openRepository(project)) { + assertThat(repo.resolve("foo")).isNull(); + } + } + @Test public void output() throws Exception { String url = canonicalWebUrl.get(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ProjectUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ProjectUtil.java index 7688f1d052..1a327dbd3b 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/ProjectUtil.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/ProjectUtil.java @@ -15,6 +15,7 @@ package com.google.gerrit.server; import com.google.gerrit.reviewdb.client.Branch; +import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.server.git.GitRepositoryManager; import java.io.IOException; import org.eclipse.jgit.errors.RepositoryNotFoundException; @@ -37,7 +38,8 @@ public class ProjectUtil { try (Repository repo = repoManager.openRepository(branch.getParentKey())) { boolean exists = repo.getRefDatabase().exactRef(branch.get()) != null; if (!exists) { - exists = repo.getFullBranch().equals(branch.get()); + exists = + repo.getFullBranch().equals(branch.get()) || RefNames.REFS_CONFIG.equals(branch.get()); } return exists; } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOpRepoManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOpRepoManager.java index 6d208640c6..e7303e8c32 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOpRepoManager.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOpRepoManager.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkState; import com.google.common.collect.Maps; import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk; @@ -135,7 +136,8 @@ public class MergeOpRepoManager implements AutoCloseable { update = or.repo.updateRef(name.get()); if (update.getOldObjectId() != null) { oldTip = or.rw.parseCommit(update.getOldObjectId()); - } else if (Objects.equals(or.repo.getFullBranch(), name.get())) { + } else if (Objects.equals(or.repo.getFullBranch(), name.get()) + || Objects.equals(RefNames.REFS_CONFIG, name.get())) { oldTip = null; update.setExpectedOldObjectId(ObjectId.zeroId()); } else { diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java index 7f909d4a04..7e2410d9ea 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/receive/ReceiveCommits.java @@ -1430,7 +1430,9 @@ class ReceiveCommits { logDebug("Handling {}", RefNames.REFS_USERS_SELF); ref = RefNames.refsUsers(user.getAccountId()); } - if (!rp.getAdvertisedRefs().containsKey(ref) && !ref.equals(readHEAD(repo))) { + if (!rp.getAdvertisedRefs().containsKey(ref) + && !ref.equals(readHEAD(repo)) + && !ref.equals(RefNames.REFS_CONFIG)) { logDebug("Ref {} not found", ref); if (ref.startsWith(Constants.R_HEADS)) { String n = ref.substring(Constants.R_HEADS.length());