Merge changes I6a7f48e4,I3d0aacb0,I0b43eaef,I909a779b
* changes: DeleteRef: make sure permission and project state is checked DeleteRef: expose separate methods for deleting single/multi refs DeleteRef: remove its factory DeleteRef: move required input to method parameters
This commit is contained in:
@@ -23,9 +23,7 @@ import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.BranchResource;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
@@ -38,17 +36,12 @@ import java.io.IOException;
|
||||
public class DeleteBranch implements RestModifyView<BranchResource, Input> {
|
||||
|
||||
private final Provider<InternalChangeQuery> queryProvider;
|
||||
private final DeleteRef.Factory deleteRefFactory;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final DeleteRef deleteRef;
|
||||
|
||||
@Inject
|
||||
DeleteBranch(
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
DeleteRef.Factory deleteRefFactory,
|
||||
PermissionBackend permissionBackend) {
|
||||
DeleteBranch(Provider<InternalChangeQuery> queryProvider, DeleteRef deleteRef) {
|
||||
this.queryProvider = queryProvider;
|
||||
this.deleteRefFactory = deleteRefFactory;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.deleteRef = deleteRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,14 +53,11 @@ public class DeleteBranch implements RestModifyView<BranchResource, Input> {
|
||||
"not allowed to delete branch " + rsrc.getBranchKey().get());
|
||||
}
|
||||
|
||||
permissionBackend.currentUser().ref(rsrc.getBranchKey()).check(RefPermission.DELETE);
|
||||
rsrc.getProjectState().checkStatePermitsWrite();
|
||||
|
||||
if (!queryProvider.get().setLimit(1).byBranchOpen(rsrc.getBranchKey()).isEmpty()) {
|
||||
throw new ResourceConflictException("branch " + rsrc.getBranchKey() + " has open changes");
|
||||
}
|
||||
|
||||
deleteRefFactory.create(rsrc).ref(rsrc.getRef()).prefix(R_HEADS).delete();
|
||||
deleteRef.deleteSingleRef(rsrc.getProjectState(), rsrc.getRef(), R_HEADS);
|
||||
return Response.none();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package com.google.gerrit.server.restapi.project;
|
||||
|
||||
import static org.eclipse.jgit.lib.Constants.R_HEADS;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.extensions.api.projects.DeleteBranchesInput;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
@@ -30,11 +31,11 @@ import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
public class DeleteBranches implements RestModifyView<ProjectResource, DeleteBranchesInput> {
|
||||
private final DeleteRef.Factory deleteRefFactory;
|
||||
private final DeleteRef deleteRef;
|
||||
|
||||
@Inject
|
||||
DeleteBranches(DeleteRef.Factory deleteRefFactory) {
|
||||
this.deleteRefFactory = deleteRefFactory;
|
||||
DeleteBranches(DeleteRef deleteRef) {
|
||||
this.deleteRef = deleteRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +44,8 @@ public class DeleteBranches implements RestModifyView<ProjectResource, DeleteBra
|
||||
if (input == null || input.branches == null || input.branches.isEmpty()) {
|
||||
throw new BadRequestException("branches must be specified");
|
||||
}
|
||||
deleteRefFactory.create(project).refs(input.branches).prefix(R_HEADS).delete();
|
||||
deleteRef.deleteMultipleRefs(
|
||||
project.getProjectState(), ImmutableSet.copyOf(input.branches), R_HEADS);
|
||||
return Response.none();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,33 +14,35 @@
|
||||
|
||||
package com.google.gerrit.server.restapi.project;
|
||||
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.gerrit.reviewdb.client.RefNames.isConfigRef;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.eclipse.jgit.lib.Constants.R_REFS;
|
||||
import static org.eclipse.jgit.lib.Constants.R_TAGS;
|
||||
import static org.eclipse.jgit.transport.ReceiveCommand.Type.DELETE;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gerrit.common.Nullable;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.reviewdb.client.Branch;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.ProjectResource;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.gerrit.server.project.RefValidationHelper;
|
||||
import com.google.gerrit.server.query.change.InternalChangeQuery;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.eclipse.jgit.errors.LockFailedException;
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
import org.eclipse.jgit.lib.NullProgressMonitor;
|
||||
@@ -52,6 +54,7 @@ import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand.Result;
|
||||
|
||||
@Singleton
|
||||
public class DeleteRef {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@@ -64,13 +67,6 @@ public class DeleteRef {
|
||||
private final GitReferenceUpdated referenceUpdated;
|
||||
private final RefValidationHelper refDeletionValidator;
|
||||
private final Provider<InternalChangeQuery> queryProvider;
|
||||
private final ProjectResource resource;
|
||||
private final List<String> refsToDelete;
|
||||
private String prefix;
|
||||
|
||||
public interface Factory {
|
||||
DeleteRef create(ProjectResource r);
|
||||
}
|
||||
|
||||
@Inject
|
||||
DeleteRef(
|
||||
@@ -79,135 +75,164 @@ public class DeleteRef {
|
||||
GitRepositoryManager repoManager,
|
||||
GitReferenceUpdated referenceUpdated,
|
||||
RefValidationHelper.Factory refDeletionValidatorFactory,
|
||||
Provider<InternalChangeQuery> queryProvider,
|
||||
@Assisted ProjectResource resource) {
|
||||
Provider<InternalChangeQuery> queryProvider) {
|
||||
this.identifiedUser = identifiedUser;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.repoManager = repoManager;
|
||||
this.referenceUpdated = referenceUpdated;
|
||||
this.refDeletionValidator = refDeletionValidatorFactory.create(DELETE);
|
||||
this.queryProvider = queryProvider;
|
||||
this.resource = resource;
|
||||
this.refsToDelete = new ArrayList<>();
|
||||
}
|
||||
|
||||
public DeleteRef ref(String ref) {
|
||||
this.refsToDelete.add(ref);
|
||||
return this;
|
||||
/**
|
||||
* Deletes a single ref from the repository.
|
||||
*
|
||||
* @param projectState the {@code ProjectState} of the project containing the target ref.
|
||||
* @param ref the ref to be deleted.
|
||||
* @throws IOException
|
||||
* @throws ResourceConflictException
|
||||
*/
|
||||
public void deleteSingleRef(ProjectState projectState, String ref)
|
||||
throws IOException, ResourceConflictException, AuthException, PermissionBackendException {
|
||||
deleteSingleRef(projectState, ref, null);
|
||||
}
|
||||
|
||||
public DeleteRef refs(List<String> refs) {
|
||||
this.refsToDelete.addAll(refs);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeleteRef prefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void delete()
|
||||
throws OrmException, IOException, ResourceConflictException, PermissionBackendException {
|
||||
if (!refsToDelete.isEmpty()) {
|
||||
try (Repository r = repoManager.openRepository(resource.getNameKey())) {
|
||||
if (refsToDelete.size() == 1) {
|
||||
deleteSingleRef(r);
|
||||
} else {
|
||||
deleteMultipleRefs(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteSingleRef(Repository r) throws IOException, ResourceConflictException {
|
||||
String ref = refsToDelete.get(0);
|
||||
/**
|
||||
* Deletes a single ref from the repository.
|
||||
*
|
||||
* @param projectState the {@code ProjectState} of the project containing the target ref.
|
||||
* @param ref the ref to be deleted.
|
||||
* @param prefix the prefix of the ref.
|
||||
* @throws IOException
|
||||
* @throws ResourceConflictException
|
||||
*/
|
||||
public void deleteSingleRef(ProjectState projectState, String ref, @Nullable String prefix)
|
||||
throws IOException, ResourceConflictException, AuthException, PermissionBackendException {
|
||||
if (prefix != null && !ref.startsWith(R_REFS)) {
|
||||
ref = prefix + ref;
|
||||
}
|
||||
RefUpdate.Result result;
|
||||
RefUpdate u = r.updateRef(ref);
|
||||
u.setExpectedOldObjectId(r.exactRef(ref).getObjectId());
|
||||
u.setNewObjectId(ObjectId.zeroId());
|
||||
u.setForceUpdate(true);
|
||||
refDeletionValidator.validateRefOperation(resource.getName(), identifiedUser.get(), u);
|
||||
int remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
|
||||
for (; ; ) {
|
||||
try {
|
||||
result = u.delete();
|
||||
} catch (LockFailedException e) {
|
||||
result = RefUpdate.Result.LOCK_FAILURE;
|
||||
} catch (IOException e) {
|
||||
logger.atSevere().withCause(e).log("Cannot delete %s", ref);
|
||||
throw e;
|
||||
}
|
||||
if (result == RefUpdate.Result.LOCK_FAILURE && --remainingLockFailureCalls > 0) {
|
||||
|
||||
projectState.checkStatePermitsWrite();
|
||||
permissionBackend
|
||||
.currentUser()
|
||||
.project(projectState.getNameKey())
|
||||
.ref(ref)
|
||||
.check(RefPermission.DELETE);
|
||||
|
||||
try (Repository repository = repoManager.openRepository(projectState.getNameKey())) {
|
||||
RefUpdate.Result result;
|
||||
RefUpdate u = repository.updateRef(ref);
|
||||
u.setExpectedOldObjectId(repository.exactRef(ref).getObjectId());
|
||||
u.setNewObjectId(ObjectId.zeroId());
|
||||
u.setForceUpdate(true);
|
||||
refDeletionValidator.validateRefOperation(projectState.getName(), identifiedUser.get(), u);
|
||||
int remainingLockFailureCalls = MAX_LOCK_FAILURE_CALLS;
|
||||
for (; ; ) {
|
||||
try {
|
||||
Thread.sleep(SLEEP_ON_LOCK_FAILURE_MS);
|
||||
} catch (InterruptedException ie) {
|
||||
// ignore
|
||||
result = u.delete();
|
||||
} catch (LockFailedException e) {
|
||||
result = RefUpdate.Result.LOCK_FAILURE;
|
||||
} catch (IOException e) {
|
||||
logger.atSevere().withCause(e).log("Cannot delete %s", ref);
|
||||
throw e;
|
||||
}
|
||||
if (result == RefUpdate.Result.LOCK_FAILURE && --remainingLockFailureCalls > 0) {
|
||||
try {
|
||||
Thread.sleep(SLEEP_ON_LOCK_FAILURE_MS);
|
||||
} catch (InterruptedException ie) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case NEW:
|
||||
case NO_CHANGE:
|
||||
case FAST_FORWARD:
|
||||
case FORCED:
|
||||
referenceUpdated.fire(
|
||||
resource.getNameKey(), u, ReceiveCommand.Type.DELETE, identifiedUser.get().state());
|
||||
break;
|
||||
switch (result) {
|
||||
case NEW:
|
||||
case NO_CHANGE:
|
||||
case FAST_FORWARD:
|
||||
case FORCED:
|
||||
referenceUpdated.fire(
|
||||
projectState.getNameKey(),
|
||||
u,
|
||||
ReceiveCommand.Type.DELETE,
|
||||
identifiedUser.get().state());
|
||||
break;
|
||||
|
||||
case REJECTED_CURRENT_BRANCH:
|
||||
logger.atSevere().log("Cannot delete %s: %s", ref, result.name());
|
||||
throw new ResourceConflictException("cannot delete current branch");
|
||||
case REJECTED_CURRENT_BRANCH:
|
||||
logger.atSevere().log("Cannot delete %s: %s", ref, result.name());
|
||||
throw new ResourceConflictException("cannot delete current branch");
|
||||
|
||||
case IO_FAILURE:
|
||||
case LOCK_FAILURE:
|
||||
case NOT_ATTEMPTED:
|
||||
case REJECTED:
|
||||
case RENAMED:
|
||||
case REJECTED_MISSING_OBJECT:
|
||||
case REJECTED_OTHER_REASON:
|
||||
default:
|
||||
logger.atSevere().log("Cannot delete %s: %s", ref, result.name());
|
||||
throw new ResourceConflictException("cannot delete: " + result.name());
|
||||
case IO_FAILURE:
|
||||
case LOCK_FAILURE:
|
||||
case NOT_ATTEMPTED:
|
||||
case REJECTED:
|
||||
case RENAMED:
|
||||
case REJECTED_MISSING_OBJECT:
|
||||
case REJECTED_OTHER_REASON:
|
||||
default:
|
||||
logger.atSevere().log("Cannot delete %s: %s", ref, result.name());
|
||||
throw new ResourceConflictException("cannot delete: " + result.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteMultipleRefs(Repository r)
|
||||
throws OrmException, IOException, ResourceConflictException, PermissionBackendException {
|
||||
BatchRefUpdate batchUpdate = r.getRefDatabase().newBatchUpdate();
|
||||
batchUpdate.setAtomic(false);
|
||||
List<String> refs =
|
||||
prefix == null
|
||||
? refsToDelete
|
||||
: refsToDelete
|
||||
.stream()
|
||||
.map(ref -> ref.startsWith(R_REFS) ? ref : prefix + ref)
|
||||
.collect(toList());
|
||||
for (String ref : refs) {
|
||||
batchUpdate.addCommand(createDeleteCommand(resource, r, ref));
|
||||
/**
|
||||
* Deletes a set of refs from the repository.
|
||||
*
|
||||
* @param projectState the {@code ProjectState} of the project whose refs are to be deleted.
|
||||
* @param refsToDelete the refs to be deleted.
|
||||
* @param prefix the prefix of the refs.
|
||||
* @throws OrmException
|
||||
* @throws IOException
|
||||
* @throws ResourceConflictException
|
||||
* @throws PermissionBackendException
|
||||
*/
|
||||
public void deleteMultipleRefs(
|
||||
ProjectState projectState, ImmutableSet<String> refsToDelete, String prefix)
|
||||
throws OrmException, IOException, ResourceConflictException, PermissionBackendException,
|
||||
AuthException {
|
||||
if (refsToDelete.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try (RevWalk rw = new RevWalk(r)) {
|
||||
batchUpdate.execute(rw, NullProgressMonitor.INSTANCE);
|
||||
|
||||
if (refsToDelete.size() == 1) {
|
||||
deleteSingleRef(projectState, Iterables.getOnlyElement(refsToDelete), prefix);
|
||||
return;
|
||||
}
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
for (ReceiveCommand command : batchUpdate.getCommands()) {
|
||||
if (command.getResult() == Result.OK) {
|
||||
postDeletion(resource, command);
|
||||
} else {
|
||||
appendAndLogErrorMessage(errorMessages, command);
|
||||
|
||||
try (Repository repository = repoManager.openRepository(projectState.getNameKey())) {
|
||||
BatchRefUpdate batchUpdate = repository.getRefDatabase().newBatchUpdate();
|
||||
batchUpdate.setAtomic(false);
|
||||
ImmutableSet<String> refs =
|
||||
prefix == null
|
||||
? refsToDelete
|
||||
: refsToDelete
|
||||
.stream()
|
||||
.map(ref -> ref.startsWith(R_REFS) ? ref : prefix + ref)
|
||||
.collect(toImmutableSet());
|
||||
for (String ref : refs) {
|
||||
batchUpdate.addCommand(createDeleteCommand(projectState, repository, ref));
|
||||
}
|
||||
try (RevWalk rw = new RevWalk(repository)) {
|
||||
batchUpdate.execute(rw, NullProgressMonitor.INSTANCE);
|
||||
}
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
for (ReceiveCommand command : batchUpdate.getCommands()) {
|
||||
if (command.getResult() == Result.OK) {
|
||||
postDeletion(projectState.getNameKey(), command);
|
||||
} else {
|
||||
appendAndLogErrorMessage(errorMessages, command);
|
||||
}
|
||||
}
|
||||
if (errorMessages.length() > 0) {
|
||||
throw new ResourceConflictException(errorMessages.toString());
|
||||
}
|
||||
}
|
||||
if (errorMessages.length() > 0) {
|
||||
throw new ResourceConflictException(errorMessages.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private ReceiveCommand createDeleteCommand(ProjectResource project, Repository r, String refName)
|
||||
private ReceiveCommand createDeleteCommand(
|
||||
ProjectState projectState, Repository r, String refName)
|
||||
throws OrmException, IOException, ResourceConflictException, PermissionBackendException {
|
||||
Ref ref = r.getRefDatabase().getRef(refName);
|
||||
ReceiveCommand command;
|
||||
@@ -227,7 +252,7 @@ public class DeleteRef {
|
||||
try {
|
||||
permissionBackend
|
||||
.currentUser()
|
||||
.project(project.getNameKey())
|
||||
.project(projectState.getNameKey())
|
||||
.ref(refName)
|
||||
.check(RefPermission.DELETE);
|
||||
} catch (AuthException denied) {
|
||||
@@ -237,12 +262,12 @@ public class DeleteRef {
|
||||
}
|
||||
}
|
||||
|
||||
if (!project.getProjectState().statePermitsWrite()) {
|
||||
if (!projectState.statePermitsWrite()) {
|
||||
command.setResult(Result.REJECTED_OTHER_REASON, "project state does not permit write");
|
||||
}
|
||||
|
||||
if (!refName.startsWith(R_TAGS)) {
|
||||
Branch.NameKey branchKey = new Branch.NameKey(project.getNameKey(), ref.getName());
|
||||
Branch.NameKey branchKey = new Branch.NameKey(projectState.getNameKey(), ref.getName());
|
||||
if (!queryProvider.get().setLimit(1).byBranchOpen(branchKey).isEmpty()) {
|
||||
command.setResult(Result.REJECTED_OTHER_REASON, "it has open changes");
|
||||
}
|
||||
@@ -252,7 +277,7 @@ public class DeleteRef {
|
||||
u.setForceUpdate(true);
|
||||
u.setExpectedOldObjectId(r.exactRef(refName).getObjectId());
|
||||
u.setNewObjectId(ObjectId.zeroId());
|
||||
refDeletionValidator.validateRefOperation(project.getName(), identifiedUser.get(), u);
|
||||
refDeletionValidator.validateRefOperation(projectState.getName(), identifiedUser.get(), u);
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -281,7 +306,7 @@ public class DeleteRef {
|
||||
errorMessages.append("\n");
|
||||
}
|
||||
|
||||
private void postDeletion(ProjectResource project, ReceiveCommand cmd) {
|
||||
referenceUpdated.fire(project.getNameKey(), cmd, identifiedUser.get().state());
|
||||
private void postDeletion(Project.NameKey project, ReceiveCommand cmd) {
|
||||
referenceUpdated.fire(project, cmd, identifiedUser.get().state());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,7 @@ import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||
import com.google.gerrit.extensions.restapi.RestModifyView;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.RefPermission;
|
||||
import com.google.gerrit.server.project.RefUtil;
|
||||
import com.google.gerrit.server.project.TagResource;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
@@ -34,13 +32,11 @@ import java.io.IOException;
|
||||
@Singleton
|
||||
public class DeleteTag implements RestModifyView<TagResource, Input> {
|
||||
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final DeleteRef.Factory deleteRefFactory;
|
||||
private final DeleteRef deleteRef;
|
||||
|
||||
@Inject
|
||||
DeleteTag(PermissionBackend permissionBackend, DeleteRef.Factory deleteRefFactory) {
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.deleteRefFactory = deleteRefFactory;
|
||||
DeleteTag(DeleteRef deleteRef) {
|
||||
this.deleteRef = deleteRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,13 +49,7 @@ public class DeleteTag implements RestModifyView<TagResource, Input> {
|
||||
throw new MethodNotAllowedException("not allowed to delete " + tag);
|
||||
}
|
||||
|
||||
permissionBackend
|
||||
.currentUser()
|
||||
.project(resource.getNameKey())
|
||||
.ref(tag)
|
||||
.check(RefPermission.DELETE);
|
||||
resource.getProjectState().checkStatePermitsWrite();
|
||||
deleteRefFactory.create(resource).ref(tag).delete();
|
||||
deleteRef.deleteSingleRef(resource.getProjectState(), tag);
|
||||
return Response.none();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package com.google.gerrit.server.restapi.project;
|
||||
|
||||
import static org.eclipse.jgit.lib.Constants.R_TAGS;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gerrit.extensions.api.projects.DeleteTagsInput;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.Response;
|
||||
@@ -30,11 +31,11 @@ import java.io.IOException;
|
||||
|
||||
@Singleton
|
||||
public class DeleteTags implements RestModifyView<ProjectResource, DeleteTagsInput> {
|
||||
private final DeleteRef.Factory deleteRefFactory;
|
||||
private final DeleteRef deleteRef;
|
||||
|
||||
@Inject
|
||||
DeleteTags(DeleteRef.Factory deleteRefFactory) {
|
||||
this.deleteRefFactory = deleteRefFactory;
|
||||
DeleteTags(DeleteRef deleteRef) {
|
||||
this.deleteRef = deleteRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +44,8 @@ public class DeleteTags implements RestModifyView<ProjectResource, DeleteTagsInp
|
||||
if (input == null || input.tags == null || input.tags.isEmpty()) {
|
||||
throw new BadRequestException("tags must be specified");
|
||||
}
|
||||
deleteRefFactory.create(project).refs(input.tags).prefix(R_TAGS).delete();
|
||||
deleteRef.deleteMultipleRefs(
|
||||
project.getProjectState(), ImmutableSet.copyOf(input.tags), R_TAGS);
|
||||
return Response.none();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,6 @@ public class Module extends RestApiModule {
|
||||
put(PROJECT_KIND, "config").to(PutConfig.class);
|
||||
post(COMMIT_KIND, "cherrypick").to(CherryPickCommit.class);
|
||||
|
||||
factory(DeleteRef.Factory.class);
|
||||
factory(ProjectNode.Factory.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.google.gerrit.common.data.Permission;
|
||||
import com.google.gerrit.extensions.api.projects.BranchInput;
|
||||
import com.google.gerrit.extensions.api.projects.DeleteBranchesInput;
|
||||
import com.google.gerrit.extensions.api.projects.ProjectApi;
|
||||
import com.google.gerrit.extensions.restapi.AuthException;
|
||||
import com.google.gerrit.extensions.restapi.BadRequestException;
|
||||
import com.google.gerrit.extensions.restapi.ResourceConflictException;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
@@ -64,7 +65,24 @@ public class DeleteBranchesIT extends AbstractDaemonTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteBranchesForbidden() throws Exception {
|
||||
public void deleteOneBranchWithoutPermissionForbidden() throws Exception {
|
||||
ImmutableList<String> branchToDelete = ImmutableList.of("refs/heads/test-1");
|
||||
|
||||
DeleteBranchesInput input = new DeleteBranchesInput();
|
||||
input.branches = branchToDelete;
|
||||
setApiUser(user);
|
||||
try {
|
||||
project().deleteBranches(input);
|
||||
fail("Expected AuthException");
|
||||
} catch (AuthException e) {
|
||||
assertThat(e).hasMessageThat().isEqualTo("delete not permitted for refs/heads/test-1");
|
||||
}
|
||||
setApiUser(admin);
|
||||
assertBranches(BRANCHES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteMultiBranchesWithoutPermissionForbidden() throws Exception {
|
||||
DeleteBranchesInput input = new DeleteBranchesInput();
|
||||
input.branches = BRANCHES;
|
||||
setApiUser(user);
|
||||
|
||||
Reference in New Issue
Block a user