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]]
== Commit Endpoints == Commit Endpoints

View File

@@ -22,6 +22,8 @@ public interface TagApi {
TagInfo get() throws RestApiException; TagInfo get() throws RestApiException;
void delete() throws RestApiException;
/** /**
* A default implementation which allows source compatibility * A default implementation which allows source compatibility
* when adding new methods to the interface. * when adding new methods to the interface.
@@ -36,5 +38,10 @@ public interface TagApi {
public TagInfo get() throws RestApiException { public TagInfo get() throws RestApiException {
throw new NotImplementedException(); 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.IdString;
import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.project.CreateTag; 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.ListTags;
import com.google.gerrit.server.project.ProjectResource; 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.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
@@ -34,16 +38,22 @@ public class TagApiImpl implements TagApi {
private final ListTags listTags; private final ListTags listTags;
private final CreateTag.Factory createTagFactory; private final CreateTag.Factory createTagFactory;
private final DeleteTag deleteTag;
private final TagsCollection tags;
private final String ref; private final String ref;
private final ProjectResource project; private final ProjectResource project;
@Inject @Inject
TagApiImpl(ListTags listTags, TagApiImpl(ListTags listTags,
CreateTag.Factory createTagFactory, CreateTag.Factory createTagFactory,
DeleteTag deleteTag,
TagsCollection tags,
@Assisted ProjectResource project, @Assisted ProjectResource project,
@Assisted String ref) { @Assisted String ref) {
this.listTags = listTags; this.listTags = listTags;
this.createTagFactory = createTagFactory; this.createTagFactory = createTagFactory;
this.deleteTag = deleteTag;
this.tags = tags;
this.project = project; this.project = project;
this.ref = ref; this.ref = ref;
} }
@@ -66,4 +76,17 @@ public class TagApiImpl implements TagApi {
throw new RestApiException(e.getMessage()); 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; 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 static org.eclipse.jgit.lib.Constants.R_TAGS;
import com.google.common.base.Strings; import com.google.common.base.Strings;
@@ -90,18 +89,8 @@ public class CreateTag implements RestModifyView<ProjectResource, TagInput> {
if (input.revision == null) { if (input.revision == null) {
input.revision = Constants.HEAD; input.revision = Constants.HEAD;
} }
while (ref.startsWith("/")) {
ref = ref.substring(1); ref = RefUtil.normalizeTagRef(ref);
}
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 + "\"");
}
RefControl refControl = resource.getControl().controlForRef(ref); RefControl refControl = resource.getControl().controlForRef(ref);
try (Repository repo = repoManager.openRepository(resource.getNameKey())) { try (Repository repo = repoManager.openRepository(resource.getNameKey())) {

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.project; package com.google.gerrit.server.project;
import static java.lang.String.format; 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 static org.eclipse.jgit.transport.ReceiveCommand.Type.DELETE;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -197,11 +198,12 @@ public class DeleteRef {
"it doesn't exist or you do not have permission to delete it"); "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 = Branch.NameKey branchKey =
new Branch.NameKey(project.getNameKey(), ref.getName()); new Branch.NameKey(project.getNameKey(), ref.getName());
if (!queryProvider.get().setLimit(1).byBranchOpen(branchKey).isEmpty()) { if (!queryProvider.get().setLimit(1).byBranchOpen(branchKey).isEmpty()) {
command.setResult(Result.REJECTED_OTHER_REASON, "it has open changes"); command.setResult(Result.REJECTED_OTHER_REASON, "it has open changes");
}
} }
RefUpdate u = r.updateRef(refName); RefUpdate u = r.updateRef(refName);

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); child(PROJECT_KIND, "tags").to(TagsCollection.class);
get(TAG_KIND).to(GetTag.class); get(TAG_KIND).to(GetTag.class);
put(TAG_KIND).to(PutTag.class); put(TAG_KIND).to(PutTag.class);
delete(TAG_KIND).to(DeleteTag.class);
factory(CreateTag.Factory.class); factory(CreateTag.Factory.class);
child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class); child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class);

View File

@@ -14,7 +14,11 @@
package com.google.gerrit.server.project; 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.common.collect.Iterables;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.client.RefNames;
@@ -99,6 +103,23 @@ public class RefUtil {
return Constants.R_HEADS; 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. */ /** Error indicating the revision is invalid as supplied. */
static class InvalidRevisionException extends Exception { static class InvalidRevisionException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;