factories,
+ Collection preProcessors) {
+ PreProcessorHandler handler = new PreProcessorHandler(factories, preProcessors, repository);
+ handler.callPreProcessors(processedObject);
+ handler.callPreProcessorFactories(processedObject);
+ }
+
+ private , F extends PreProcessorFactory, P extends PreProcessor> void handlePreProcessForIterable(Repository repository, I processedObjects,
+ Collection factories,
+ Collection preProcessors) {
+ PreProcessorHandler handler = new PreProcessorHandler(factories, preProcessors, repository);
+ handler.callPreProcessors(processedObjects);
+ handler.callPreProcessorFactories(processedObjects);
+ }
+
//~--- inner classes --------------------------------------------------------
/**
@@ -454,6 +445,10 @@ public class PreProcessorUtil
/** Field description */
private final Collection changesetPreProcessorSet;
+ private final Collection modificationsPreProcessorFactorySet;
+
+ private final Collection modificationsPreProcessorSet;
+
/** Field description */
private final Collection fileObjectPreProcessorFactorySet;
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/Command.java b/scm-core/src/main/java/sonia/scm/repository/api/Command.java
index ccb0d8c2c0..2f844cfbfb 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/Command.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/Command.java
@@ -61,5 +61,11 @@ public enum Command
/**
* @since 1.43
*/
- BUNDLE, UNBUNDLE;
+ BUNDLE, UNBUNDLE,
+
+ /**
+ * @since 2.0
+ */
+ MODIFICATIONS
+
}
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java
new file mode 100644
index 0000000000..d81088bd33
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/repository/api/ModificationsCommandBuilder.java
@@ -0,0 +1,113 @@
+package sonia.scm.repository.api;
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+import lombok.extern.slf4j.Slf4j;
+import sonia.scm.cache.Cache;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.PreProcessorUtil;
+import sonia.scm.repository.Repository;
+import sonia.scm.repository.RepositoryCacheKey;
+import sonia.scm.repository.RevisionNotFoundException;
+import sonia.scm.repository.spi.ModificationsCommand;
+import sonia.scm.repository.spi.ModificationsCommandRequest;
+
+import java.io.IOException;
+
+/**
+ * Get the modifications applied to files in a revision.
+ *
+ * Modifications are for example: Add, Update and Delete
+ *
+ * @author Mohamed Karray
+ * @since 2.0
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Accessors(fluent = true)
+public final class ModificationsCommandBuilder {
+ static final String CACHE_NAME = "sonia.cache.cmd.modifications";
+
+ private final ModificationsCommand modificationsCommand;
+
+ private final ModificationsCommandRequest request = new ModificationsCommandRequest();
+
+ private final Repository repository;
+
+ private final Cache cache;
+
+ private final PreProcessorUtil preProcessorUtil;
+
+ @Setter
+ private boolean disableEscaping = false;
+
+ @Setter
+ private boolean disableCache = false;
+
+ @Setter
+ private boolean disablePreProcessors = false;
+
+ public ModificationsCommandBuilder revision(String revision){
+ request.setRevision(revision);
+ return this;
+ }
+
+ /**
+ * Reset each parameter to its default value.
+ *
+ *
+ * @return {@code this}
+ */
+ public ModificationsCommandBuilder reset() {
+ request.reset();
+ this.disableCache = false;
+ this.disablePreProcessors = false;
+ return this;
+ }
+
+ public Modifications getModifications() throws IOException, RevisionNotFoundException {
+ Modifications modifications;
+ if (disableCache) {
+ log.info("Get modifications for {} with disabled cache", request);
+ modifications = modificationsCommand.getModifications(request);
+ } else {
+ ModificationsCommandBuilder.CacheKey key = new ModificationsCommandBuilder.CacheKey(repository.getId(), request);
+ if (cache.contains(key)) {
+ modifications = cache.get(key);
+ log.debug("Get modifications for {} from the cache", request);
+ } else {
+ log.info("Get modifications for {} with enabled cache", request);
+ modifications = modificationsCommand.getModifications(request);
+ if (modifications != null) {
+ cache.put(key, modifications);
+ log.debug("Modifications for {} added to the cache with key {}", request, key);
+ }
+ }
+ }
+ if (!disablePreProcessors && (modifications != null)) {
+ preProcessorUtil.prepareForReturn(repository, modifications, !disableEscaping);
+ }
+ return modifications;
+ }
+
+ @AllArgsConstructor
+ @Getter
+ @Setter
+ @EqualsAndHashCode
+ @ToString
+ class CacheKey implements RepositoryCacheKey {
+ private final String repositoryId;
+ private final ModificationsCommandRequest request;
+
+ @Override
+ public String getRepositoryId() {
+ return repositoryId;
+ }
+ }
+
+}
diff --git a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java
index 27eed6becd..9eb7427a4f 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/RepositoryService.java
@@ -250,6 +250,18 @@ public final class RepositoryService implements Closeable {
repository, preProcessorUtil);
}
+ /**
+ * The modification command shows file modifications in a revision.
+ *
+ * @return instance of {@link ModificationsCommandBuilder}
+ * @throws CommandNotSupportedException if the command is not supported
+ * by the implementation of the repository service provider.
+ */
+ public ModificationsCommandBuilder getModificationsCommand() {
+ logger.debug("create modifications command for repository {}",repository.getNamespaceAndName());
+ return new ModificationsCommandBuilder(provider.getModificationsCommand(),repository, cacheManager.getCache(ModificationsCommandBuilder.CACHE_NAME), preProcessorUtil);
+ }
+
/**
* The outgoing command show {@link Changeset}s not found in a remote repository.
*
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java
similarity index 57%
rename from scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java
rename to scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java
index f7cb60e3df..e9b40e8a17 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnModificationHandler.java
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommand.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2010, Sebastian Sdorra
* All rights reserved.
*
@@ -29,60 +29,25 @@
*
*/
+package sonia.scm.repository.spi;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.RevisionNotFoundException;
-package sonia.scm.repository;
-
-//~--- non-JDK imports --------------------------------------------------------
-
-import org.tmatesoft.svn.core.SVNException;
-import org.tmatesoft.svn.core.wc.admin.ISVNChangeEntryHandler;
-import org.tmatesoft.svn.core.wc.admin.SVNChangeEntry;
+import java.io.IOException;
/**
+ * Command to get the modifications applied to files in a revision.
*
- * @author Sebastian Sdorra
+ * Modifications are for example: Add, Update, Delete
+ *
+ * @author Mohamed Karray
+ * @since 2.0
*/
-public class SvnModificationHandler implements ISVNChangeEntryHandler
-{
+public interface ModificationsCommand {
- /**
- * Constructs ...
- *
- *
- * @param changeset
- */
- public SvnModificationHandler(Changeset changeset)
- {
- this.changeset = changeset;
- }
+ Modifications getModifications(String revision) throws IOException, RevisionNotFoundException;
- //~--- methods --------------------------------------------------------------
+ Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException;
- /**
- * Method description
- *
- *
- * @param entry
- *
- * @throws SVNException
- */
- @Override
- public void handleEntry(SVNChangeEntry entry) throws SVNException
- {
- Modifications modification = changeset.getModifications();
-
- if (modification == null)
- {
- modification = new Modifications();
- changeset.setModifications(modification);
- }
-
- SvnUtil.appendModification(modification, entry);
- }
-
- //~--- fields ---------------------------------------------------------------
-
- /** Field description */
- private Changeset changeset;
}
diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java
new file mode 100644
index 0000000000..8a910a3396
--- /dev/null
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/ModificationsCommandRequest.java
@@ -0,0 +1,24 @@
+package sonia.scm.repository.spi;
+
+
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import lombok.ToString;
+
+@ToString
+@EqualsAndHashCode
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ModificationsCommandRequest implements Resetable {
+ private String revision;
+
+ @Override
+ public void reset() {
+ revision = null;
+ }
+}
diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java
index 976f38fffb..2f436836cd 100644
--- a/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/RepositoryServiceProvider.java
@@ -39,14 +39,13 @@ import sonia.scm.repository.Feature;
import sonia.scm.repository.api.Command;
import sonia.scm.repository.api.CommandNotSupportedException;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.Closeable;
import java.io.IOException;
-
import java.util.Collections;
import java.util.Set;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -173,6 +172,16 @@ public abstract class RepositoryServiceProvider implements Closeable
throw new CommandNotSupportedException(Command.LOG);
}
+ /**
+ * Get the corresponding {@link ModificationsCommand} implemented from the Plugins
+ *
+ * @return the corresponding {@link ModificationsCommand} implemented from the Plugins
+ * @throws CommandNotSupportedException if there is no Implementation
+ */
+ public ModificationsCommand getModificationsCommand() {
+ throw new CommandNotSupportedException(Command.MODIFICATIONS);
+ }
+
/**
* Method description
*
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 ddcce9f4e8..d9a6846795 100644
--- a/scm-core/src/main/java/sonia/scm/web/VndMediaType.java
+++ b/scm-core/src/main/java/sonia/scm/web/VndMediaType.java
@@ -21,6 +21,7 @@ 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 MODIFICATIONS = PREFIX + "modifications" + 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;
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 fc095828b3..398921a692 100644
--- a/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java
+++ b/scm-it/src/test/java/sonia/scm/it/RepositoryAccessITCase.java
@@ -3,6 +3,8 @@ package sonia.scm.it;
import io.restassured.response.ExtractableResponse;
import io.restassured.response.Response;
import org.apache.http.HttpStatus;
+import org.assertj.core.util.Lists;
+import org.assertj.core.util.Maps;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
@@ -17,8 +19,11 @@ import sonia.scm.web.VndMediaType;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import static java.lang.Thread.sleep;
import static org.assertj.core.api.Assertions.assertThat;
@@ -312,5 +317,163 @@ public class RepositoryAccessITCase {
}
);
}
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void shouldFindAddedModifications() throws IOException {
+ RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
+ String fileName = "a.txt";
+ Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a");
+ String revision = changeset.getId();
+ repositoryGetRequest
+ .usingRepositoryResponse()
+ .requestChangesets()
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingChangesetsResponse()
+ .requestModifications(revision)
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingModificationsResponse()
+ .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision))
+ .assertAdded(addedFiles -> assertThat(addedFiles)
+ .hasSize(1)
+ .containsExactly(fileName))
+ .assertRemoved(removedFiles -> assertThat(removedFiles)
+ .hasSize(0))
+ .assertModified(files -> assertThat(files)
+ .hasSize(0));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void shouldFindRemovedModifications() throws IOException {
+ RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
+ String fileName = "a.txt";
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a");
+ Changeset changeset = RepositoryUtil.removeAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName);
+
+ String revision = changeset.getId();
+ repositoryGetRequest
+ .usingRepositoryResponse()
+ .requestChangesets()
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingChangesetsResponse()
+ .requestModifications(revision)
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingModificationsResponse()
+ .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision))
+ .assertRemoved(removedFiles -> assertThat(removedFiles)
+ .hasSize(1)
+ .containsExactly(fileName))
+ .assertAdded(addedFiles -> assertThat(addedFiles)
+ .hasSize(0))
+ .assertModified(files -> assertThat(files)
+ .hasSize(0));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void shouldFindUpdateModifications() throws IOException {
+ RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
+ String fileName = "a.txt";
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "a");
+ Changeset changeset = RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, fileName, "new Content");
+
+ String revision = changeset.getId();
+ repositoryGetRequest
+ .usingRepositoryResponse()
+ .requestChangesets()
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingChangesetsResponse()
+ .requestModifications(revision)
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingModificationsResponse()
+ .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision))
+ .assertModified(modifiedFiles -> assertThat(modifiedFiles)
+ .hasSize(1)
+ .containsExactly(fileName))
+ .assertRemoved(removedFiles -> assertThat(removedFiles)
+ .hasSize(0))
+ .assertAdded(addedFiles -> assertThat(addedFiles)
+ .hasSize(0));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void shouldFindMultipleModifications() throws IOException {
+ RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "b.txt", "b");
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "c.txt", "c");
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "d.txt", "d");
+ Map addedFiles = new HashMap()
+ {{
+ put("a.txt", "bla bla");
+ }};
+ Map modifiedFiles = new HashMap()
+ {{
+ put("b.txt", "new content");
+ }};
+ ArrayList removedFiles = Lists.newArrayList("c.txt", "d.txt");
+ Changeset changeset = RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles);
+
+ String revision = changeset.getId();
+ repositoryGetRequest
+ .usingRepositoryResponse()
+ .requestChangesets()
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingChangesetsResponse()
+ .requestModifications(revision)
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingModificationsResponse()
+ .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision))
+ .assertAdded(a -> assertThat(a)
+ .hasSize(1)
+ .containsExactly("a.txt"))
+ .assertModified(m-> assertThat(m)
+ .hasSize(1)
+ .containsExactly("b.txt"))
+ .assertRemoved(r -> assertThat(r)
+ .hasSize(2)
+ .containsExactly("c.txt", "d.txt"));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void svnShouldCreateOneModificationPerFolder() throws IOException {
+ Assume.assumeThat(repositoryType, equalTo("svn"));
+ RepositoryClient repositoryClient = RepositoryUtil.createRepositoryClient(repositoryType, folder);
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "bbb/bb/b.txt", "b");
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "ccc/cc/c.txt", "c");
+ RepositoryUtil.createAndCommitFile(repositoryClient, ADMIN_USERNAME, "ddd/dd/d.txt", "d");
+ Map addedFiles = new HashMap()
+ {{
+ put("aaa/aa/a.txt", "bla bla");
+ }};
+ Map modifiedFiles = new HashMap()
+ {{
+ put("bbb/bb/b.txt", "new content");
+ }};
+ ArrayList removedFiles = Lists.newArrayList("ccc/cc/c.txt", "ddd/dd/d.txt");
+ Changeset changeset = RepositoryUtil.commitMultipleFileModifications(repositoryClient, ADMIN_USERNAME, addedFiles, modifiedFiles, removedFiles);
+
+ String revision = changeset.getId();
+ repositoryGetRequest
+ .usingRepositoryResponse()
+ .requestChangesets()
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingChangesetsResponse()
+ .requestModifications(revision)
+ .assertStatusCode(HttpStatus.SC_OK)
+ .usingModificationsResponse()
+ .assertRevision(actualRevision -> assertThat(actualRevision).isEqualTo(revision))
+ .assertAdded(a -> assertThat(a)
+ .hasSize(3)
+ .containsExactly("aaa/aa/a.txt", "aaa", "aaa/aa"))
+ .assertModified(m-> assertThat(m)
+ .hasSize(1)
+ .containsExactly("bbb/bb/b.txt"))
+ .assertRemoved(r -> assertThat(r)
+ .hasSize(2)
+ .containsExactly("ccc/cc/c.txt", "ddd/dd/d.txt"));
+ }
}
diff --git a/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java b/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java
index 41fa2a6a3d..79300d7b45 100644
--- a/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java
+++ b/scm-it/src/test/java/sonia/scm/it/RepositoryRequests.java
@@ -156,7 +156,7 @@ public class RepositoryRequests {
return new AppliedGetSourcesRequest(getResponseFromLink(repositoryResponse, "_links.sources.href"));
}
- AppliedGetChangesetsRequest requestChangesets(String fileName) {
+ AppliedGetChangesetsRequest requestChangesets() {
return new AppliedGetChangesetsRequest(getResponseFromLink(repositoryResponse, "_links.changesets.href"));
}
}
@@ -189,6 +189,9 @@ public class RepositoryRequests {
return new AppliedGetDiffRequest(getResponseFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.diff.href"));
}
+ public AppliedGetModificationsRequest requestModifications(String revision) {
+ return new AppliedGetModificationsRequest(getResponseFromLink(changesetsResponse, "_embedded.changesets.find{it.id=='" + revision + "'}._links.modifications.href"));
+ }
}
class AppliedGetSourcesRequest extends AppliedGetRequest {
@@ -246,4 +249,45 @@ public class RepositoryRequests {
return new GivenWithUrlAndAuth();
}
}
+
+ class AppliedGetModificationsRequest extends AppliedGetRequest {
+ public AppliedGetModificationsRequest(Response response) { super(response); }
+ ModificationsResponse usingModificationsResponse() {
+ return new ModificationsResponse(super.response);
+ }
+
+ }
+
+ class ModificationsResponse {
+ private Response resource;
+
+ public ModificationsResponse(Response resource) {
+ this.resource = resource;
+ }
+
+ ModificationsResponse assertRevision(Consumer assertRevision) {
+ String revision = resource.then().extract().path("revision");
+ assertRevision.accept(revision);
+ return this;
+ }
+
+ ModificationsResponse assertAdded(Consumer> assertAdded) {
+ List added = resource.then().extract().path("added");
+ assertAdded.accept(added);
+ return this;
+ }
+
+ ModificationsResponse assertRemoved(Consumer> assertRemoved) {
+ List removed = resource.then().extract().path("removed");
+ assertRemoved.accept(removed);
+ return this;
+ }
+
+ ModificationsResponse assertModified(Consumer> assertModified) {
+ List modified = resource.then().extract().path("modified");
+ assertModified.accept(modified);
+ return this;
+ }
+
+ }
}
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 0e2eb24ca9..96b92a0bed 100644
--- a/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java
+++ b/scm-it/src/test/java/sonia/scm/it/RepositoryUtil.java
@@ -14,6 +14,8 @@ import sonia.scm.repository.client.api.RepositoryClientFactory;
import java.io.File;
import java.io.IOException;
+import java.util.List;
+import java.util.Map;
import java.util.UUID;
public class RepositoryUtil {
@@ -42,11 +44,53 @@ public class RepositoryUtil {
}
static Changeset createAndCommitFile(RepositoryClient repositoryClient, String username, String fileName, String content) throws IOException {
+ writeAndAddFile(repositoryClient, fileName, content);
+ return commit(repositoryClient, username, "added " + fileName);
+ }
+
+ /**
+ * Bundle multiple File modification in one changeset
+ *
+ * @param repositoryClient
+ * @param username
+ * @param addedFiles map.key: path of the file, value: the file content
+ * @param modifiedFiles map.key: path of the file, value: the file content
+ * @param removedFiles list of file paths to be removed
+ * @return the changeset with all modifications
+ * @throws IOException
+ */
+ static Changeset commitMultipleFileModifications(RepositoryClient repositoryClient, String username, Map addedFiles, Map modifiedFiles, List removedFiles) throws IOException {
+ for (String fileName : addedFiles.keySet()) {
+ writeAndAddFile(repositoryClient, fileName, addedFiles.get(fileName));
+ }
+ for (String fileName : modifiedFiles.keySet()) {
+ writeAndAddFile(repositoryClient, fileName, modifiedFiles.get(fileName));
+ }
+ for (String fileName : removedFiles) {
+ deleteFileAndApplyRemoveCommand(repositoryClient, fileName);
+ }
+ return commit(repositoryClient, username, "multiple file modifications" );
+ }
+
+ private static File writeAndAddFile(RepositoryClient repositoryClient, String fileName, String content) throws IOException {
File file = new File(repositoryClient.getWorkingCopy(), fileName);
Files.createParentDirs(file);
Files.write(content, file, Charsets.UTF_8);
addWithParentDirectories(repositoryClient, file);
- return commit(repositoryClient, username, "added " + fileName);
+ return file;
+ }
+
+ static Changeset removeAndCommitFile(RepositoryClient repositoryClient, String username, String fileName) throws IOException {
+ deleteFileAndApplyRemoveCommand(repositoryClient, fileName);
+ return commit(repositoryClient, username, "removed " + fileName);
+ }
+
+ private static void deleteFileAndApplyRemoveCommand(RepositoryClient repositoryClient, String fileName) throws IOException {
+ File file = new File(repositoryClient.getWorkingCopy(), fileName);
+ if (repositoryClient.isCommandSupported(ClientCommand.REMOVE)) {
+ repositoryClient.getRemoveCommand().remove(fileName);
+ }
+ file.delete();
}
private static String addWithParentDirectories(RepositoryClient repositoryClient, File file) throws IOException {
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java
index a59e3b5754..6936c51269 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitChangesetConverter.java
@@ -37,32 +37,25 @@ package sonia.scm.repository;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
-
-import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import sonia.scm.util.Util;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.Closeable;
import java.io.IOException;
-
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -224,13 +217,6 @@ public class GitChangesetConverter implements Closeable
changeset.setParents(parentList);
}
- Modifications modifications = createModifications(treeWalk, commit);
-
- if (modifications != null)
- {
- changeset.setModifications(modifications);
- }
-
Collection tagCollection = tags.get(commit.getId());
if (Util.isNotEmpty(tagCollection))
@@ -245,108 +231,7 @@ public class GitChangesetConverter implements Closeable
return changeset;
}
- /**
- * TODO: copy and rename
- *
- *
- * @param modifications
- * @param entry
- */
- private void appendModification(Modifications modifications, DiffEntry entry)
- {
- switch (entry.getChangeType())
- {
- case ADD :
- modifications.getAdded().add(entry.getNewPath());
- break;
-
- case MODIFY :
- modifications.getModified().add(entry.getNewPath());
-
- break;
-
- case DELETE :
- modifications.getRemoved().add(entry.getOldPath());
-
- break;
- }
- }
-
- /**
- * Method description
- *
- *
- * @param treeWalk
- * @param commit
- *
- * @return
- *
- * @throws IOException
- */
- private Modifications createModifications(TreeWalk treeWalk, RevCommit commit)
- throws IOException
- {
- Modifications modifications = null;
-
- treeWalk.reset();
- treeWalk.setRecursive(true);
-
- if (commit.getParentCount() > 0)
- {
- RevCommit parent = commit.getParent(0);
- RevTree tree = parent.getTree();
-
- if ((tree == null) && (revWalk != null))
- {
- revWalk.parseHeaders(parent);
- tree = parent.getTree();
- }
-
- if (tree != null)
- {
- treeWalk.addTree(tree);
- }
- else
- {
- if (logger.isTraceEnabled())
- {
- logger.trace("no parent tree at position 0 for commit {}",
- commit.getName());
- }
-
- treeWalk.addTree(new EmptyTreeIterator());
- }
- }
- else
- {
- if (logger.isTraceEnabled())
- {
- logger.trace("no parent available for commit {}", commit.getName());
- }
-
- treeWalk.addTree(new EmptyTreeIterator());
- }
-
- treeWalk.addTree(commit.getTree());
-
- List entries = DiffEntry.scan(treeWalk);
-
- for (DiffEntry e : entries)
- {
- if (!e.getOldId().equals(e.getNewId()))
- {
- if (modifications == null)
- {
- modifications = new Modifications();
- }
-
- appendModification(modifications, e);
- }
- }
-
- return modifications;
- }
//~--- fields ---------------------------------------------------------------
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java
new file mode 100644
index 0000000000..2b35ba74f6
--- /dev/null
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModificationsCommand.java
@@ -0,0 +1,106 @@
+package sonia.scm.repository.spi;
+
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.EmptyTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import sonia.scm.repository.GitUtil;
+import sonia.scm.repository.InternalRepositoryException;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.Repository;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.List;
+
+
+@Slf4j
+public class GitModificationsCommand extends AbstractGitCommand implements ModificationsCommand {
+
+ protected GitModificationsCommand(GitContext context, Repository repository) {
+ super(context, repository);
+ }
+
+ private Modifications createModifications(TreeWalk treeWalk, RevCommit commit, RevWalk revWalk, String revision)
+ throws IOException, UnsupportedModificationTypeException {
+ treeWalk.reset();
+ treeWalk.setRecursive(true);
+ if (commit.getParentCount() > 0) {
+ RevCommit parent = commit.getParent(0);
+ RevTree tree = parent.getTree();
+ if ((tree == null) && (revWalk != null)) {
+ revWalk.parseHeaders(parent);
+ tree = parent.getTree();
+ }
+ if (tree != null) {
+ treeWalk.addTree(tree);
+ } else {
+ log.trace("no parent tree at position 0 for commit {}", commit.getName());
+ treeWalk.addTree(new EmptyTreeIterator());
+ }
+ } else {
+ log.trace("no parent available for commit {}", commit.getName());
+ treeWalk.addTree(new EmptyTreeIterator());
+ }
+ treeWalk.addTree(commit.getTree());
+ List entries = DiffEntry.scan(treeWalk);
+ Modifications modifications = new Modifications();
+ for (DiffEntry e : entries) {
+ if (!e.getOldId().equals(e.getNewId())) {
+ appendModification(modifications, e);
+ }
+ }
+ modifications.setRevision(revision);
+ return modifications;
+ }
+
+ @Override
+ public Modifications getModifications(String revision) {
+ org.eclipse.jgit.lib.Repository gitRepository = null;
+ RevWalk revWalk = null;
+ try {
+ gitRepository = open();
+ if (!gitRepository.getAllRefs().isEmpty()) {
+ revWalk = new RevWalk(gitRepository);
+ ObjectId id = GitUtil.getRevisionId(gitRepository, revision);
+ RevCommit commit = revWalk.parseCommit(id);
+ TreeWalk treeWalk = new TreeWalk(gitRepository);
+ return createModifications(treeWalk, commit, revWalk, revision);
+ }
+ } catch (IOException ex) {
+ log.error("could not open repository", ex);
+ throw new InternalRepositoryException(ex);
+
+ } catch (UnsupportedModificationTypeException ex) {
+ log.error("Unsupported modification type", ex);
+ throw new InternalRepositoryException(ex);
+
+ } finally {
+ GitUtil.release(revWalk);
+ GitUtil.close(gitRepository);
+ }
+ return null;
+ }
+
+ @Override
+ public Modifications getModifications(ModificationsCommandRequest request) {
+ return getModifications(request.getRevision());
+ }
+
+ private void appendModification(Modifications modifications, DiffEntry entry) throws UnsupportedModificationTypeException {
+ DiffEntry.ChangeType type = entry.getChangeType();
+ if (type == DiffEntry.ChangeType.ADD) {
+ modifications.getAdded().add(entry.getNewPath());
+ } else if (type == DiffEntry.ChangeType.MODIFY) {
+ modifications.getModified().add(entry.getNewPath());
+ } else if (type == DiffEntry.ChangeType.DELETE) {
+ modifications.getRemoved().add(entry.getOldPath());
+ } else {
+ throw new UnsupportedModificationTypeException(MessageFormat.format("The modification type: {0} is not supported.", type));
+ }
+ }
+}
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java
index 7ea26de83f..29744a8e9b 100644
--- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java
@@ -36,17 +36,15 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.collect.ImmutableSet;
-
import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.repository.Repository;
import sonia.scm.repository.api.Command;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.IOException;
-
import java.util.Set;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -188,6 +186,11 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider
return new GitLogCommand(context, repository);
}
+ @Override
+ public ModificationsCommand getModificationsCommand() {
+ return new GitModificationsCommand(context,repository);
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java
new file mode 100644
index 0000000000..5081a29d21
--- /dev/null
+++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/UnsupportedModificationTypeException.java
@@ -0,0 +1,9 @@
+package sonia.scm.repository.spi;
+
+import sonia.scm.repository.InternalRepositoryException;
+
+public class UnsupportedModificationTypeException extends InternalRepositoryException {
+ public UnsupportedModificationTypeException(String message) {
+ super(message);
+ }
+}
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java
index e2a401bf7d..97e09c0708 100644
--- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/AbstractRemoteCommandTestBase.java
@@ -85,14 +85,14 @@ public class AbstractRemoteCommandTestBase
outgoingDirectory = tempFolder.newFile("outgoing");
outgoingDirectory.delete();
- incomgingRepository = new Repository("1", "git", "space", "incoming");
+ incomingRepository = new Repository("1", "git", "space", "incoming");
outgoingRepository = new Repository("2", "git", "space", "outgoing");
incoming = Git.init().setDirectory(incomingDirectory).setBare(false).call();
outgoing = Git.init().setDirectory(outgoingDirectory).setBare(false).call();
handler = mock(GitRepositoryHandler.class);
- when(handler.getDirectory(incomgingRepository)).thenReturn(
+ when(handler.getDirectory(incomingRepository)).thenReturn(
incomingDirectory);
when(handler.getDirectory(outgoingRepository)).thenReturn(
outgoingDirectory);
@@ -211,7 +211,7 @@ public class AbstractRemoteCommandTestBase
protected GitRepositoryHandler handler;
/** Field description */
- protected Repository incomgingRepository;
+ protected Repository incomingRepository;
/** Field description */
protected Git incoming;
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java
index 6aa852b12c..e3d36601e7 100644
--- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitIncomingCommandTest.java
@@ -105,7 +105,7 @@ public class GitIncomingCommandTest
commit(outgoing, "added a");
- GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory), incomgingRepository);
+ GitPullCommand pull = new GitPullCommand(handler, new GitContext(incomingDirectory), incomingRepository);
PullCommandRequest req = new PullCommandRequest();
req.setRemoteRepository(outgoingRepository);
pull.pull(req);
@@ -192,6 +192,6 @@ public class GitIncomingCommandTest
private GitIncomingCommand createCommand()
{
return new GitIncomingCommand(handler, new GitContext(incomingDirectory),
- incomgingRepository);
+ incomingRepository);
}
}
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java
index 51df1298e5..d6e6ac98d8 100644
--- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitLogCommandTest.java
@@ -168,21 +168,23 @@ public class GitLogCommandTest extends AbstractGitCommandTestBase
Changeset c = command.getChangeset("435df2f061add3589cb3");
assertNotNull(c);
- assertEquals("435df2f061add3589cb326cc64be9b9c3897ceca", c.getId());
+ String revision = "435df2f061add3589cb326cc64be9b9c3897ceca";
+ assertEquals(revision, c.getId());
assertEquals("added a and b files", c.getDescription());
checkDate(c.getDate());
assertEquals("Douglas Adams", c.getAuthor().getName());
assertEquals("douglas.adams@hitchhiker.com", c.getAuthor().getMail());
assertEquals("added a and b files", c.getDescription());
- Modifications mods = c.getModifications();
+ GitModificationsCommand gitModificationsCommand = new GitModificationsCommand(createContext(), repository);
+ Modifications modifications = gitModificationsCommand.getModifications(revision);
- assertNotNull(mods);
- assertTrue("modified list should be empty", mods.getModified().isEmpty());
- assertTrue("removed list should be empty", mods.getRemoved().isEmpty());
- assertFalse("added list should not be empty", mods.getAdded().isEmpty());
- assertEquals(2, mods.getAdded().size());
- assertThat(mods.getAdded(), contains("a.txt", "b.txt"));
+ assertNotNull(modifications);
+ assertTrue("modified list should be empty", modifications.getModified().isEmpty());
+ assertTrue("removed list should be empty", modifications.getRemoved().isEmpty());
+ assertFalse("added list should not be empty", modifications.getAdded().isEmpty());
+ assertEquals(2, modifications.getAdded().size());
+ assertThat(modifications.getAdded(), contains("a.txt", "b.txt"));
}
@Test
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java
new file mode 100644
index 0000000000..fb982f6f0c
--- /dev/null
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModificationsCommandTest.java
@@ -0,0 +1,126 @@
+package sonia.scm.repository.spi;
+
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.junit.Before;
+import org.junit.Test;
+import sonia.scm.repository.Modifications;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.function.Consumer;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+
+public class GitModificationsCommandTest extends AbstractRemoteCommandTestBase {
+
+ private GitModificationsCommand incomingModificationsCommand;
+ private GitModificationsCommand outgoingModificationsCommand;
+
+ @Before
+ public void init() {
+ incomingModificationsCommand = new GitModificationsCommand(new GitContext(incomingDirectory), incomingRepository);
+ outgoingModificationsCommand = new GitModificationsCommand(new GitContext(outgoingDirectory), outgoingRepository);
+ }
+
+ @Test
+ public void shouldReadAddedFiles() throws Exception {
+ write(outgoing, outgoingDirectory, "a.txt", "bal bla");
+ RevCommit addedFileCommit = commit(outgoing, "add file");
+ String revision = addedFileCommit.getName();
+ Consumer assertModifications = assertAddedFiles("a.txt");
+ assertModifications.accept(outgoingModificationsCommand.getModifications(revision));
+ pushOutgoingAndPullIncoming();
+ assertModifications.accept(incomingModificationsCommand.getModifications(revision));
+ }
+
+ @Test
+ public void shouldReadModifiedFiles() throws Exception {
+ write(outgoing, outgoingDirectory, "a.txt", "bal bla");
+ commit(outgoing, "add file");
+ write(outgoing, outgoingDirectory, "a.txt", "modified content");
+ RevCommit modifiedFileCommit = commit(outgoing, "modify file");
+ String revision = modifiedFileCommit.getName();
+ Consumer assertModifications = assertModifiedFiles("a.txt");
+ assertModifications.accept(outgoingModificationsCommand.getModifications(revision));
+ pushOutgoingAndPullIncoming();
+ assertModifications.accept(incomingModificationsCommand.getModifications(revision));
+ }
+
+ @Test
+ public void shouldReadRemovedFiles() throws Exception {
+ String fileName = "a.txt";
+ write(outgoing, outgoingDirectory, fileName, "bal bla");
+ commit(outgoing, "add file");
+ File file = new File(outgoingDirectory, fileName);
+ file.delete();
+ outgoing.rm().addFilepattern(fileName).call();
+ RevCommit removedFileCommit = commit(outgoing, "remove file");
+ String revision = removedFileCommit.getName();
+ Consumer assertModifications = assertRemovedFiles(fileName);
+ pushOutgoingAndPullIncoming();
+ assertModifications.accept(incomingModificationsCommand.getModifications(revision));
+ assertModifications.accept(outgoingModificationsCommand.getModifications(revision));
+ }
+
+ void pushOutgoingAndPullIncoming() throws IOException {
+ GitPushCommand cmd = new GitPushCommand(handler, new GitContext(outgoingDirectory),
+ outgoingRepository);
+ PushCommandRequest request = new PushCommandRequest();
+ request.setRemoteRepository(incomingRepository);
+ cmd.push(request);
+ GitPullCommand pullCommand = new GitPullCommand(handler, new GitContext(incomingDirectory),
+ incomingRepository);
+ PullCommandRequest pullRequest = new PullCommandRequest();
+ pullRequest.setRemoteRepository(incomingRepository);
+ pullCommand.pull(pullRequest);
+ }
+
+ Consumer assertRemovedFiles(String fileName) {
+ return (modifications) -> {
+ assertThat(modifications).isNotNull();
+ assertThat(modifications.getAdded())
+ .as("added files modifications")
+ .hasSize(0);
+ assertThat(modifications.getModified())
+ .as("modified files modifications")
+ .hasSize(0);
+ assertThat(modifications.getRemoved())
+ .as("removed files modifications")
+ .hasSize(1)
+ .containsOnly(fileName);
+ };
+ }
+
+
+ Consumer assertModifiedFiles(String file) {
+ return (modifications) -> {
+ assertThat(modifications).isNotNull();
+ assertThat(modifications.getAdded())
+ .as("added files modifications")
+ .hasSize(0);
+ assertThat(modifications.getModified())
+ .as("modified files modifications")
+ .hasSize(1)
+ .containsOnly(file);
+ assertThat(modifications.getRemoved())
+ .as("removed files modifications")
+ .hasSize(0);
+ };
+ }
+
+ Consumer assertAddedFiles(String file) {
+ return (modifications) -> {
+ assertThat(modifications).isNotNull();
+ assertThat(modifications.getAdded())
+ .as("added files modifications")
+ .hasSize(1)
+ .containsOnly(file);
+ assertThat(modifications.getModified())
+ .as("modified files modifications")
+ .hasSize(0);
+ assertThat(modifications.getRemoved())
+ .as("removed files modifications")
+ .hasSize(0);
+ };
+ }
+}
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java
index 58f70109ef..3510650fb4 100644
--- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitOutgoingCommandTest.java
@@ -78,7 +78,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase
GitOutgoingCommand cmd = createCommand();
OutgoingCommandRequest request = new OutgoingCommandRequest();
- request.setRemoteRepository(incomgingRepository);
+ request.setRemoteRepository(incomingRepository);
ChangesetPagingResult cpr = cmd.getOutgoingChangesets(request);
@@ -98,7 +98,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase
* @throws RepositoryException
*/
@Test
- public void testGetOutgoingChangesetsWithAllreadyPushedChanges()
+ public void testGetOutgoingChangesetsWithAlreadyPushedChanges()
throws IOException, GitAPIException
{
write(outgoing, outgoingDirectory, "a.txt", "content of a.txt");
@@ -110,7 +110,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase
outgoingRepository);
PushCommandRequest req = new PushCommandRequest();
- req.setRemoteRepository(incomgingRepository);
+ req.setRemoteRepository(incomingRepository);
push.push(req);
write(outgoing, outgoingDirectory, "b.txt", "content of b.txt");
@@ -120,7 +120,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase
GitOutgoingCommand cmd = createCommand();
OutgoingCommandRequest request = new OutgoingCommandRequest();
- request.setRemoteRepository(incomgingRepository);
+ request.setRemoteRepository(incomingRepository);
ChangesetPagingResult cpr = cmd.getOutgoingChangesets(request);
@@ -144,7 +144,7 @@ public class GitOutgoingCommandTest extends AbstractRemoteCommandTestBase
GitOutgoingCommand cmd = createCommand();
OutgoingCommandRequest request = new OutgoingCommandRequest();
- request.setRemoteRepository(incomgingRepository);
+ request.setRemoteRepository(incomingRepository);
ChangesetPagingResult cpr = cmd.getOutgoingChangesets(request);
diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java
index 91fad57880..4f3d7e933d 100644
--- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java
+++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitPushCommandTest.java
@@ -78,7 +78,7 @@ public class GitPushCommandTest extends AbstractRemoteCommandTestBase
GitPushCommand cmd = createCommand();
PushCommandRequest request = new PushCommandRequest();
- request.setRemoteRepository(incomgingRepository);
+ request.setRemoteRepository(incomingRepository);
PushResponse response = cmd.push(request);
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java
new file mode 100644
index 0000000000..c67b9ff5d9
--- /dev/null
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgModificationsCommand.java
@@ -0,0 +1,32 @@
+package sonia.scm.repository.spi;
+
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.Repository;
+import sonia.scm.repository.spi.javahg.HgLogChangesetCommand;
+
+import java.text.MessageFormat;
+
+public class HgModificationsCommand extends AbstractCommand implements ModificationsCommand {
+
+ HgModificationsCommand(HgCommandContext context, Repository repository) {
+ super(context, repository);
+ }
+
+
+ @Override
+ public Modifications getModifications(String revision) {
+ com.aragost.javahg.Repository repository = open();
+ HgLogChangesetCommand hgLogChangesetCommand = HgLogChangesetCommand.on(repository, getContext().getConfig());
+ int hgRevision = hgLogChangesetCommand.rev(revision).singleRevision();
+ Modifications modifications = hgLogChangesetCommand.rev(MessageFormat.format("{0}:{0}", hgRevision)).extractModifications();
+ modifications.setRevision(revision);
+ return modifications;
+ }
+
+ @Override
+ public Modifications getModifications(ModificationsCommandRequest request) {
+ return getModifications(request.getRevision());
+ }
+
+
+}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java
index 4295bf45e4..7749b7e40a 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgRepositoryServiceProvider.java
@@ -42,6 +42,7 @@ import sonia.scm.repository.HgHookManager;
import sonia.scm.repository.HgRepositoryHandler;
import sonia.scm.repository.Repository;
import sonia.scm.repository.api.Command;
+import sonia.scm.repository.api.CommandNotSupportedException;
//~--- JDK imports ------------------------------------------------------------
@@ -201,6 +202,16 @@ public class HgRepositoryServiceProvider extends RepositoryServiceProvider
return new HgLogCommand(context, repository);
}
+ /**
+ * Get the corresponding {@link ModificationsCommand} implemented from the Plugins
+ *
+ * @return the corresponding {@link ModificationsCommand} implemented from the Plugins
+ * @throws CommandNotSupportedException if there is no Implementation
+ */
+ public ModificationsCommand getModificationsCommand() {
+ return new HgModificationsCommand(context,repository);
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java
index 827f86ded1..6466eb6d11 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/AbstractChangesetCommand.java
@@ -41,21 +41,18 @@ import com.aragost.javahg.internals.AbstractCommand;
import com.aragost.javahg.internals.HgInputStream;
import com.aragost.javahg.internals.RuntimeIOException;
import com.aragost.javahg.internals.Utils;
-
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
-
import sonia.scm.repository.Changeset;
import sonia.scm.repository.HgConfig;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.Person;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.IOException;
-
import java.util.List;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -251,33 +248,14 @@ public abstract class AbstractChangesetCommand extends AbstractCommand
changeset.getProperties().put(PROPERTY_CLOSE, "true");
}
- Modifications modifications = changeset.getModifications();
-
String line = in.textUpTo('\n');
-
- while (line.length() > 0)
- {
-
- if (line.startsWith("a "))
- {
- modifications.getAdded().add(line.substring(2));
- }
- else if (line.startsWith("m "))
- {
- modifications.getModified().add(line.substring(2));
- }
- else if (line.startsWith("d "))
- {
- modifications.getRemoved().add(line.substring(2));
- }
- else if (line.startsWith("t "))
+ while (line.length() > 0) {
+ if (line.startsWith("t "))
{
changeset.getTags().add(line.substring(2));
}
-
line = in.textUpTo('\n');
}
-
String message = in.textUpTo('\0');
changeset.setDescription(message);
@@ -285,6 +263,36 @@ public abstract class AbstractChangesetCommand extends AbstractCommand
return changeset;
}
+ protected Modifications readModificationsFromStream(HgInputStream in) {
+ try {
+ boolean found = in.find(CHANGESET_PATTERN);
+ if (found) {
+ while (!in.match(CHANGESET_PATTERN)) {
+ return extractModifications(in);
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeIOException(e);
+ }
+ return null;
+ }
+
+ private Modifications extractModifications(HgInputStream in) throws IOException {
+ Modifications modifications = new Modifications();
+ String line = in.textUpTo('\n');
+ while (line.length() > 0) {
+ if (line.startsWith("a ")) {
+ modifications.getAdded().add(line.substring(2));
+ } else if (line.startsWith("m ")) {
+ modifications.getModified().add(line.substring(2));
+ } else if (line.startsWith("d ")) {
+ modifications.getRemoved().add(line.substring(2));
+ }
+ line = in.textUpTo('\n');
+ }
+ return modifications;
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java
index 4c62fb4f93..f57c2a63d9 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/javahg/HgLogChangesetCommand.java
@@ -38,14 +38,14 @@ package sonia.scm.repository.spi.javahg;
import com.aragost.javahg.Repository;
import com.aragost.javahg.internals.HgInputStream;
import com.aragost.javahg.internals.Utils;
-
import sonia.scm.repository.Changeset;
import sonia.scm.repository.HgConfig;
-
-//~--- JDK imports ------------------------------------------------------------
+import sonia.scm.repository.Modifications;
import java.util.List;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -106,11 +106,22 @@ public class HgLogChangesetCommand extends AbstractChangesetCommand
*/
public List execute(String... files)
{
- cmdAppend("--style", CHANGESET_EAGER_STYLE_PATH);
+ return readListFromStream(getHgInputStream(files, CHANGESET_EAGER_STYLE_PATH));
+ }
- HgInputStream stream = launchStream(files);
+ /**
+ * Extract Modifications from the Repository files
+ *
+ * @param files repo files
+ * @return modifications
+ */
+ public Modifications extractModifications(String... files) {
+ return readModificationsFromStream(getHgInputStream(files, CHANGESET_EAGER_STYLE_PATH));
+ }
- return readListFromStream(stream);
+ HgInputStream getHgInputStream(String[] files, String changesetStylePath) {
+ cmdAppend("--style", changesetStylePath);
+ return launchStream(files);
}
/**
@@ -138,11 +149,7 @@ public class HgLogChangesetCommand extends AbstractChangesetCommand
*/
public List loadRevisions(String... files)
{
- cmdAppend("--style", CHANGESET_LAZY_STYLE_PATH);
-
- HgInputStream stream = launchStream(files);
-
- return loadRevisionsFromStream(stream);
+ return loadRevisionsFromStream(getHgInputStream(files, CHANGESET_LAZY_STYLE_PATH));
}
/**
diff --git a/scm-plugins/scm-hg-plugin/src/main/js/HgAvatar.js b/scm-plugins/scm-hg-plugin/src/main/js/HgAvatar.js
index b2348b54cc..ce10ec293c 100644
--- a/scm-plugins/scm-hg-plugin/src/main/js/HgAvatar.js
+++ b/scm-plugins/scm-hg-plugin/src/main/js/HgAvatar.js
@@ -1,6 +1,6 @@
//@flow
import React from "react";
-import { Image } from "@scm-manager/ui-components";
+import {Image} from "@scm-manager/ui-components";
type Props = {
};
diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java
index aa611a8ba4..b8967ed15b 100644
--- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java
+++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/client/spi/HgCommitCommand.java
@@ -32,11 +32,11 @@ package sonia.scm.repository.client.spi;
import com.aragost.javahg.Repository;
import com.google.common.collect.Lists;
-import java.io.IOException;
import sonia.scm.repository.Changeset;
-import sonia.scm.repository.Modifications;
import sonia.scm.repository.Person;
+import java.io.IOException;
+
/**
* Mercurial implementation of the {@link CommitCommand}.
*
@@ -70,9 +70,6 @@ public class HgCommitCommand implements CommitCommand
changeset.setBranches(Lists.newArrayList(c.getBranch()));
changeset.setTags(c.tags());
- changeset.setModifications(
- new Modifications(c.getAddedFiles(), c.getModifiedFiles(), c.getDeletedFiles())
- );
return changeset;
}
diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java
index c4d49ba8b5..99e9fc191a 100644
--- a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java
+++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgLogCommandTest.java
@@ -39,6 +39,9 @@ import org.junit.Test;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.Modifications;
+import sonia.scm.repository.RevisionNotFoundException;
+
+import java.io.IOException;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertEquals;
@@ -133,27 +136,28 @@ public class HgLogCommandTest extends AbstractHgCommandTestBase
}
@Test
- public void testGetCommit() {
+ public void testGetCommit() throws IOException, RevisionNotFoundException {
HgLogCommand command = createComamnd();
+ String revision = "a9bacaf1b7fa0cebfca71fed4e59ed69a6319427";
Changeset c =
- command.getChangeset("a9bacaf1b7fa0cebfca71fed4e59ed69a6319427");
+ command.getChangeset(revision);
assertNotNull(c);
- assertEquals("a9bacaf1b7fa0cebfca71fed4e59ed69a6319427", c.getId());
+ assertEquals(revision, c.getId());
assertEquals("added a and b files", c.getDescription());
checkDate(c.getDate());
assertEquals("Douglas Adams", c.getAuthor().getName());
assertEquals("douglas.adams@hitchhiker.com", c.getAuthor().getMail());
assertEquals("added a and b files", c.getDescription());
+ ModificationsCommand modificationsCommand = new HgModificationsCommand(cmdContext, repository);
+ Modifications modifications = modificationsCommand.getModifications(revision);
- Modifications mods = c.getModifications();
-
- assertNotNull(mods);
- assertTrue("modified list should be empty", mods.getModified().isEmpty());
- assertTrue("removed list should be empty", mods.getRemoved().isEmpty());
- assertFalse("added list should not be empty", mods.getAdded().isEmpty());
- assertEquals(2, mods.getAdded().size());
- assertThat(mods.getAdded(), contains("a.txt", "b.txt"));
+ assertNotNull(modifications);
+ assertTrue("modified list should be empty", modifications.getModified().isEmpty());
+ assertTrue("removed list should be empty", modifications.getRemoved().isEmpty());
+ assertFalse("added list should not be empty", modifications.getAdded().isEmpty());
+ assertEquals(2, modifications.getAdded().size());
+ assertThat(modifications.getAdded(), contains("a.txt", "b.txt"));
}
@Test
diff --git a/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java
new file mode 100644
index 0000000000..eae8319b89
--- /dev/null
+++ b/scm-plugins/scm-hg-plugin/src/test/java/sonia/scm/repository/spi/HgModificationsCommandTest.java
@@ -0,0 +1,111 @@
+package sonia.scm.repository.spi;
+
+import com.aragost.javahg.Changeset;
+import com.aragost.javahg.commands.RemoveCommand;
+import org.junit.Before;
+import org.junit.Test;
+import sonia.scm.repository.HgTestUtil;
+import sonia.scm.repository.Modifications;
+
+import java.io.File;
+import java.util.function.Consumer;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+
+public class HgModificationsCommandTest extends IncomingOutgoingTestBase {
+
+
+ private HgModificationsCommand outgoingModificationsCommand;
+
+ @Before
+ public void init() {
+ HgCommandContext outgoingContext = new HgCommandContext(HgTestUtil.createHookManager(), handler, outgoingRepository, outgoingDirectory);
+ outgoingModificationsCommand = new HgModificationsCommand(outgoingContext, outgoingRepository);
+ }
+
+ @Test
+ public void shouldReadAddedFiles() throws Exception {
+ String fileName = "a.txt";
+ writeNewFile(outgoing, outgoingDirectory, fileName, "bal bla");
+ Changeset changeset = commit(outgoing, "added a.txt");
+ String revision = String.valueOf(changeset.getRevision());
+ Consumer assertModifications = assertAddedFile(fileName);
+ assertModifications.accept(outgoingModificationsCommand.getModifications(revision));
+ }
+
+ @Test
+ public void shouldReadModifiedFiles() throws Exception {
+ String fileName = "a.txt";
+ writeNewFile(outgoing, outgoingDirectory, fileName, "bal bla");
+ commit(outgoing, "added a.txt");
+ writeNewFile(outgoing, outgoingDirectory, fileName, "new content");
+ Changeset changeset = commit(outgoing, "modified a.txt");
+ String revision = String.valueOf(changeset.getRevision());
+ Consumer assertModifications = assertModifiedFiles(fileName);
+ assertModifications.accept(outgoingModificationsCommand.getModifications(revision));
+ }
+
+ @Test
+ public void shouldReadRemovedFiles() throws Exception {
+ String fileName = "a.txt";
+ writeNewFile(outgoing, outgoingDirectory, fileName, "bal bla");
+ commit(outgoing, "added a.txt");
+ File file = new File(outgoingDirectory, fileName);
+ file.delete();
+ RemoveCommand.on(outgoing).execute(file);
+ Changeset changeset = commit(outgoing, "removed a.txt");
+ String revision = String.valueOf(changeset.getRevision());
+ Consumer assertModifications = assertRemovedFiles(fileName);
+ assertModifications.accept(outgoingModificationsCommand.getModifications(revision));
+ }
+
+
+ Consumer assertRemovedFiles(String fileName) {
+ return (modifications) -> {
+ assertThat(modifications).isNotNull();
+ assertThat(modifications.getAdded())
+ .as("added files modifications")
+ .hasSize(0);
+ assertThat(modifications.getModified())
+ .as("modified files modifications")
+ .hasSize(0);
+ assertThat(modifications.getRemoved())
+ .as("removed files modifications")
+ .hasSize(1)
+ .containsOnly(fileName);
+ };
+ }
+
+
+ Consumer assertModifiedFiles(String file) {
+ return (modifications) -> {
+ assertThat(modifications).isNotNull();
+ assertThat(modifications.getAdded())
+ .as("added files modifications")
+ .hasSize(0);
+ assertThat(modifications.getModified())
+ .as("modified files modifications")
+ .hasSize(1)
+ .containsOnly(file);
+ assertThat(modifications.getRemoved())
+ .as("removed files modifications")
+ .hasSize(0);
+ };
+ }
+
+ Consumer assertAddedFile(String addedFile) {
+ return (modifications) -> {
+ assertThat(modifications).isNotNull();
+ assertThat(modifications.getAdded())
+ .as("added files modifications")
+ .hasSize(1)
+ .containsOnly(addedFile);
+ assertThat(modifications.getModified())
+ .as("modified files modifications")
+ .hasSize(0);
+ assertThat(modifications.getRemoved())
+ .as("removed files modifications")
+ .hasSize(0);
+ };
+ }
+}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java
index eb613e6144..480026c27a 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/SvnUtil.java
@@ -49,7 +49,6 @@ import org.tmatesoft.svn.core.internal.util.SVNEncodingUtil;
import org.tmatesoft.svn.core.internal.util.SVNXMLUtil;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNClientManager;
-import org.tmatesoft.svn.core.wc.admin.SVNChangeEntry;
import sonia.scm.util.HttpUtil;
import sonia.scm.util.Util;
@@ -103,30 +102,37 @@ public final class SvnUtil
//~--- methods --------------------------------------------------------------
- /**
- * TODO: type replaced
- *
- *
- * @param modifications
- * @param entry
- */
- public static void appendModification(Modifications modifications,
- SVNLogEntryPath entry)
- {
- appendModification(modifications, entry.getType(), entry.getPath());
+ public static long parseRevision(String v) throws RevisionNotFoundException {
+ long result = -1l;
+
+ if (!Strings.isNullOrEmpty(v))
+ {
+ try
+ {
+ result = Long.parseLong(v);
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new RevisionNotFoundException(v);
+ }
+ }
+
+ return result;
}
- /**
- * Method description
- *
- *
- * @param modifications
- * @param entry
- */
- public static void appendModification(Modifications modifications,
- SVNChangeEntry entry)
- {
- appendModification(modifications, entry.getType(), entry.getPath());
+
+ public static Modifications createModifications(SVNLogEntry entry, String revision) {
+ Modifications modifications = new Modifications();
+ modifications.setRevision(revision);
+ Map changeMap = entry.getChangedPaths();
+
+ if (Util.isNotEmpty(changeMap)) {
+
+ for (SVNLogEntryPath e : changeMap.values()) {
+ appendModification(modifications, e.getType(), e.getPath());
+ }
+ }
+ return modifications;
}
/**
@@ -210,19 +216,6 @@ public final class SvnUtil
{
changeset.getParents().add(String.valueOf(revision - 1));
}
-
- Map changeMap = entry.getChangedPaths();
-
- if (Util.isNotEmpty(changeMap))
- {
- Modifications modifications = changeset.getModifications();
-
- for (SVNLogEntryPath e : changeMap.values())
- {
- appendModification(modifications, e);
- }
- }
-
return changeset;
}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java
index ededb4e1f0..332dcb55a6 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnLogCommand.java
@@ -54,6 +54,8 @@ import sonia.scm.util.Util;
import java.util.Collection;
import java.util.List;
+import static sonia.scm.repository.SvnUtil.parseRevision;
+
//~--- JDK imports ------------------------------------------------------------
public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
@@ -144,25 +146,6 @@ public class SvnLogCommand extends AbstractSvnCommand implements LogCommand
return changesets;
}
- //~--- methods --------------------------------------------------------------
-
- private long parseRevision(String v) throws RevisionNotFoundException {
- long result = -1l;
-
- if (!Strings.isNullOrEmpty(v))
- {
- try
- {
- result = Long.parseLong(v);
- }
- catch (NumberFormatException ex)
- {
- throw new RevisionNotFoundException(v);
- }
- }
-
- return result;
- }
//~--- get methods ----------------------------------------------------------
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java
new file mode 100644
index 0000000000..e6cedc8ebf
--- /dev/null
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnModificationsCommand.java
@@ -0,0 +1,50 @@
+package sonia.scm.repository.spi;
+
+import lombok.extern.slf4j.Slf4j;
+import org.tmatesoft.svn.core.SVNException;
+import org.tmatesoft.svn.core.SVNLogEntry;
+import org.tmatesoft.svn.core.io.SVNRepository;
+import sonia.scm.repository.InternalRepositoryException;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.Repository;
+import sonia.scm.repository.RevisionNotFoundException;
+import sonia.scm.repository.SvnUtil;
+import sonia.scm.util.Util;
+
+import java.io.IOException;
+import java.util.Collection;
+
+@Slf4j
+public class SvnModificationsCommand extends AbstractSvnCommand implements ModificationsCommand {
+
+ SvnModificationsCommand(SvnContext context, Repository repository) {
+ super(context, repository);
+ }
+
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Modifications getModifications(String revision) throws IOException, RevisionNotFoundException {
+ Modifications modifications = null;
+ log.debug("get modifications {}", revision);
+ try {
+ long revisionNumber = SvnUtil.parseRevision(revision);
+ SVNRepository repo = open();
+ Collection entries = repo.log(null, null, revisionNumber,
+ revisionNumber, true, true);
+ if (Util.isNotEmpty(entries)) {
+ modifications = SvnUtil.createModifications(entries.iterator().next(), revision);
+ }
+ } catch (SVNException ex) {
+ throw new InternalRepositoryException("could not open repository", ex);
+ }
+ return modifications;
+ }
+
+ @Override
+ public Modifications getModifications(ModificationsCommandRequest request) throws IOException, RevisionNotFoundException {
+ return getModifications(request.getRevision());
+ }
+
+
+}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java
index 93fb88f841..e4efdb71ab 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnPreReceiveHookChangesetProvier.java
@@ -37,22 +37,19 @@ package sonia.scm.repository.spi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.wc.ISVNOptions;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNWCUtil;
import org.tmatesoft.svn.core.wc.admin.SVNLookClient;
-
import sonia.scm.repository.Changeset;
import sonia.scm.repository.RepositoryHookType;
-import sonia.scm.repository.SvnModificationHandler;
import sonia.scm.repository.SvnUtil;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.File;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -123,10 +120,6 @@ public class SvnPreReceiveHookChangesetProvier
{
changeset = SvnUtil.createChangeset(entry);
changeset.setId(SvnUtil.createTransactionEntryId(transaction));
-
- clientManager.doGetChanged(repositoryDirectory, transaction,
- new SvnModificationHandler(changeset), true);
-
}
else if (logger.isWarnEnabled())
{
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java
index 24180bfe9e..1fda21f0d8 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnRepositoryServiceProvider.java
@@ -167,6 +167,10 @@ public class SvnRepositoryServiceProvider extends RepositoryServiceProvider
return new SvnLogCommand(context, repository);
}
+ public ModificationsCommand getModificationsCommand() {
+ return new SvnModificationsCommand(context, repository);
+ }
+
/**
* Method description
*
diff --git a/scm-plugins/scm-svn-plugin/src/main/js/SvnAvatar.js b/scm-plugins/scm-svn-plugin/src/main/js/SvnAvatar.js
index 9996cbbfe0..731c9ddf33 100644
--- a/scm-plugins/scm-svn-plugin/src/main/js/SvnAvatar.js
+++ b/scm-plugins/scm-svn-plugin/src/main/js/SvnAvatar.js
@@ -1,6 +1,6 @@
//@flow
import React from "react";
-import { Image } from "@scm-manager/ui-components";
+import {Image} from "@scm-manager/ui-components";
type Props = {
};
diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java
index b54e51c4d6..302ef3e8aa 100644
--- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java
+++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/client/spi/SvnChangeWorker.java
@@ -70,13 +70,15 @@ class SvnChangeWorker {
SVNWCClient wClient = client.getWCClient();
// add files
- try {
- wClient.doAdd(addedFiles.toArray(new File[0]), true, false, false,
- SVNDepth.INFINITY, false, false, false);
- addedFiles.clear();
+ if (!addedFiles.isEmpty()){
+ try {
+ wClient.doAdd(addedFiles.toArray(new File[0]), true, false, false,
+ SVNDepth.INFINITY, false, false, false);
+ addedFiles.clear();
- } catch (SVNException ex) {
- throw new RepositoryClientException("failed to add files", ex);
+ } catch (SVNException ex) {
+ throw new RepositoryClientException("failed to add files", ex);
+ }
}
// remove files
diff --git a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java
index 941687190c..a55138f151 100644
--- a/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java
+++ b/scm-plugins/scm-svn-plugin/src/test/java/sonia/scm/repository/spi/SvnLogCommandTest.java
@@ -40,6 +40,8 @@ import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.Modifications;
import sonia.scm.repository.RevisionNotFoundException;
+import java.io.IOException;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -128,7 +130,7 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
}
@Test
- public void testGetCommit() throws RevisionNotFoundException {
+ public void testGetCommit() throws RevisionNotFoundException, IOException {
Changeset c = createCommand().getChangeset("3");
assertNotNull(c);
@@ -137,15 +139,15 @@ public class SvnLogCommandTest extends AbstractSvnCommandTestBase
checkDate(c.getDate());
assertEquals("perfect", c.getAuthor().getName());
assertNull("douglas.adams@hitchhiker.com", c.getAuthor().getMail());
+ SvnModificationsCommand modificationsCommand = new SvnModificationsCommand(createContext(), repository);
+ Modifications modifications = modificationsCommand.getModifications("3");
- Modifications mods = c.getModifications();
-
- assertNotNull(mods);
- assertEquals(1, mods.getModified().size());
- assertEquals(1, mods.getRemoved().size());
- assertTrue("added list should be empty", mods.getAdded().isEmpty());
- assertEquals("a.txt", mods.getModified().get(0));
- assertEquals("b.txt", mods.getRemoved().get(0));
+ assertNotNull(modifications);
+ assertEquals(1, modifications.getModified().size());
+ assertEquals(1, modifications.getRemoved().size());
+ assertTrue("added list should be empty", modifications.getAdded().isEmpty());
+ assertEquals("a.txt", modifications.getModified().get(0));
+ assertEquals("b.txt", modifications.getRemoved().get(0));
}
@Test
diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index 761a28730c..da01814152 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -254,7 +254,6 @@
tika-core
1.18
-
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java
index a8dc3f3968..a189dcec97 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ChangesetToChangesetDtoMapper.java
@@ -65,7 +65,8 @@ public abstract class ChangesetToChangesetDtoMapper implements InstantAttributeM
Links.Builder linksBuilder = linkingTo()
.self(resourceLinks.changeset().self(repository.getNamespace(), repository.getName(), target.getId()))
- .single(link("diff", resourceLinks.diff().self(namespace, name, target.getId())));
+ .single(link("diff", resourceLinks.diff().self(namespace, name, target.getId())))
+ .single(link("modifications", resourceLinks.modifications().self(namespace, name, target.getId())));
target.add(linksBuilder.build());
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java
index 9cadbfb6ff..bebd7def23 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java
@@ -34,6 +34,7 @@ public class MapperModule extends AbstractModule {
bind(TagToTagDtoMapper.class).to(Mappers.getMapper(TagToTagDtoMapper.class).getClass());
bind(FileObjectToFileObjectDtoMapper.class).to(Mappers.getMapper(FileObjectToFileObjectDtoMapper.class).getClass());
+ bind(ModificationsToDtoMapper.class).to(Mappers.getMapper(ModificationsToDtoMapper.class).getClass());
// no mapstruct required
bind(UIPluginDtoMapper.class);
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java
new file mode 100644
index 0000000000..9ea0359157
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsDto.java
@@ -0,0 +1,39 @@
+package sonia.scm.api.v2.resources;
+
+import de.otto.edison.hal.HalRepresentation;
+import de.otto.edison.hal.Links;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+public class ModificationsDto extends HalRepresentation {
+
+
+ private String revision;
+ /**
+ * list of added files
+ */
+ private List added;
+
+ /**
+ * list of modified files
+ */
+ private List modified;
+
+ /**
+ * list of removed files
+ */
+ private List removed;
+
+ @Override
+ @SuppressWarnings("squid:S1185") // We want to have this method available in this package
+ protected HalRepresentation add(Links links) {
+ return super.add(links);
+ }
+
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java
new file mode 100644
index 0000000000..28f855f40c
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsRootResource.java
@@ -0,0 +1,62 @@
+package sonia.scm.api.v2.resources;
+
+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.InternalRepositoryException;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.NamespaceAndName;
+import sonia.scm.repository.RepositoryNotFoundException;
+import sonia.scm.repository.RevisionNotFoundException;
+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.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+public class ModificationsRootResource {
+
+ private final RepositoryServiceFactory serviceFactory;
+ private final ModificationsToDtoMapper modificationsToDtoMapper;
+
+ @Inject
+ public ModificationsRootResource(RepositoryServiceFactory serviceFactory, ModificationsToDtoMapper modificationsToDtoMapper) {
+ this.serviceFactory = serviceFactory;
+ this.modificationsToDtoMapper = modificationsToDtoMapper;
+ }
+
+ /**
+ * Get the file modifications related to a revision.
+ * file modifications are for example: Modified, Added or Removed.
+ */
+ @GET
+ @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 modifications"),
+ @ResponseCode(code = 404, condition = "not found, no changeset with the specified id is available in the repository"),
+ @ResponseCode(code = 500, condition = "internal server error")
+ })
+ @Produces(VndMediaType.MODIFICATIONS)
+ @TypeHint(ModificationsDto.class)
+ @Path("{revision}")
+ public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) throws IOException, RevisionNotFoundException, RepositoryNotFoundException , InternalRepositoryException {
+ try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
+ Modifications modifications = repositoryService.getModificationsCommand()
+ .revision(revision)
+ .getModifications();
+ ModificationsDto output = modificationsToDtoMapper.map(modifications, repositoryService.getRepository());
+ if (modifications != null ) {
+ return Response.ok(output).build();
+ } else {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+ }
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java
new file mode 100644
index 0000000000..422d8fc4d9
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/ModificationsToDtoMapper.java
@@ -0,0 +1,31 @@
+package sonia.scm.api.v2.resources;
+
+import de.otto.edison.hal.Links;
+import org.mapstruct.AfterMapping;
+import org.mapstruct.Context;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingTarget;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.Repository;
+
+import javax.inject.Inject;
+
+import static de.otto.edison.hal.Links.linkingTo;
+
+@Mapper
+public abstract class ModificationsToDtoMapper {
+
+ @Inject
+ private ResourceLinks resourceLinks;
+
+ @Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
+ public abstract ModificationsDto map(Modifications modifications, @Context Repository repository);
+
+ @AfterMapping
+ void appendLinks(@MappingTarget ModificationsDto target, @Context Repository repository) {
+ Links.Builder linksBuilder = linkingTo()
+ .self(resourceLinks.modifications().self(repository.getNamespace(), repository.getName(), target.getRevision()));
+ target.add(linksBuilder.build());
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java
index 1585065b91..f9328525a9 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java
@@ -40,6 +40,7 @@ public class RepositoryResource {
private final Provider contentResource;
private final Provider permissionRootResource;
private final Provider diffRootResource;
+ private final Provider modificationsRootResource;
private final Provider fileHistoryRootResource;
@Inject
@@ -52,7 +53,9 @@ public class RepositoryResource {
Provider sourceRootResource, Provider contentResource,
Provider permissionRootResource,
Provider diffRootResource,
- Provider fileHistoryRootResource) {
+ Provider modificationsRootResource,
+ Provider fileHistoryRootResource
+ ) {
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
this.manager = manager;
this.repositoryToDtoMapper = repositoryToDtoMapper;
@@ -64,6 +67,7 @@ public class RepositoryResource {
this.contentResource = contentResource;
this.permissionRootResource = permissionRootResource;
this.diffRootResource = diffRootResource;
+ this.modificationsRootResource = modificationsRootResource;
this.fileHistoryRootResource = fileHistoryRootResource;
}
@@ -188,6 +192,9 @@ public class RepositoryResource {
return permissionRootResource.get();
}
+ @Path("modifications/")
+ public ModificationsRootResource modifications() {return modificationsRootResource.get(); }
+
private Optional handleNotArchived(Throwable throwable) {
if (throwable instanceof RepositoryIsNotArchivedException) {
return Optional.of(Response.status(Response.Status.PRECONDITION_FAILED).build());
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 3d61083033..2e7202e981 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
@@ -311,6 +311,21 @@ class ResourceLinks {
}
}
+ public ModificationsLinks modifications() {
+ return new ModificationsLinks(uriInfoStore.get());
+ }
+
+ static class ModificationsLinks {
+ private final LinkBuilder modificationsLinkBuilder;
+
+ ModificationsLinks(UriInfo uriInfo) {
+ modificationsLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ModificationsRootResource.class);
+ }
+ String self(String namespace, String name, String revision) {
+ return modificationsLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("modifications").parameters().method("get").parameters(revision).href();
+ }
+ }
+
public FileHistoryLinks fileHistory() {
return new FileHistoryLinks(uriInfoStore.get());
}
diff --git a/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java b/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java
index b3864d894f..7da9c7b263 100644
--- a/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/WebResourceServletTest.java
@@ -19,8 +19,15 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
-import static org.junit.Assert.*;
-import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
public class WebResourceServletTest {
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java
index 0a209e905f..c8d25ae82d 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/BranchRootResourceTest.java
@@ -44,7 +44,7 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
@Slf4j
-public class BranchRootResourceTest {
+public class BranchRootResourceTest extends RepositoryTestBase {
public static final String BRANCH_PATH = "space/repo/branches/master";
public static final String BRANCH_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + BRANCH_PATH;
@@ -92,9 +92,8 @@ public class BranchRootResourceTest {
changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks);
branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper, changesetCollectionToDtoMapper);
- RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, null, null, null, MockProvider.of(branchRootResource), null, null, null, null, null, null)), null);
- dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
-
+ super.branchRootResource = MockProvider.of(branchRootResource);
+ dispatcher.getRegistry().addSingletonResource(getRepositoryRootResource());
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"));
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 a7bad96534..e4e991a7d4 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
@@ -44,7 +44,7 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
@Slf4j
-public class ChangesetRootResourceTest {
+public class ChangesetRootResourceTest extends RepositoryTestBase {
public static final String CHANGESET_PATH = "space/repo/changesets/";
@@ -79,10 +79,8 @@ public class ChangesetRootResourceTest {
public void prepareEnvironment() throws Exception {
changesetCollectionToDtoMapper = new ChangesetCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
changesetRootResource = new ChangesetRootResource(serviceFactory, changesetCollectionToDtoMapper, changesetToChangesetDtoMapper);
- RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
- .of(new RepositoryResource(null, null, null, null, null,
- MockProvider.of(changesetRootResource), null, null, null, null, null)), null);
- dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
+ super.changesetRootResource = MockProvider.of(changesetRootResource);
+ dispatcher.getRegistry().addSingletonResource(getRepositoryRootResource());
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"));
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java
index 2613292e0b..f6a8fa4e09 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DiffResourceTest.java
@@ -37,7 +37,7 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
@Slf4j
-public class DiffResourceTest {
+public class DiffResourceTest extends RepositoryTestBase {
public static final String DIFF_PATH = "space/repo/diff/";
@@ -63,10 +63,8 @@ public class DiffResourceTest {
@Before
public void prepareEnvironment() throws Exception {
diffRootResource = new DiffRootResource(serviceFactory);
- RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
- .of(new RepositoryResource(null, null, null, null, null,
- null, null, null, null, MockProvider.of(diffRootResource),null)), null);
- dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
+ super.diffRootResource = MockProvider.of(diffRootResource);
+ dispatcher.getRegistry().addSingletonResource(getRepositoryRootResource());
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"));
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java
index 4d4ed435df..3505d00dc6 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/DispatcherMock.java
@@ -14,6 +14,7 @@ public class DispatcherMock {
dispatcher.getProviderFactory().registerProvider(AlreadyExistsExceptionMapper.class);
dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class);
dispatcher.getProviderFactory().registerProvider(ConcurrentModificationExceptionMapper.class);
+ dispatcher.getProviderFactory().registerProvider(InternalRepositoryExceptionMapper.class);
return dispatcher;
}
}
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java
index f89a92f124..778682f62d 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/FileHistoryResourceTest.java
@@ -47,7 +47,7 @@ import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
@Slf4j
-public class FileHistoryResourceTest {
+public class FileHistoryResourceTest extends RepositoryTestBase {
public static final String FILE_HISTORY_PATH = "space/repo/history/";
public static final String FILE_HISTORY_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + FILE_HISTORY_PATH;
@@ -81,10 +81,8 @@ public class FileHistoryResourceTest {
public void prepareEnvironment() throws Exception {
fileHistoryCollectionToDtoMapper = new FileHistoryCollectionToDtoMapper(changesetToChangesetDtoMapper, resourceLinks);
fileHistoryRootResource = new FileHistoryRootResource(serviceFactory, fileHistoryCollectionToDtoMapper);
- RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
- .of(new RepositoryResource(null, null, null, null, null,
- null, null, null, null, null, MockProvider.of(fileHistoryRootResource))), null);
- dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
+ super.fileHistoryRootResource = MockProvider.of(fileHistoryRootResource);
+ dispatcher.getRegistry().addSingletonResource(getRepositoryRootResource());
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"));
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java
new file mode 100644
index 0000000000..f8b555f180
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ModificationsResourceTest.java
@@ -0,0 +1,149 @@
+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.InternalRepositoryException;
+import sonia.scm.repository.Modifications;
+import sonia.scm.repository.NamespaceAndName;
+import sonia.scm.repository.Repository;
+import sonia.scm.repository.api.ModificationsCommandBuilder;
+import sonia.scm.repository.api.RepositoryService;
+import sonia.scm.repository.api.RepositoryServiceFactory;
+import sonia.scm.web.VndMediaType;
+
+import java.net.URI;
+import java.text.MessageFormat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@Slf4j
+@RunWith(MockitoJUnitRunner.Silent.class)
+public class ModificationsResourceTest extends RepositoryTestBase {
+
+
+ public static final String MODIFICATIONS_PATH = "space/repo/modifications/";
+ public static final String MODIFICATIONS_URL = "/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + MODIFICATIONS_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 ModificationsCommandBuilder modificationsCommandBuilder;
+
+ @InjectMocks
+ private ModificationsToDtoMapperImpl modificationsToDtoMapper;
+
+ private ModificationsRootResource modificationsRootResource;
+
+
+ private final Subject subject = mock(Subject.class);
+ private final ThreadState subjectThreadState = new SubjectThreadState(subject);
+
+
+ @Before
+ public void prepareEnvironment() throws Exception {
+ modificationsRootResource = new ModificationsRootResource(serviceFactory, modificationsToDtoMapper);
+ super.modificationsRootResource = MockProvider.of(modificationsRootResource);
+ dispatcher.getRegistry().addSingletonResource(getRepositoryRootResource());
+ 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);
+ dispatcher.getProviderFactory().registerProvider(InternalRepositoryExceptionMapper.class);
+ when(repositoryService.getModificationsCommand()).thenReturn(modificationsCommandBuilder);
+ subjectThreadState.bind();
+ ThreadContext.bind(subject);
+ when(subject.isPermitted(any(String.class))).thenReturn(true);
+ }
+
+ @After
+ public void cleanupContext() {
+ ThreadContext.unbindSubject();
+ }
+
+ @Test
+ public void shouldGet404OnMissingModifications() throws Exception {
+ when(modificationsCommandBuilder.revision(any())).thenReturn(modificationsCommandBuilder);
+ when(modificationsCommandBuilder.getModifications()).thenReturn(null);
+
+ MockHttpRequest request = MockHttpRequest
+ .get(MODIFICATIONS_URL + "not_existing_revision")
+ .accept(VndMediaType.MODIFICATIONS);
+ MockHttpResponse response = new MockHttpResponse();
+ dispatcher.invoke(request, response);
+ assertEquals(404, response.getStatus());
+ }
+
+ @Test
+ public void shouldGet500OnModificationsCommandError() throws Exception {
+ when(modificationsCommandBuilder.revision(any())).thenReturn(modificationsCommandBuilder);
+ when(modificationsCommandBuilder.getModifications()).thenThrow(InternalRepositoryException.class);
+
+ MockHttpRequest request = MockHttpRequest
+ .get(MODIFICATIONS_URL + "revision")
+ .accept(VndMediaType.MODIFICATIONS);
+ MockHttpResponse response = new MockHttpResponse();
+ dispatcher.invoke(request, response);
+ assertEquals(500, response.getStatus());
+ }
+
+
+ @Test
+ public void shouldGetModifications() throws Exception {
+ Modifications modifications = new Modifications();
+ String revision = "revision";
+ String addedFile_1 = "a.txt";
+ String addedFile_2 = "b.txt";
+ String modifiedFile_1 = "d.txt";
+ String modifiedFile_2 = "c.txt";
+ String removedFile_1 = "e.txt";
+ String removedFile_2 = "f.txt";
+ modifications.setRevision(revision);
+ modifications.setAdded(Lists.newArrayList(addedFile_1, addedFile_2));
+ modifications.setModified(Lists.newArrayList(modifiedFile_1, modifiedFile_2));
+ modifications.setRemoved(Lists.newArrayList(removedFile_1, removedFile_2));
+ when(modificationsCommandBuilder.getModifications()).thenReturn(modifications);
+ when(modificationsCommandBuilder.revision(eq(revision))).thenReturn(modificationsCommandBuilder);
+
+ MockHttpRequest request = MockHttpRequest
+ .get(MODIFICATIONS_URL + revision)
+ .accept(VndMediaType.MODIFICATIONS);
+ MockHttpResponse response = new MockHttpResponse();
+ dispatcher.invoke(request, response);
+ assertEquals(200, response.getStatus());
+ log.info("the content: ", response.getContentAsString());
+ assertTrue(response.getContentAsString().contains(String.format("\"revision\":\"%s\"", revision)));
+ assertTrue(response.getContentAsString().contains(MessageFormat.format("\"added\":[\"{0}\",\"{1}\"]", addedFile_1, addedFile_2)));
+ assertTrue(response.getContentAsString().contains(MessageFormat.format("\"modified\":[\"{0}\",\"{1}\"]", modifiedFile_1, modifiedFile_2)));
+ assertTrue(response.getContentAsString().contains(MessageFormat.format("\"removed\":[\"{0}\",\"{1}\"]", removedFile_1, removedFile_2)));
+ }
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java
index 3f2ea9b317..ac5ad07cf8 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/PermissionRootResourceTest.java
@@ -64,7 +64,7 @@ import static sonia.scm.api.v2.resources.PermissionDto.GROUP_PREFIX;
password = "secret",
configuration = "classpath:sonia/scm/repository/shiro.ini"
)
-public class PermissionRootResourceTest {
+public class PermissionRootResourceTest extends RepositoryTestBase {
private static final String REPOSITORY_NAMESPACE = "repo_namespace";
private static final String REPOSITORY_NAME = "repo";
private static final String PERMISSION_WRITE = "repository:permissionWrite:" + REPOSITORY_NAME;
@@ -137,9 +137,8 @@ public class PermissionRootResourceTest {
initMocks(this);
permissionCollectionToDtoMapper = new PermissionCollectionToDtoMapper(permissionToPermissionDtoMapper, resourceLinks);
permissionRootResource = new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, permissionCollectionToDtoMapper, resourceLinks, repositoryManager);
- RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
- .of(new RepositoryResource(null, null, null, null, null, null, null, null, MockProvider.of(permissionRootResource), null, null)), null);
- dispatcher = createDispatcher(repositoryRootResource);
+ super.permissionRootResource = MockProvider.of(permissionRootResource);
+ dispatcher = createDispatcher(getRepositoryRootResource());
subjectThreadState.bind();
ThreadContext.bind(subject);
}
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java
index 48ca62089f..7c6deedf65 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java
@@ -55,7 +55,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
password = "secret",
configuration = "classpath:sonia/scm/repository/shiro.ini"
)
-public class RepositoryRootResourceTest {
+public class RepositoryRootResourceTest extends RepositoryTestBase {
private Dispatcher dispatcher;
@@ -79,11 +79,12 @@ public class RepositoryRootResourceTest {
@Before
public void prepareEnvironment() {
initMocks(this);
- RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null, null, null, null);
+ super.repositoryToDtoMapper = repositoryToDtoMapper;
+ super.dtoToRepositoryMapper = dtoToRepositoryMapper;
+ super.manager = repositoryManager;
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
- RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks);
- RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource));
- dispatcher = createDispatcher(repositoryRootResource);
+ super.repositoryCollectionResource = MockProvider.of(new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks));
+ dispatcher = createDispatcher(getRepositoryRootResource());
}
@Test
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java
new file mode 100644
index 0000000000..c3cc56958a
--- /dev/null
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java
@@ -0,0 +1,42 @@
+package sonia.scm.api.v2.resources;
+
+import sonia.scm.repository.RepositoryManager;
+
+import javax.inject.Provider;
+
+public abstract class RepositoryTestBase {
+
+
+ protected RepositoryToRepositoryDtoMapper repositoryToDtoMapper;
+ protected RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
+ protected RepositoryManager manager;
+ protected Provider tagRootResource;
+ protected Provider branchRootResource;
+ protected Provider changesetRootResource;
+ protected Provider sourceRootResource;
+ protected Provider contentResource;
+ protected Provider permissionRootResource;
+ protected Provider diffRootResource;
+ protected Provider modificationsRootResource;
+ protected Provider fileHistoryRootResource;
+ protected Provider repositoryCollectionResource;
+
+
+ RepositoryRootResource getRepositoryRootResource() {
+ return new RepositoryRootResource(MockProvider.of(new RepositoryResource(
+ repositoryToDtoMapper,
+ dtoToRepositoryMapper,
+ manager,
+ tagRootResource,
+ branchRootResource,
+ changesetRootResource,
+ sourceRootResource,
+ contentResource,
+ permissionRootResource,
+ diffRootResource,
+ modificationsRootResource,
+ fileHistoryRootResource)), repositoryCollectionResource);
+ }
+
+
+}
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java
index 018797a7a3..1d0fac68e3 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/ResourceLinksMock.java
@@ -28,6 +28,7 @@ public class ResourceLinksMock {
when(resourceLinks.config()).thenReturn(new ResourceLinks.ConfigLinks(uriInfo));
when(resourceLinks.branch()).thenReturn(new ResourceLinks.BranchLinks(uriInfo));
when(resourceLinks.diff()).thenReturn(new ResourceLinks.DiffLinks(uriInfo));
+ when(resourceLinks.modifications()).thenReturn(new ResourceLinks.ModificationsLinks(uriInfo));
when(resourceLinks.repositoryType()).thenReturn(new ResourceLinks.RepositoryTypeLinks(uriInfo));
when(resourceLinks.repositoryTypeCollection()).thenReturn(new ResourceLinks.RepositoryTypeCollectionLinks(uriInfo));
when(resourceLinks.uiPluginCollection()).thenReturn(new ResourceLinks.UIPluginCollectionLinks(uriInfo));
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java
index 5f35ce9cf2..4759e1ebd7 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java
@@ -32,7 +32,7 @@ import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
@RunWith(MockitoJUnitRunner.Silent.class)
-public class SourceRootResourceTest {
+public class SourceRootResourceTest extends RepositoryTestBase {
private Dispatcher dispatcher;
private final URI baseUri = URI.create("/");
@@ -63,20 +63,8 @@ public class SourceRootResourceTest {
when(fileObjectToFileObjectDtoMapper.map(any(FileObject.class), any(NamespaceAndName.class), anyString())).thenReturn(dto);
SourceRootResource sourceRootResource = new SourceRootResource(serviceFactory, browserResultToBrowserResultDtoMapper);
- RepositoryRootResource repositoryRootResource =
- new RepositoryRootResource(MockProvider.of(new RepositoryResource(null,
- null,
- null,
- null,
- null,
- null,
- MockProvider.of(sourceRootResource),
- null,
- null,
- null,
- null)),
- null);
- dispatcher = createDispatcher(repositoryRootResource);
+ super.sourceRootResource = MockProvider.of(sourceRootResource);
+ dispatcher = createDispatcher(getRepositoryRootResource());
}
@Test
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 ad4b396101..3149182d98 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
@@ -7,7 +7,6 @@ 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;
@@ -35,14 +34,15 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static sonia.scm.api.v2.resources.DispatcherMock.createDispatcher;
@Slf4j
@RunWith(MockitoJUnitRunner.Silent.class)
-public class TagRootResourceTest {
+public class TagRootResourceTest extends RepositoryTestBase {
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 Dispatcher dispatcher ;
private final URI baseUri = URI.create("/");
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
@@ -55,7 +55,6 @@ public class TagRootResourceTest {
@Mock
private TagsCommandBuilder tagsCommandBuilder;
-
private TagCollectionToDtoMapper tagCollectionToDtoMapper;
@InjectMocks
@@ -72,10 +71,8 @@ public class TagRootResourceTest {
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)), null);
- dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
+ super.tagRootResource = MockProvider.of(tagRootResource);
+ dispatcher = createDispatcher(getRepositoryRootResource());
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"));