diff --git a/java/com/google/gerrit/server/restapi/project/CreateBranch.java b/java/com/google/gerrit/server/restapi/project/CreateBranch.java index c15fdeb663..b901057a86 100644 --- a/java/com/google/gerrit/server/restapi/project/CreateBranch.java +++ b/java/com/google/gerrit/server/restapi/project/CreateBranch.java @@ -17,7 +17,6 @@ package com.google.gerrit.server.restapi.project; import static com.google.gerrit.entities.RefNames.isConfigRef; import com.google.common.base.Strings; -import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.BranchNameKey; import com.google.gerrit.entities.RefNames; import com.google.gerrit.extensions.api.projects.BranchInfo; @@ -46,7 +45,6 @@ import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; import java.io.IOException; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.RefUpdate; @@ -58,8 +56,6 @@ import org.eclipse.jgit.transport.ReceiveCommand; @Singleton public class CreateBranch implements RestCollectionCreateView { - private static final FluentLogger logger = FluentLogger.forEnclosingClass(); - private final Provider identifiedUser; private final PermissionBackend permissionBackend; private final GitRepositoryManager repoManager; @@ -114,7 +110,7 @@ public class CreateBranch + "\""); } - final BranchNameKey name = BranchNameKey.create(rsrc.getNameKey(), ref); + BranchNameKey name = BranchNameKey.create(rsrc.getNameKey(), ref); try (Repository repo = repoManager.openRepository(rsrc.getNameKey())) { ObjectId revid = RefUtil.parseBaseRevision(repo, rsrc.getNameKey(), input.revision); RevWalk rw = RefUtil.verifyConnected(repo, revid); @@ -122,80 +118,71 @@ public class CreateBranch if (ref.startsWith(Constants.R_HEADS)) { // Ensure that what we start the branch from is a commit. If we - // were given a tag, deference to the commit instead. + // were given a tag, dereference to the commit instead. // - try { - object = rw.parseCommit(object); - } catch (IncorrectObjectTypeException notCommit) { - throw new BadRequestException("\"" + input.revision + "\" not a commit", notCommit); - } + object = rw.parseCommit(object); } createRefControl.checkCreateRef(identifiedUser, repo, name, object); - try { - final RefUpdate u = repo.updateRef(ref); - u.setExpectedOldObjectId(ObjectId.zeroId()); - u.setNewObjectId(object.copy()); - u.setRefLogIdent(identifiedUser.get().newRefLogIdent()); - u.setRefLogMessage("created via REST from " + input.revision, false); - refCreationValidator.validateRefOperation(rsrc.getName(), identifiedUser.get(), u); - final RefUpdate.Result result = u.update(rw); - switch (result) { - case FAST_FORWARD: - case NEW: - case NO_CHANGE: - referenceUpdated.fire( - name.project(), u, ReceiveCommand.Type.CREATE, identifiedUser.get().state()); - break; - case LOCK_FAILURE: - if (repo.getRefDatabase().exactRef(ref) != null) { - throw new ResourceConflictException("branch \"" + ref + "\" already exists"); + RefUpdate u = repo.updateRef(ref); + u.setExpectedOldObjectId(ObjectId.zeroId()); + u.setNewObjectId(object.copy()); + u.setRefLogIdent(identifiedUser.get().newRefLogIdent()); + u.setRefLogMessage("created via REST from " + input.revision, false); + refCreationValidator.validateRefOperation(rsrc.getName(), identifiedUser.get(), u); + RefUpdate.Result result = u.update(rw); + switch (result) { + case FAST_FORWARD: + case NEW: + case NO_CHANGE: + referenceUpdated.fire( + name.project(), u, ReceiveCommand.Type.CREATE, identifiedUser.get().state()); + break; + case LOCK_FAILURE: + if (repo.getRefDatabase().exactRef(ref) != null) { + throw new ResourceConflictException("branch \"" + ref + "\" already exists"); + } + String refPrefix = RefUtil.getRefPrefix(ref); + while (!Constants.R_HEADS.equals(refPrefix)) { + if (repo.getRefDatabase().exactRef(refPrefix) != null) { + throw new ResourceConflictException( + "Cannot create branch \"" + + ref + + "\" since it conflicts with branch \"" + + refPrefix + + "\"."); } - String refPrefix = RefUtil.getRefPrefix(ref); - while (!Constants.R_HEADS.equals(refPrefix)) { - if (repo.getRefDatabase().exactRef(refPrefix) != null) { - throw new ResourceConflictException( - "Cannot create branch \"" - + ref - + "\" since it conflicts with branch \"" - + refPrefix - + "\"."); - } - refPrefix = RefUtil.getRefPrefix(refPrefix); - } - throw new LockFailureException(String.format("Failed to create %s", ref), u); - case FORCED: - case IO_FAILURE: - case NOT_ATTEMPTED: - case REJECTED: - case REJECTED_CURRENT_BRANCH: - case RENAMED: - case REJECTED_MISSING_OBJECT: - case REJECTED_OTHER_REASON: - default: - throw new IOException(String.format("Failed to create %s: %s", ref, result.name())); - } - - BranchInfo info = new BranchInfo(); - info.ref = ref; - info.revision = revid.getName(); - - if (isConfigRef(name.branch())) { - // Never allow to delete the meta config branch. - info.canDelete = null; - } else { - info.canDelete = - permissionBackend.currentUser().ref(name).testOrFalse(RefPermission.DELETE) - && rsrc.getProjectState().statePermitsWrite() - ? true - : null; - } - return Response.created(info); - } catch (IOException err) { - logger.atSevere().withCause(err).log("Cannot create branch \"%s\"", name); - throw err; + refPrefix = RefUtil.getRefPrefix(refPrefix); + } + throw new LockFailureException(String.format("Failed to create %s", ref), u); + case FORCED: + case IO_FAILURE: + case NOT_ATTEMPTED: + case REJECTED: + case REJECTED_CURRENT_BRANCH: + case RENAMED: + case REJECTED_MISSING_OBJECT: + case REJECTED_OTHER_REASON: + default: + throw new IOException(String.format("Failed to create %s: %s", ref, result.name())); } + + BranchInfo info = new BranchInfo(); + info.ref = ref; + info.revision = revid.getName(); + + if (isConfigRef(name.branch())) { + // Never allow to delete the meta config branch. + info.canDelete = null; + } else { + info.canDelete = + permissionBackend.currentUser().ref(name).testOrFalse(RefPermission.DELETE) + && rsrc.getProjectState().statePermitsWrite() + ? true + : null; + } + return Response.created(info); } catch (RefUtil.InvalidRevisionException e) { throw new BadRequestException("invalid revision \"" + input.revision + "\"", e); } diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java index 311c264c58..b01a07bf51 100644 --- a/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateBranchIT.java @@ -50,6 +50,7 @@ import com.google.gerrit.server.validators.ValidationException; import com.google.inject.Inject; import java.io.IOException; import java.util.List; +import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; @@ -188,6 +189,23 @@ public class CreateBranchIT extends AbstractDaemonTest { assertCreateSucceeds(BranchNameKey.create(project, metaRef)); } + @Test + public void createMetaConfigBranch() throws Exception { + // Since the refs/meta/config branch exists by default, we must delete it before we can test + // creating it. Since deleting the refs/meta/config branch is not allowed through the API, we + // delete it directly in the remote repository. + try (TestRepository repo = + new TestRepository<>(repoManager.openRepository(project))) { + repo.delete(RefNames.REFS_CONFIG); + } + + // Create refs/meta/config branch. + BranchInfo created = + branch(BranchNameKey.create(project, RefNames.REFS_CONFIG)).create(new BranchInput()).get(); + assertThat(created.ref).isEqualTo(RefNames.REFS_CONFIG); + assertThat(created.canDelete).isNull(); + } + @Test public void createUserBranch_Conflict() throws Exception { projectOperations