Add REST API endpoint to delete a tag

Also-by: Paladox none <thomasmulhall410@yahoo.com>
Change-Id: I40f0a2ca40a615aa2bf757171aaf393afd9eb8ad
This commit is contained in:
David Pursehouse
2016-11-30 20:42:33 +09:00
parent 39806f60fe
commit e113216219
8 changed files with 130 additions and 18 deletions

View File

@@ -1886,6 +1886,23 @@ As response a link:#tag-info[TagInfo] entity is returned that describes the tag.
}
----
[[delete-tag]]
=== Delete Tag
--
'DELETE /projects/link:#project-name[\{project-name\}]/tags/link:#tag-id[\{tag-id\}]'
--
Deletes a tag.
.Request
----
DELETE /projects/MyProject/tags/v1.0 HTTP/1.0
----
.Response
----
HTTP/1.1 204 No Content
----
[[commit-endpoints]]
== Commit Endpoints

View File

@@ -22,6 +22,8 @@ public interface TagApi {
TagInfo get() throws RestApiException;
void delete() throws RestApiException;
/**
* A default implementation which allows source compatibility
* when adding new methods to the interface.
@@ -36,5 +38,10 @@ public interface TagApi {
public TagInfo get() throws RestApiException {
throw new NotImplementedException();
}
@Override
public void delete() throws RestApiException {
throw new NotImplementedException();
}
}
}

View File

@@ -20,8 +20,12 @@ import com.google.gerrit.extensions.api.projects.TagInput;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.project.CreateTag;
import com.google.gerrit.server.project.DeleteTag;
import com.google.gerrit.server.project.ListTags;
import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.project.TagResource;
import com.google.gerrit.server.project.TagsCollection;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -34,16 +38,22 @@ public class TagApiImpl implements TagApi {
private final ListTags listTags;
private final CreateTag.Factory createTagFactory;
private final DeleteTag deleteTag;
private final TagsCollection tags;
private final String ref;
private final ProjectResource project;
@Inject
TagApiImpl(ListTags listTags,
CreateTag.Factory createTagFactory,
DeleteTag deleteTag,
TagsCollection tags,
@Assisted ProjectResource project,
@Assisted String ref) {
this.listTags = listTags;
this.createTagFactory = createTagFactory;
this.deleteTag = deleteTag;
this.tags = tags;
this.project = project;
this.ref = ref;
}
@@ -66,4 +76,17 @@ public class TagApiImpl implements TagApi {
throw new RestApiException(e.getMessage());
}
}
@Override
public void delete() throws RestApiException {
try {
deleteTag.apply(resource(), new DeleteTag.Input());
} catch (OrmException | IOException e) {
throw new RestApiException(e.getMessage());
}
}
private TagResource resource() throws RestApiException, IOException {
return tags.parse(project, IdString.fromDecoded(ref));
}
}

View File

@@ -14,7 +14,6 @@
package com.google.gerrit.server.project;
import static org.eclipse.jgit.lib.Constants.R_REFS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import com.google.common.base.Strings;
@@ -90,18 +89,8 @@ public class CreateTag implements RestModifyView<ProjectResource, TagInput> {
if (input.revision == null) {
input.revision = Constants.HEAD;
}
while (ref.startsWith("/")) {
ref = ref.substring(1);
}
if (ref.startsWith(R_REFS) && !ref.startsWith(R_TAGS)) {
throw new BadRequestException("invalid tag name \"" + ref + "\"");
}
if (!ref.startsWith(R_TAGS)) {
ref = R_TAGS + ref;
}
if (!Repository.isValidRefName(ref)) {
throw new BadRequestException("invalid tag name \"" + ref + "\"");
}
ref = RefUtil.normalizeTagRef(ref);
RefControl refControl = resource.getControl().controlForRef(ref);
try (Repository repo = repoManager.openRepository(resource.getNameKey())) {

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.project;
import static java.lang.String.format;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import static org.eclipse.jgit.transport.ReceiveCommand.Type.DELETE;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -197,12 +198,13 @@ public class DeleteRef {
"it doesn't exist or you do not have permission to delete it");
}
//TODO: this check should not be done when deletion of tags is added
if (!refName.startsWith(R_TAGS)) {
Branch.NameKey branchKey =
new Branch.NameKey(project.getNameKey(), ref.getName());
if (!queryProvider.get().setLimit(1).byBranchOpen(branchKey).isEmpty()) {
command.setResult(Result.REJECTED_OTHER_REASON, "it has open changes");
}
}
RefUpdate u = r.updateRef(refName);
u.setForceUpdate(true);

View File

@@ -0,0 +1,52 @@
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.server.project;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@Singleton
public class DeleteTag implements RestModifyView<TagResource, DeleteTag.Input> {
private final DeleteRef.Factory deleteRefFactory;
public static class Input {
}
@Inject
DeleteTag(DeleteRef.Factory deleteRefFactory) {
this.deleteRefFactory = deleteRefFactory;
}
@Override
public Response<?> apply(TagResource resource, Input input)
throws OrmException, RestApiException, IOException {
String tag = RefUtil.normalizeTagRef(resource.getTagInfo().ref);
RefControl refControl = resource.getControl().controlForRef(tag);
if (!refControl.canDelete()) {
throw new AuthException("Cannot delete tag");
}
deleteRefFactory.create(resource).ref(tag).delete();
return Response.none();
}
}

View File

@@ -81,6 +81,7 @@ public class Module extends RestApiModule {
child(PROJECT_KIND, "tags").to(TagsCollection.class);
get(TAG_KIND).to(GetTag.class);
put(TAG_KIND).to(PutTag.class);
delete(TAG_KIND).to(DeleteTag.class);
factory(CreateTag.Factory.class);
child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class);

View File

@@ -14,7 +14,11 @@
package com.google.gerrit.server.project;
import static org.eclipse.jgit.lib.Constants.R_REFS;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
import com.google.common.collect.Iterables;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
@@ -99,6 +103,23 @@ public class RefUtil {
return Constants.R_HEADS;
}
public static String normalizeTagRef(String tag) throws BadRequestException {
String result = tag;
while (result.startsWith("/")) {
result = result.substring(1);
}
if (result.startsWith(R_REFS) && !result.startsWith(R_TAGS)) {
throw new BadRequestException("invalid tag name \"" + result + "\"");
}
if (!result.startsWith(R_TAGS)) {
result = R_TAGS + result;
}
if (!Repository.isValidRefName(result)) {
throw new BadRequestException("invalid tag name \"" + result + "\"");
}
return result;
}
/** Error indicating the revision is invalid as supplied. */
static class InvalidRevisionException extends Exception {
private static final long serialVersionUID = 1L;