From 0b70c6227cc0495378ce7b234035cbba4cdf3483 Mon Sep 17 00:00:00 2001 From: Philipp Czora Date: Mon, 3 Sep 2018 15:36:09 +0200 Subject: [PATCH 1/9] Added integration test --- .../java/sonia/scm/it/RepositoryAccessITCase.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index a9139f18c8..ce3453f4af 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -16,8 +16,8 @@ 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.given; @@ -98,6 +98,7 @@ public class RepositoryAccessITCase { .statusCode(HttpStatus.SC_OK) .extract() .path("files.find{it.name=='a.txt'}._links.self.href"); + given() .when() .get(rootContentUrl) @@ -112,7 +113,15 @@ public class RepositoryAccessITCase { .statusCode(HttpStatus.SC_OK) .extract() .path("files.find{it.name=='subfolder'}._links.self.href"); - String subfolderContentUrl= given() + String selfOfSubfolderUrl = given() + .when() + .get(subfolderSourceUrl) + .then() + .statusCode(HttpStatus.SC_OK) + .extract() + .path("_links.self.href"); + assertThat(subfolderSourceUrl).isEqualTo(selfOfSubfolderUrl); + String subfolderContentUrl = given() .when() .get(subfolderSourceUrl) .then() From d7e319a856a8efaf68987bdbe80fc2186213f428 Mon Sep 17 00:00:00 2001 From: Philipp Czora Date: Mon, 3 Sep 2018 16:22:07 +0200 Subject: [PATCH 2/9] Fixes self-links in sources --- .../BrowserResultToBrowserResultDtoMapper.java | 11 +++++++---- .../scm/api/v2/resources/SourceRootResource.java | 2 +- .../BrowserResultToBrowserResultDtoMapperTest.java | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java index 7abb1ae69b..a334283b4b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java @@ -17,7 +17,7 @@ public class BrowserResultToBrowserResultDtoMapper { @Inject private ResourceLinks resourceLinks; - public BrowserResultDto map(BrowserResult browserResult, NamespaceAndName namespaceAndName) { + public BrowserResultDto map(BrowserResult browserResult, NamespaceAndName namespaceAndName, String path) { BrowserResultDto browserResultDto = new BrowserResultDto(); browserResultDto.setTag(browserResult.getTag()); @@ -30,7 +30,7 @@ public class BrowserResultToBrowserResultDtoMapper { } browserResultDto.setFiles(fileObjectDtoList); - this.addLinks(browserResult, browserResultDto, namespaceAndName); + this.addLinks(browserResult, browserResultDto, namespaceAndName, path); return browserResultDto; } @@ -38,11 +38,14 @@ public class BrowserResultToBrowserResultDtoMapper { return fileObjectToFileObjectDtoMapper.map(fileObject, namespaceAndName, revision); } - private void addLinks(BrowserResult browserResult, BrowserResultDto dto, NamespaceAndName namespaceAndName) { + private void addLinks(BrowserResult browserResult, BrowserResultDto dto, NamespaceAndName namespaceAndName, String path) { + if (path.equals("/")) { + path = ""; + } if (browserResult.getRevision() == null) { dto.add(Links.linkingTo().self(resourceLinks.source().selfWithoutRevision(namespaceAndName.getNamespace(), namespaceAndName.getName())).build()); } else { - dto.add(Links.linkingTo().self(resourceLinks.source().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision())).build()); + dto.add(Links.linkingTo().self(resourceLinks.source().sourceWithPath(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path)).build()); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java index fe12f69ecc..32a4105c46 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java @@ -61,7 +61,7 @@ public class SourceRootResource { BrowserResult browserResult = browseCommand.getBrowserResult(); if (browserResult != null) { - return Response.ok(browserResultToBrowserResultDtoMapper.map(browserResult, namespaceAndName)).build(); + return Response.ok(browserResultToBrowserResultDtoMapper.map(browserResult, namespaceAndName, path)).build(); } else { return Response.status(Response.Status.NOT_FOUND).build(); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java index bb7dadb566..f0e4c7e0d5 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java @@ -71,7 +71,7 @@ public class BrowserResultToBrowserResultDtoMapperTest { public void shouldMapAttributesCorrectly() { BrowserResult browserResult = createBrowserResult(); - BrowserResultDto dto = mapper.map(browserResult, new NamespaceAndName("foo", "bar")); + BrowserResultDto dto = mapper.map(browserResult, new NamespaceAndName("foo", "bar"), "path"); assertEqualAttributes(browserResult, dto); } @@ -81,12 +81,22 @@ public class BrowserResultToBrowserResultDtoMapperTest { BrowserResult browserResult = createBrowserResult(); NamespaceAndName namespaceAndName = new NamespaceAndName("foo", "bar"); - BrowserResultDto dto = mapper.map(browserResult, namespaceAndName); + BrowserResultDto dto = mapper.map(browserResult, namespaceAndName, "path"); verify(fileObjectToFileObjectDtoMapper).map(fileObject1, namespaceAndName, "Revision"); verify(fileObjectToFileObjectDtoMapper).map(fileObject2, namespaceAndName, "Revision"); } + @Test + public void shouldSetLinksCorrectly() { + BrowserResult browserResult = createBrowserResult(); + NamespaceAndName namespaceAndName = new NamespaceAndName("foo", "bar"); + + BrowserResultDto dto = mapper.map(browserResult, namespaceAndName, "path"); + + assertThat(dto.getLinks().getLinkBy("self").get().getHref()).contains("path"); + } + private BrowserResult createBrowserResult() { BrowserResult browserResult = new BrowserResult(); browserResult.setTag("Tag"); From 9b7e34b08b39c812b2b97fd1e5d924249112b3b5 Mon Sep 17 00:00:00 2001 From: Mohamed Karray Date: Tue, 4 Sep 2018 17:38:28 +0200 Subject: [PATCH 3/9] add tag endpoints --- .../main/java/sonia/scm/web/VndMediaType.java | 2 + .../sonia/scm/it/RepositoryAccessITCase.java | 90 +++++++- .../java/sonia/scm/it/RepositoryUtil.java | 17 +- .../repository/client/spi/GitPushCommand.java | 19 +- .../repository/client/spi/GitTagCommand.java | 12 +- .../repository/client/spi/HgPushCommand.java | 10 +- .../repository/client/spi/HgTagCommand.java | 8 +- .../client/api/PushCommandBuilder.java | 13 +- .../client/api/TagCommandBuilder.java | 8 +- .../repository/client/spi/PushCommand.java | 10 +- .../scm/repository/client/spi/TagRequest.java | 12 ++ .../scm/api/v2/resources/ResourceLinks.java | 4 +- .../v2/resources/TagNotFoundException.java | 7 + .../scm/api/v2/resources/TagRootResource.java | 93 +++++++- .../api/v2/resources/TagToTagDtoMapper.java | 5 +- .../resources/ChangesetRootResourceTest.java | 10 +- .../api/v2/resources/TagRootResourceTest.java | 201 ++++++++++++++++++ 17 files changed, 471 insertions(+), 50 deletions(-) create mode 100644 scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagNotFoundException.java create mode 100644 scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java diff --git a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java index 73bcf10bd0..ecab36969c 100644 --- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java +++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java @@ -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; diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index a9139f18c8..0211647321 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -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 = 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); diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java index ef2332074b..9fb1fcb236 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java @@ -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; + } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitPushCommand.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitPushCommand.java index 3b9d29abdf..8d65b54b06 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitPushCommand.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitPushCommand.java @@ -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 commandSupplier) throws RepositoryClientException { try { - org.eclipse.jgit.api.PushCommand cmd = git.push().setPushAll(); + org.eclipse.jgit.api.PushCommand cmd = commandSupplier.get(); if (credentialsProvider != null) { diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java index ee03dc7458..e5e1f36155 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/client/spi/GitTagCommand.java @@ -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(); } - tag = new Tag(request.getName(), ref.getPeeledObjectId().toString()); + if (ref.isPeeled()) { + tag = new Tag(request.getName(), ref.getPeeledObjectId().toString()); + } else { + tag = new Tag(request.getName(), ref.getObjectId().toString()); + } } catch (GitAPIException ex) diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgPushCommand.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgPushCommand.java index 73e0a1f9a4..263347ca00 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgPushCommand.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgPushCommand.java @@ -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}. * @@ -63,5 +64,10 @@ public class HgPushCommand implements PushCommand throw new RepositoryClientException("push to repository failed", ex); } } - + + @Override + public void pushTags() throws IOException { + push(); + } + } diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgTagCommand.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgTagCommand.java index 3aa448bfca..639adf9a1b 100644 --- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgTagCommand.java +++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgTagCommand.java @@ -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); } diff --git a/scm-test/src/main/java/sonia/scm/repository/client/api/PushCommandBuilder.java b/scm-test/src/main/java/sonia/scm/repository/client/api/PushCommandBuilder.java index b3b7619e7b..06b59e4ba0 100644 --- a/scm-test/src/main/java/sonia/scm/repository/client/api/PushCommandBuilder.java +++ b/scm-test/src/main/java/sonia/scm/repository/client/api/PushCommandBuilder.java @@ -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 */ diff --git a/scm-test/src/main/java/sonia/scm/repository/client/api/TagCommandBuilder.java b/scm-test/src/main/java/sonia/scm/repository/client/api/TagCommandBuilder.java index 8b42817aa8..1d153dee0e 100644 --- a/scm-test/src/main/java/sonia/scm/repository/client/api/TagCommandBuilder.java +++ b/scm-test/src/main/java/sonia/scm/repository/client/api/TagCommandBuilder.java @@ -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()) { diff --git a/scm-test/src/main/java/sonia/scm/repository/client/spi/PushCommand.java b/scm-test/src/main/java/sonia/scm/repository/client/spi/PushCommand.java index 5e85ed0e5e..be8fd94718 100644 --- a/scm-test/src/main/java/sonia/scm/repository/client/spi/PushCommand.java +++ b/scm-test/src/main/java/sonia/scm/repository/client/spi/PushCommand.java @@ -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; } diff --git a/scm-test/src/main/java/sonia/scm/repository/client/spi/TagRequest.java b/scm-test/src/main/java/sonia/scm/repository/client/spi/TagRequest.java index ff34309b6d..53abf0f8f8 100644 --- a/scm-test/src/main/java/sonia/scm/repository/client/spi/TagRequest.java +++ b/scm-test/src/main/java/sonia/scm/repository/client/spi/TagRequest.java @@ -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; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java index d51a462c19..1d3e5e222e 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ResourceLinks.java @@ -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) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagNotFoundException.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagNotFoundException.java new file mode 100644 index 0000000000..b572d20c5b --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagNotFoundException.java @@ -0,0 +1,7 @@ +package sonia.scm.api.v2.resources; + +import sonia.scm.NotFoundException; + +public class TagNotFoundException extends NotFoundException { + +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagRootResource.java index 10b4607fbc..b3601f7709 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagRootResource.java @@ -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(); + } + + } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java index ada0fa2887..917b4b7789 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/TagToTagDtoMapper.java @@ -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()); } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java index 570830d651..40aa61852a 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ChangesetRootResourceTest.java @@ -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); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java new file mode 100644 index 0000000000..029184e71f --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -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))); + } +} From e79041140f68e16e91248f694e38705438955cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Wed, 5 Sep 2018 15:17:49 +0200 Subject: [PATCH 4/9] Remove tags and branches from browse result and embed files --- .../sonia/scm/it/RepositoryAccessITCase.java | 6 +++--- .../api/v2/resources/BrowserResultDto.java | 20 +++---------------- ...BrowserResultToBrowserResultDtoMapper.java | 4 ---- .../FileObjectToFileObjectDtoMapper.java | 10 ++-------- .../scm/api/v2/resources/ResourceLinks.java | 13 ++++++------ ...serResultToBrowserResultDtoMapperTest.java | 8 ++++---- .../v2/resources/SourceRootResourceTest.java | 4 ---- 7 files changed, 19 insertions(+), 46 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index ce3453f4af..6184cc73e4 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -97,7 +97,7 @@ public class RepositoryAccessITCase { .then() .statusCode(HttpStatus.SC_OK) .extract() - .path("files.find{it.name=='a.txt'}._links.self.href"); + .path("_embedded.files.find{it.name=='a.txt'}._links.self.href"); given() .when() @@ -112,7 +112,7 @@ public class RepositoryAccessITCase { .then() .statusCode(HttpStatus.SC_OK) .extract() - .path("files.find{it.name=='subfolder'}._links.self.href"); + .path("_embedded.files.find{it.name=='subfolder'}._links.self.href"); String selfOfSubfolderUrl = given() .when() .get(subfolderSourceUrl) @@ -127,7 +127,7 @@ public class RepositoryAccessITCase { .then() .statusCode(HttpStatus.SC_OK) .extract() - .path("files[0]._links.self.href"); + .path("_embedded.files[0]._links.self.href"); given() .when() .get(subfolderContentUrl) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultDto.java index b8ffd7ff26..2b49f18fa1 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultDto.java @@ -6,18 +6,13 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import java.util.Iterator; import java.util.List; @Getter @Setter @NoArgsConstructor -public class BrowserResultDto extends HalRepresentation implements Iterable { +public class BrowserResultDto extends HalRepresentation { private String revision; - private String tag; - private String branch; - // REVIEW files nicht embedded? - private List files; @Override @SuppressWarnings("squid:S1185") // We want to have this method available in this package @@ -25,16 +20,7 @@ public class BrowserResultDto extends HalRepresentation implements Iterable iterator() { - Iterator it = null; - - if (files != null) - { - it = files.iterator(); - } - - return it; + public void setFiles(List files) { + this.withEmbedded("files", files); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java index a334283b4b..6ea6a11a2e 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java @@ -20,8 +20,6 @@ public class BrowserResultToBrowserResultDtoMapper { public BrowserResultDto map(BrowserResult browserResult, NamespaceAndName namespaceAndName, String path) { BrowserResultDto browserResultDto = new BrowserResultDto(); - browserResultDto.setTag(browserResult.getTag()); - browserResultDto.setBranch(browserResult.getBranch()); browserResultDto.setRevision(browserResult.getRevision()); List fileObjectDtoList = new ArrayList<>(); @@ -48,6 +46,4 @@ public class BrowserResultToBrowserResultDtoMapper { dto.add(Links.linkingTo().self(resourceLinks.source().sourceWithPath(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path)).build()); } } - - } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java index bc814c7e0c..fdcc5c56ca 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/FileObjectToFileObjectDtoMapper.java @@ -10,7 +10,6 @@ import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.SubRepository; import javax.inject.Inject; -import java.net.URI; @Mapper public abstract class FileObjectToFileObjectDtoMapper extends BaseMapper { @@ -27,19 +26,14 @@ public abstract class FileObjectToFileObjectDtoMapper extends BaseMapper Date: Wed, 5 Sep 2018 17:01:13 +0200 Subject: [PATCH 5/9] Fail for missing revision --- .../api/v2/resources/BrowserResultToBrowserResultDtoMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java index 6ea6a11a2e..c877cb0647 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapper.java @@ -41,7 +41,7 @@ public class BrowserResultToBrowserResultDtoMapper { path = ""; } if (browserResult.getRevision() == null) { - dto.add(Links.linkingTo().self(resourceLinks.source().selfWithoutRevision(namespaceAndName.getNamespace(), namespaceAndName.getName())).build()); + throw new IllegalStateException("missing revision in browser result for repository " + namespaceAndName + " and path " + path); } else { dto.add(Links.linkingTo().self(resourceLinks.source().sourceWithPath(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision(), path)).build()); } From b961a82e1536ed2d967dad72f235a56ec56908fb Mon Sep 17 00:00:00 2001 From: Philipp Czora Date: Thu, 6 Sep 2018 10:41:49 +0200 Subject: [PATCH 6/9] Minor refactoring --- .../sonia/scm/it/RepositoryAccessITCase.java | 35 +++++++++---------- .../api/v2/resources/TagRootResourceTest.java | 4 +-- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java index 0211647321..59fc70b9af 100644 --- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java +++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java @@ -109,8 +109,7 @@ public class RepositoryAccessITCase { assertThat(response.body()).isNotNull(); assertThat(response.body().asString()) .isNotNull() - .isNotBlank() - ; + .isNotBlank(); RepositoryUtil.addTag(repositoryClient, changeset.getId(), tagName); response = given(VndMediaType.TAG_COLLECTION, ADMIN_USERNAME, ADMIN_PASSWORD) @@ -118,48 +117,46 @@ public class RepositoryAccessITCase { .get(tagsUrl) .then() .statusCode(HttpStatus.SC_OK) - .extract() - ; + .extract(); assertThat(response).isNotNull(); assertThat(response.body()).isNotNull(); assertThat(response.body().asString()) .isNotNull() - .isNotBlank() - ; + .isNotBlank(); + assertThat(response.body().jsonPath().getString("_links.self.href")) .as("assert tags self link") .isNotNull() - .contains(repositoryUrl + "/tags/") - ; + .contains(repositoryUrl + "/tags/"); + assertThat(response.body().jsonPath().getList("_embedded.tags")) .as("assert tag size") .isNotNull() .size() - .isGreaterThan(0) - ; + .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()) - ; + .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)) - ; + .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())) - ; + .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())) - ; + .contains(String.format("%s/changesets/%s", repositoryUrl, changeset.getId())); } @Test @@ -200,6 +197,7 @@ public class RepositoryAccessITCase { .statusCode(HttpStatus.SC_OK) .extract() .path("files.find{it.name=='subfolder'}._links.self.href"); + String subfolderContentUrl= given() .when() .get(subfolderSourceUrl) @@ -207,6 +205,7 @@ public class RepositoryAccessITCase { .statusCode(HttpStatus.SC_OK) .extract() .path("files[0]._links.self.href"); + given() .when() .get(subfolderContentUrl) diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java index 029184e71f..92d11b3895 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/TagRootResourceTest.java @@ -121,9 +121,7 @@ public class TagRootResourceTest { assertThat(response).isNotNull(); assertThat(response.getContentAsString()) .isNotBlank() - .contains("_links") - ; - + .contains("_links"); } @Test From 20f50acf4635973a241ae0f5f6e4cf5c02351cf2 Mon Sep 17 00:00:00 2001 From: Philipp Czora Date: Thu, 6 Sep 2018 08:44:04 +0000 Subject: [PATCH 7/9] Close branch feature/tag_endpoints_v2 From a2182da8fa83f09132350cd96f89f6229d7e9c50 Mon Sep 17 00:00:00 2001 From: Philipp Czora Date: Thu, 6 Sep 2018 11:56:09 +0200 Subject: [PATCH 8/9] Made ArgumentMatchers in test match more specifically --- .../resources/BrowserResultToBrowserResultDtoMapperTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java index f11f631ccf..528418a187 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BrowserResultToBrowserResultDtoMapperTest.java @@ -19,6 +19,7 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -63,7 +64,8 @@ public class BrowserResultToBrowserResultDtoMapperTest { fileObject2.setDescription("description of file object 2"); fileObject2.setDirectory(true); - when(fileObjectToFileObjectDtoMapper.map(any(), any(), any())).thenReturn(new FileObjectDto()); + when(fileObjectToFileObjectDtoMapper.map(any(FileObject.class), any(NamespaceAndName.class), anyString())) + .thenReturn(new FileObjectDto()); } @After From dbde9181f2a643b80a166c535e83e8a71fd9eea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Thu, 6 Sep 2018 11:33:33 +0000 Subject: [PATCH 9/9] Close branch feature/self_link_bug