mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-07 05:55:44 +01:00
add tag endpoints
This commit is contained in:
@@ -19,6 +19,8 @@ public class VndMediaType {
|
||||
public static final String PERMISSION = PREFIX + "permission" + SUFFIX;
|
||||
public static final String CHANGESET = PREFIX + "changeset" + SUFFIX;
|
||||
public static final String CHANGESET_COLLECTION = PREFIX + "changesetCollection" + SUFFIX;
|
||||
public static final String TAG = PREFIX + "tag" + SUFFIX;
|
||||
public static final String TAG_COLLECTION = PREFIX + "tagCollection" + SUFFIX;
|
||||
public static final String BRANCH = PREFIX + "branch" + SUFFIX;
|
||||
public static final String USER_COLLECTION = PREFIX + "userCollection" + SUFFIX;
|
||||
public static final String GROUP_COLLECTION = PREFIX + "groupCollection" + SUFFIX;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package sonia.scm.it;
|
||||
|
||||
import io.restassured.response.ExtractableResponse;
|
||||
import io.restassured.response.Response;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Before;
|
||||
@@ -8,18 +10,22 @@ import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.client.api.ClientCommand;
|
||||
import sonia.scm.repository.client.api.RepositoryClient;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static java.lang.Thread.sleep;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static sonia.scm.it.RestUtil.ADMIN_PASSWORD;
|
||||
import static sonia.scm.it.RestUtil.ADMIN_USERNAME;
|
||||
import static sonia.scm.it.RestUtil.given;
|
||||
import static sonia.scm.it.ScmTypes.availableScmTypes;
|
||||
|
||||
@@ -74,6 +80,88 @@ public class RepositoryAccessITCase {
|
||||
assertNotNull(branchName);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldFindTags() throws IOException {
|
||||
RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
|
||||
|
||||
Assume.assumeTrue("There are no tags for " + repositoryType, repositoryClient.isCommandSupported(ClientCommand.TAG));
|
||||
|
||||
Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "a.txt", "a");
|
||||
|
||||
String tagName = "v1.0";
|
||||
String repositoryUrl = TestData.getDefaultRepositoryUrl(repositoryType);
|
||||
String tagsUrl = given()
|
||||
.when()
|
||||
.get(repositoryUrl)
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_OK)
|
||||
.extract()
|
||||
.path("_links.tags.href");
|
||||
|
||||
ExtractableResponse<Response> response = given(VndMediaType.TAG_COLLECTION, ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
.when()
|
||||
.get(tagsUrl)
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_OK)
|
||||
.extract();
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.body()).isNotNull();
|
||||
assertThat(response.body().asString())
|
||||
.isNotNull()
|
||||
.isNotBlank()
|
||||
;
|
||||
|
||||
RepositoryUtil.addTag(repositoryClient, changeset.getId(), tagName);
|
||||
response = given(VndMediaType.TAG_COLLECTION, ADMIN_USERNAME, ADMIN_PASSWORD)
|
||||
.when()
|
||||
.get(tagsUrl)
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_OK)
|
||||
.extract()
|
||||
;
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.body()).isNotNull();
|
||||
assertThat(response.body().asString())
|
||||
.isNotNull()
|
||||
.isNotBlank()
|
||||
;
|
||||
assertThat(response.body().jsonPath().getString("_links.self.href"))
|
||||
.as("assert tags self link")
|
||||
.isNotNull()
|
||||
.contains(repositoryUrl + "/tags/")
|
||||
;
|
||||
assertThat(response.body().jsonPath().getList("_embedded.tags"))
|
||||
.as("assert tag size")
|
||||
.isNotNull()
|
||||
.size()
|
||||
.isGreaterThan(0)
|
||||
;
|
||||
assertThat(response.body().jsonPath().getMap("_embedded.tags.find{it.name=='" + tagName + "'}"))
|
||||
.as("assert tag name and revision")
|
||||
.isNotNull()
|
||||
.hasSize(3)
|
||||
.containsEntry("name", tagName)
|
||||
.containsEntry("revision", changeset.getId())
|
||||
;
|
||||
assertThat(response.body().jsonPath().getString("_embedded.tags.find{it.name=='" + tagName + "'}._links.self.href"))
|
||||
.as("assert single tag self link")
|
||||
.isNotNull()
|
||||
.contains(String.format("%s/tags/%s", repositoryUrl, tagName))
|
||||
;
|
||||
assertThat(response.body().jsonPath().getString("_embedded.tags.find{it.name=='" + tagName + "'}._links.sources.href"))
|
||||
.as("assert single tag source link")
|
||||
.isNotNull()
|
||||
.contains(String.format("%s/sources/%s", repositoryUrl, changeset.getId()))
|
||||
;
|
||||
assertThat(response.body().jsonPath().getString("_embedded.tags.find{it.name=='" + tagName + "'}._links.changesets.href"))
|
||||
.as("assert single tag changesets link")
|
||||
.isNotNull()
|
||||
.contains(String.format("%s/changesets/%s", repositoryUrl, changeset.getId()))
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReadContent() throws IOException, InterruptedException {
|
||||
RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.google.common.io.Files;
|
||||
import org.apache.http.HttpStatus;
|
||||
import sonia.scm.repository.Changeset;
|
||||
import sonia.scm.repository.Person;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.client.api.ClientCommand;
|
||||
import sonia.scm.repository.client.api.RepositoryClient;
|
||||
import sonia.scm.repository.client.api.RepositoryClientFactory;
|
||||
@@ -36,11 +37,11 @@ public class RepositoryUtil {
|
||||
return name;
|
||||
}
|
||||
|
||||
static void createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException {
|
||||
static Changeset createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException {
|
||||
File file = new File(repositoryClient.getWorkingCopy(), fileName);
|
||||
Files.write(content, file, Charsets.UTF_8);
|
||||
addWithParentDirectories(repositoryClient, file);
|
||||
commit(repositoryClient, username, "added " + fileName);
|
||||
return commit(repositoryClient, username, "added " + fileName);
|
||||
}
|
||||
|
||||
private static String addWithParentDirectories(RepositoryClient repositoryClient, File file) throws IOException {
|
||||
@@ -64,4 +65,16 @@ public class RepositoryUtil {
|
||||
}
|
||||
return changeset;
|
||||
}
|
||||
|
||||
static Tag addTag(RepositoryClient repositoryClient, String revision, String tagName) throws IOException {
|
||||
if (repositoryClient.isCommandSupported(ClientCommand.TAG)) {
|
||||
Tag tag = repositoryClient.getTagCommand().setRevision(revision).tag(tagName, TestData.USER_SCM_ADMIN);
|
||||
if (repositoryClient.isCommandSupported(ClientCommand.PUSH)) {
|
||||
repositoryClient.getPushCommand().pushTags();
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ package sonia.scm.repository.client.spi;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
|
||||
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -73,11 +73,20 @@ public class GitPushCommand implements PushCommand
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void push() throws IOException
|
||||
public void push() throws IOException {
|
||||
push(() -> git.push().setPushAll());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushTags() throws IOException {
|
||||
push(() -> git.push().setPushTags());
|
||||
}
|
||||
|
||||
private void push(Supplier<org.eclipse.jgit.api.PushCommand> commandSupplier) throws RepositoryClientException
|
||||
{
|
||||
try
|
||||
{
|
||||
org.eclipse.jgit.api.PushCommand cmd = git.push().setPushAll();
|
||||
org.eclipse.jgit.api.PushCommand cmd = commandSupplier.get();
|
||||
|
||||
if (credentialsProvider != null)
|
||||
{
|
||||
|
||||
@@ -35,22 +35,20 @@ package sonia.scm.repository.client.spi;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.revwalk.RevObject;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
|
||||
import sonia.scm.repository.GitUtil;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
@@ -119,7 +117,11 @@ public class GitTagCommand implements TagCommand
|
||||
ref = git.tag().setObjectId(revObject).call();
|
||||
}
|
||||
|
||||
if (ref.isPeeled()) {
|
||||
tag = new Tag(request.getName(), ref.getPeeledObjectId().toString());
|
||||
} else {
|
||||
tag = new Tag(request.getName(), ref.getObjectId().toString());
|
||||
}
|
||||
|
||||
}
|
||||
catch (GitAPIException ex)
|
||||
|
||||
@@ -32,9 +32,10 @@ package sonia.scm.repository.client.spi;
|
||||
|
||||
import com.aragost.javahg.Repository;
|
||||
import com.aragost.javahg.commands.ExecutionException;
|
||||
import java.io.IOException;
|
||||
import sonia.scm.repository.client.api.RepositoryClientException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Mercurial implementation of the {@link PushCommand}.
|
||||
*
|
||||
@@ -64,4 +65,9 @@ public class HgPushCommand implements PushCommand
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushTags() throws IOException {
|
||||
push();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ package sonia.scm.repository.client.spi;
|
||||
|
||||
import com.aragost.javahg.Repository;
|
||||
import com.google.common.base.Strings;
|
||||
import java.io.IOException;
|
||||
import sonia.scm.repository.Tag;
|
||||
|
||||
/**
|
||||
@@ -51,13 +50,16 @@ public class HgTagCommand implements TagCommand
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag tag(TagRequest request) throws IOException
|
||||
public Tag tag(TagRequest request)
|
||||
{
|
||||
String rev = request.getRevision();
|
||||
if ( Strings.isNullOrEmpty(rev) ){
|
||||
rev = repository.tip().getNode();
|
||||
}
|
||||
com.aragost.javahg.commands.TagCommand.on(repository).rev(rev).execute(request.getName());
|
||||
com.aragost.javahg.commands.TagCommand.on(repository)
|
||||
.rev(rev)
|
||||
.user(request.getUserName())
|
||||
.execute(request.getName());
|
||||
return new Tag(request.getName(), rev);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,13 +36,12 @@ package sonia.scm.repository.client.api;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.repository.client.spi.PushCommand;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
@@ -88,6 +87,14 @@ public final class PushCommandBuilder
|
||||
command.push();
|
||||
}
|
||||
|
||||
public void pushTags() throws IOException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("push tag changes back to main repository");
|
||||
}
|
||||
|
||||
command.pushTags();
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
|
||||
@@ -36,15 +36,14 @@ package sonia.scm.repository.client.api;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.client.spi.TagCommand;
|
||||
import sonia.scm.repository.client.spi.TagRequest;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
@@ -84,9 +83,10 @@ public final class TagCommandBuilder
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public Tag tag(String name) throws IOException
|
||||
public Tag tag(String name, String username) throws IOException
|
||||
{
|
||||
request.setName(name);
|
||||
request.setUsername(username);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
|
||||
@@ -44,11 +44,7 @@ import java.io.IOException;
|
||||
public interface PushCommand
|
||||
{
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void push() throws IOException;
|
||||
void push() throws IOException;
|
||||
|
||||
void pushTags() throws IOException;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ public final class TagRequest
|
||||
{
|
||||
this.name = null;
|
||||
this.revision = null;
|
||||
this.username = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,6 +107,7 @@ public final class TagRequest
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("revision", revision)
|
||||
.add("name", name)
|
||||
.add("username", username)
|
||||
.toString();
|
||||
//J+
|
||||
}
|
||||
@@ -134,6 +136,10 @@ public final class TagRequest
|
||||
this.revision = revision;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -158,6 +164,10 @@ public final class TagRequest
|
||||
return revision;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return username;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@@ -165,4 +175,6 @@ public final class TagRequest
|
||||
|
||||
/** Field description */
|
||||
private String revision;
|
||||
|
||||
private String username;
|
||||
}
|
||||
|
||||
@@ -218,8 +218,8 @@ class ResourceLinks {
|
||||
tagLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, TagRootResource.class);
|
||||
}
|
||||
|
||||
String self(String namespace, String name, String id) {
|
||||
return tagLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("tags").parameters().method("get").parameters(id).href();
|
||||
String self(String namespace, String name, String tagName) {
|
||||
return tagLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("tags").parameters().method("get").parameters(tagName).href();
|
||||
}
|
||||
|
||||
String all(String namespace, String name) {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import sonia.scm.NotFoundException;
|
||||
|
||||
public class TagNotFoundException extends NotFoundException {
|
||||
|
||||
}
|
||||
@@ -1,27 +1,100 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryNotFoundException;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.Tags;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TagRootResource {
|
||||
|
||||
private final RepositoryServiceFactory serviceFactory;
|
||||
private final TagCollectionToDtoMapper tagCollectionToDtoMapper;
|
||||
private final TagToTagDtoMapper tagToTagDtoMapper;
|
||||
|
||||
@Inject
|
||||
public TagRootResource(RepositoryServiceFactory serviceFactory,
|
||||
TagCollectionToDtoMapper tagCollectionToDtoMapper,
|
||||
TagToTagDtoMapper tagToTagDtoMapper) {
|
||||
this.serviceFactory = serviceFactory;
|
||||
this.tagCollectionToDtoMapper = tagCollectionToDtoMapper;
|
||||
this.tagToTagDtoMapper = tagToTagDtoMapper;
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("")
|
||||
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||
@DefaultValue("10") @QueryParam("pageSize") int pageSize,
|
||||
@QueryParam("sortBy") String sortBy,
|
||||
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||
throw new UnsupportedOperationException();
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the tags"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces(VndMediaType.TAG_COLLECTION)
|
||||
@TypeHint(CollectionDto.class)
|
||||
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws IOException, RepositoryNotFoundException {
|
||||
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
|
||||
Tags tags = getTags(repositoryService);
|
||||
if (tags != null && tags.getTags() != null) {
|
||||
return Response.ok(tagCollectionToDtoMapper.map(namespace, name, tags.getTags())).build();
|
||||
} else {
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Error on getting tag from repository.")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
public Response get(String id) {
|
||||
throw new UnsupportedOperationException();
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the tags"),
|
||||
@ResponseCode(code = 404, condition = "not found, no tag available in the repository"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces(VndMediaType.TAG)
|
||||
@TypeHint(TagDto.class)
|
||||
@Path("{tagName}")
|
||||
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("tagName") String tagName) throws IOException, RepositoryNotFoundException, TagNotFoundException {
|
||||
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
|
||||
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
|
||||
Tags tags = getTags(repositoryService);
|
||||
if (tags != null && tags.getTags() != null) {
|
||||
Tag tag = tags.getTags().stream()
|
||||
.filter(t -> tagName.equals(t.getName()))
|
||||
.findFirst()
|
||||
.orElseThrow(TagNotFoundException::new);
|
||||
return Response.ok(tagToTagDtoMapper.map(tag, namespaceAndName)).build();
|
||||
} else {
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
|
||||
.entity("Error on getting tag from repository.")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Tags getTags(RepositoryService repositoryService) throws IOException {
|
||||
Repository repository = repositoryService.getRepository();
|
||||
RepositoryPermissions.read(repository).check();
|
||||
return repositoryService.getTagsCommand().getTags();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import sonia.scm.repository.Tag;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static de.otto.edison.hal.Link.link;
|
||||
import static de.otto.edison.hal.Links.linkingTo;
|
||||
|
||||
@Mapper
|
||||
@@ -25,7 +26,9 @@ public abstract class TagToTagDtoMapper {
|
||||
@AfterMapping
|
||||
void appendLinks(@MappingTarget TagDto target, @Context NamespaceAndName namespaceAndName) {
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.self(resourceLinks.tag().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName()));
|
||||
.self(resourceLinks.tag().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName()))
|
||||
.single(link("sources", resourceLinks.source().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getRevision())))
|
||||
.single(link("changesets", resourceLinks.changeset().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getRevision())));
|
||||
target.add(linksBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ChangesetRootResourceTest {
|
||||
private RepositoryServiceFactory serviceFactory;
|
||||
|
||||
@Mock
|
||||
private RepositoryService service;
|
||||
private RepositoryService repositoryService;
|
||||
|
||||
@Mock
|
||||
private LogCommandBuilder logCommandBuilder;
|
||||
@@ -83,12 +83,12 @@ public class ChangesetRootResourceTest {
|
||||
.of(new RepositoryResource(null, null, null, null, null,
|
||||
MockProvider.of(changesetRootResource), null, null, null, null)), null);
|
||||
dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
|
||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(service);
|
||||
when(service.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo"));
|
||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
||||
when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo"));
|
||||
dispatcher.getProviderFactory().registerProvider(NotFoundExceptionMapper.class);
|
||||
dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class);
|
||||
when(service.getLogCommand()).thenReturn(logCommandBuilder);
|
||||
when(repositoryService.getLogCommand()).thenReturn(logCommandBuilder);
|
||||
subjectThreadState.bind();
|
||||
ThreadContext.bind(subject);
|
||||
when(subject.isPermitted(any(String.class))).thenReturn(true);
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.subject.support.SubjectThreadState;
|
||||
import org.apache.shiro.util.ThreadContext;
|
||||
import org.apache.shiro.util.ThreadState;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.jboss.resteasy.core.Dispatcher;
|
||||
import org.jboss.resteasy.mock.MockDispatcherFactory;
|
||||
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import sonia.scm.api.rest.AuthorizationExceptionMapper;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.Tag;
|
||||
import sonia.scm.repository.Tags;
|
||||
import sonia.scm.repository.api.RepositoryService;
|
||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||
import sonia.scm.repository.api.TagsCommandBuilder;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Slf4j
|
||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||
public class TagRootResourceTest {
|
||||
|
||||
public static final String TAG_PATH = "space/repo/tags/";
|
||||
public static final String TAG_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + TAG_PATH;
|
||||
private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
||||
|
||||
private final URI baseUri = URI.create("/");
|
||||
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||
|
||||
@Mock
|
||||
private RepositoryServiceFactory serviceFactory;
|
||||
|
||||
@Mock
|
||||
private RepositoryService repositoryService;
|
||||
|
||||
@Mock
|
||||
private TagsCommandBuilder tagsCommandBuilder;
|
||||
|
||||
private TagCollectionToDtoMapper tagCollectionToDtoMapper;
|
||||
|
||||
@InjectMocks
|
||||
private TagToTagDtoMapperImpl tagToTagDtoMapper;
|
||||
|
||||
private TagRootResource tagRootResource;
|
||||
|
||||
|
||||
private final Subject subject = mock(Subject.class);
|
||||
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
|
||||
|
||||
|
||||
@Before
|
||||
public void prepareEnvironment() throws Exception {
|
||||
tagCollectionToDtoMapper = new TagCollectionToDtoMapper(resourceLinks, tagToTagDtoMapper);
|
||||
tagRootResource = new TagRootResource(serviceFactory, tagCollectionToDtoMapper, tagToTagDtoMapper);
|
||||
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
|
||||
.of(new RepositoryResource(null, null, null, MockProvider.of(tagRootResource), null,
|
||||
null, null, null, null, null)), null);
|
||||
dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
|
||||
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(repositoryService);
|
||||
when(serviceFactory.create(any(Repository.class))).thenReturn(repositoryService);
|
||||
when(repositoryService.getRepository()).thenReturn(new Repository("repoId", "git", "space", "repo"));
|
||||
dispatcher.getProviderFactory().registerProvider(NotFoundExceptionMapper.class);
|
||||
dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class);
|
||||
when(repositoryService.getTagsCommand()).thenReturn(tagsCommandBuilder);
|
||||
subjectThreadState.bind();
|
||||
ThreadContext.bind(subject);
|
||||
when(subject.isPermitted(any(String.class))).thenReturn(true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupContext() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGet404OnMissingTag() throws Exception {
|
||||
Tags tags = new Tags();
|
||||
tags.setTags(Lists.emptyList());
|
||||
when(tagsCommandBuilder.getTags()).thenReturn(tags);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.get(TAG_URL + "not_existing_tag")
|
||||
.accept(VndMediaType.TAG);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(404, response.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetEmptyTagListOnMissingTags() throws Exception {
|
||||
Tags tags = new Tags();
|
||||
tags.setTags(Lists.emptyList());
|
||||
when(tagsCommandBuilder.getTags()).thenReturn(tags);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.get(TAG_URL)
|
||||
.accept(VndMediaType.TAG_COLLECTION);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(200, response.getStatus());
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.getContentAsString())
|
||||
.isNotBlank()
|
||||
.contains("_links")
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGet500OnTagCommandError() throws Exception {
|
||||
when(tagsCommandBuilder.getTags()).thenReturn(null);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.get(TAG_URL + "not_existing_tag")
|
||||
.accept(VndMediaType.TAG);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(500, response.getStatus());
|
||||
|
||||
request = MockHttpRequest
|
||||
.get(TAG_URL)
|
||||
.accept(VndMediaType.TAG_COLLECTION);
|
||||
response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(500, response.getStatus());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldGetTags() throws Exception {
|
||||
Tags tags = new Tags();
|
||||
String tag1 = "v1.0";
|
||||
String revision1 = "revision_1234";
|
||||
String tag2 = "v2.0";
|
||||
String revision2 = "revision_12345";
|
||||
tags.setTags(Lists.newArrayList(new Tag(tag1, revision1), new Tag(tag2, revision2)));
|
||||
when(tagsCommandBuilder.getTags()).thenReturn(tags);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.get(TAG_URL)
|
||||
.accept(VndMediaType.TAG_COLLECTION);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(200, response.getStatus());
|
||||
log.info("the content: ", response.getContentAsString());
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"name\":\"%s\"", tag1)));
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"revision\":\"%s\"", revision1)));
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"name\":\"%s\"", tag2)));
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"revision\":\"%s\"", revision2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetTag() throws Exception {
|
||||
Tags tags = new Tags();
|
||||
String tag1 = "v1.0";
|
||||
String revision1 = "revision_1234";
|
||||
String tag2 = "v2.0";
|
||||
String revision2 = "revision_12345";
|
||||
tags.setTags(Lists.newArrayList(new Tag(tag1, revision1), new Tag(tag2, revision2)));
|
||||
when(tagsCommandBuilder.getTags()).thenReturn(tags);
|
||||
|
||||
MockHttpRequest request = MockHttpRequest
|
||||
.get(TAG_URL + tag1)
|
||||
.accept(VndMediaType.TAG);
|
||||
MockHttpResponse response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(200, response.getStatus());
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"name\":\"%s\"", tag1)));
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"revision\":\"%s\"", revision1)));
|
||||
|
||||
request = MockHttpRequest
|
||||
.get(TAG_URL + tag2)
|
||||
.accept(VndMediaType.TAG);
|
||||
response = new MockHttpResponse();
|
||||
dispatcher.invoke(request, response);
|
||||
assertEquals(200, response.getStatus());
|
||||
log.info("the content: ", response.getContentAsString());
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"name\":\"%s\"", tag2)));
|
||||
assertTrue(response.getContentAsString().contains(String.format("\"revision\":\"%s\"", revision2)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user