You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ra...@apache.org on 2019/09/13 13:53:38 UTC

[sling-org-apache-sling-committer-cli] branch master updated: SLING-8694 - Allow selectively downloading artifacts from a staged Nexus repository

This is an automated email from the ASF dual-hosted git repository.

radu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-committer-cli.git


The following commit(s) were added to refs/heads/master by this push:
     new 4988558  SLING-8694 - Allow selectively downloading artifacts from a staged Nexus repository
4988558 is described below

commit 4988558ae1328e318f094e4c2b63ac6fda98c95b
Author: Radu Cotescu <ra...@apache.org>
AuthorDate: Fri Sep 13 15:51:54 2019 +0200

    SLING-8694 - Allow selectively downloading artifacts from a staged Nexus repository
---
 pom.xml                                            |   1 +
 .../sling/cli/impl/http/HttpClientFactory.java     |  14 +-
 .../apache/sling/cli/impl/jira/VersionClient.java  |   4 +-
 .../org/apache/sling/cli/impl/nexus/Artifact.java  |  15 +-
 .../sling/cli/impl/nexus/RepositoryService.java    | 175 +++++++++++++--------
 .../sling/cli/impl/ci/CIStatusValidatorTest.java   |  27 ++--
 .../sling/cli/impl/http/HttpExchangeHandler.java   |  46 ++++++
 .../org/apache/sling/cli/impl/jira/JiraAction.java |  52 +++---
 .../org/apache/sling/cli/impl/jira/MockJira.java   |  15 +-
 .../org/apache/sling/cli/impl/nexus/MockNexus.java |  92 +++++++++++
 .../cli/impl/nexus/QueryLuceneIndexHandler.java    |  62 ++++++++
 .../cli/impl/nexus/RepositoryContentHandler.java   |  37 +++++
 .../cli/impl/nexus/RepositoryServiceTest.java      | 161 +++++++++++++++++++
 .../cli/impl/nexus/StagingRepositoriesHandler.java |  50 ++++++
 .../resources/nexus/orgapachesling-0/lucene.json   |  51 ++++++
 .../1.0.0/adapter-annotations-1.0.0-javadoc.jar    | Bin 0 -> 34361 bytes
 .../adapter-annotations-1.0.0-javadoc.jar.asc      |   8 +
 .../adapter-annotations-1.0.0-javadoc.jar.md5      |   1 +
 .../adapter-annotations-1.0.0-javadoc.jar.sha1     |   1 +
 .../adapter-annotations-1.0.0-source-release.zip   | Bin 0 -> 10162 bytes
 ...dapter-annotations-1.0.0-source-release.zip.asc |   8 +
 ...dapter-annotations-1.0.0-source-release.zip.md5 |   1 +
 ...apter-annotations-1.0.0-source-release.zip.sha1 |   1 +
 .../1.0.0/adapter-annotations-1.0.0-sources.jar    | Bin 0 -> 8183 bytes
 .../adapter-annotations-1.0.0-sources.jar.asc      |   8 +
 .../adapter-annotations-1.0.0-sources.jar.md5      |   1 +
 .../adapter-annotations-1.0.0-sources.jar.sha1     |   1 +
 .../1.0.0/adapter-annotations-1.0.0.jar            | Bin 0 -> 8833 bytes
 .../1.0.0/adapter-annotations-1.0.0.jar.asc        |   8 +
 .../1.0.0/adapter-annotations-1.0.0.jar.md5        |   1 +
 .../1.0.0/adapter-annotations-1.0.0.jar.sha1       |   1 +
 .../1.0.0/adapter-annotations-1.0.0.pom            |  40 +++++
 .../1.0.0/adapter-annotations-1.0.0.pom.asc        |   8 +
 .../1.0.0/adapter-annotations-1.0.0.pom.md5        |   1 +
 .../1.0.0/adapter-annotations-1.0.0.pom.sha1       |   1 +
 src/test/resources/nexus/staging-repositories.json |  52 ++++++
 36 files changed, 820 insertions(+), 124 deletions(-)

diff --git a/pom.xml b/pom.xml
index 5fc6e33..7591c69 100644
--- a/pom.xml
+++ b/pom.xml
@@ -173,6 +173,7 @@
                 <configuration>
                     <excludes>
                         <exclude>src/main/resources/templates/*</exclude>
+                        <exclude>src/test/resources/nexus/orgapachesling-0/**/*</exclude>
                     </excludes>
                 </configuration>
             </plugin>
diff --git a/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java b/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java
index fe2bf2f..adc8d8e 100644
--- a/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java
+++ b/src/main/java/org/apache/sling/cli/impl/http/HttpClientFactory.java
@@ -30,6 +30,7 @@ import org.apache.sling.cli.impl.ComponentContextHelper;
 import org.apache.sling.cli.impl.Credentials;
 import org.apache.sling.cli.impl.CredentialsService;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 
@@ -38,18 +39,25 @@ public class HttpClientFactory {
     
     private static final String DEFAULT_JIRA_HOST = "issues.apache.org";
     private static final int DEFAULT_JIRA_PORT = 443;
+
+    private static final String DEFAULT_NEXUS_HOST = "repository.apache.org";
+    private static final int DEFAULT_NEXUS_PORT = 443;
     
     @Reference
     private CredentialsService credentialsService;
     
     private String jiraHost;
     private int jiraPort;
-    
+    private String nexusHost;
+    private int nexusPort;
+
+    @Activate
     protected void activate(ComponentContext ctx) {
-        
         ComponentContextHelper helper = ComponentContextHelper.wrap(ctx);
         jiraHost = helper.getProperty("jira.host", DEFAULT_JIRA_HOST);
         jiraPort = helper.getProperty("jira.port", DEFAULT_JIRA_PORT);
+        nexusHost = helper.getProperty("nexus.host", DEFAULT_NEXUS_HOST);
+        nexusPort = helper.getProperty("nexus.port", DEFAULT_NEXUS_PORT);
     }
 
     public CloseableHttpClient newClient() {
@@ -64,7 +72,7 @@ public class HttpClientFactory {
         Credentials jira = credentialsService.getJiraCredentials();
         
         BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope("repository.apache.org", 443), 
+        credentialsProvider.setCredentials(new AuthScope(nexusHost, nexusPort),
                 new UsernamePasswordCredentials(asf.getUsername(), asf.getPassword()));
         credentialsProvider.setCredentials(new AuthScope("reporter.apache.org", 443), 
                 new UsernamePasswordCredentials(asf.getUsername(), asf.getPassword()));
diff --git a/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java b/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java
index b62599e..51d5394 100644
--- a/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java
+++ b/src/main/java/org/apache/sling/cli/impl/jira/VersionClient.java
@@ -38,6 +38,7 @@ import org.apache.sling.cli.impl.ComponentContextHelper;
 import org.apache.sling.cli.impl.http.HttpClientFactory;
 import org.apache.sling.cli.impl.release.Release;
 import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 
@@ -60,7 +61,8 @@ public class VersionClient {
     @Reference
     private HttpClientFactory httpClientFactory;
     private String jiraUrlPrefix;
-    
+
+    @Activate
     protected void activate(ComponentContext ctx) {
         ComponentContextHelper helper = ComponentContextHelper.wrap(ctx);
         jiraUrlPrefix = helper.getProperty("jira.url.prefix", DEFAULT_JIRA_URL_PREFIX);
diff --git a/src/main/java/org/apache/sling/cli/impl/nexus/Artifact.java b/src/main/java/org/apache/sling/cli/impl/nexus/Artifact.java
index 74194b5..7656301 100644
--- a/src/main/java/org/apache/sling/cli/impl/nexus/Artifact.java
+++ b/src/main/java/org/apache/sling/cli/impl/nexus/Artifact.java
@@ -18,6 +18,7 @@
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 package org.apache.sling.cli.impl.nexus;
 
+import java.net.URI;
 import java.util.Objects;
 
 /**
@@ -25,17 +26,20 @@ import java.util.Objects;
  */
 public class Artifact {
 
+    private final StagingRepository repository;
     private final String groupId;
     private final String artifactId;
     private final String version;
     private final String classifier;
     private final String type;
+    private final URI uri;
     private final String repositoryRelativePath;
     private final String repositoryRelativeSignaturePath;
     private final String repositoryRelativeSha1SumPath;
     private final String repositoryRelativeMd5SumPath;
 
-    public Artifact(String groupId, String artifactId, String version, String classifier, String type) {
+    public Artifact(StagingRepository repository, String groupId, String artifactId, String version, String classifier, String type) {
+        this.repository = repository;
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.version = version;
@@ -48,11 +52,20 @@ public class Artifact {
         }
         stringBuilder.append(".").append(this.type);
         repositoryRelativePath = stringBuilder.toString();
+        uri = URI.create(repository.getRepositoryURI() + "/" + repositoryRelativePath);
         repositoryRelativeSignaturePath = repositoryRelativePath + ".asc";
         repositoryRelativeSha1SumPath = repositoryRelativePath + ".sha1";
         repositoryRelativeMd5SumPath = repositoryRelativePath + ".md5";
     }
 
+    public StagingRepository getRepository() {
+        return repository;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
     public String getRepositoryRelativePath() {
         return repositoryRelativePath;
     }
diff --git a/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java b/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java
index 22d21e4..3a19db4 100644
--- a/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java
+++ b/src/main/java/org/apache/sling/cli/impl/nexus/RepositoryService.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -34,9 +35,12 @@ import org.apache.commons.io.IOUtils;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.sling.cli.impl.ComponentContextHelper;
 import org.apache.sling.cli.impl.http.HttpClientFactory;
 import org.apache.sling.cli.impl.nexus.StagingRepository.Status;
 import org.jetbrains.annotations.NotNull;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -50,52 +54,60 @@ import com.google.gson.JsonParser;
 
 @Component(service = RepositoryService.class)
 public class RepositoryService {
-    
-    private static final String REPOSITORY_PREFIX = "orgapachesling-";
+
     private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryService.class);
+    private static final String REPOSITORY_PREFIX = "orgapachesling-";
+    private static final String DEFAULT_NEXUS_URL_PREFIX = "https://repository.apache.org";
+    private static final String CONTENT_TYPE_JSON = "application/json";
 
     private Map<String, LocalRepository> repositories = new HashMap<>();
     private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
 
     @Reference
     private HttpClientFactory httpClientFactory;
+    private String nexusUrlPrefix;
+
+    @Activate
+    private void activate(ComponentContext componentContext) {
+        ComponentContextHelper helper = ComponentContextHelper.wrap(componentContext);
+        nexusUrlPrefix = helper.getProperty("nexus.url.prefix", DEFAULT_NEXUS_URL_PREFIX);
+    }
 
     public List<StagingRepository> list() throws IOException {
-        return this.withStagingRepositories( reader -> {
+        return this.withStagingRepositories(reader -> {
             Gson gson = new Gson();
             return gson.fromJson(reader, StagingRepositories.class).getData().stream()
-                    .filter( r -> r.getType() == Status.closed)
-                    .filter( r -> r.getRepositoryId().startsWith(REPOSITORY_PREFIX) )
-                    .collect(Collectors.toList());            
+                    .filter(r -> r.getType() == Status.closed)
+                    .filter(r -> r.getRepositoryId().startsWith(REPOSITORY_PREFIX))
+                    .collect(Collectors.toList());
         });
     }
 
     public StagingRepository find(int stagingRepositoryId) throws IOException {
-        return this.withStagingRepositories( reader -> {
+        return this.withStagingRepositories(reader -> {
             Gson gson = new Gson();
             return gson.fromJson(reader, StagingRepositories.class).getData().stream()
-                    .filter( r -> r.getType() == Status.closed)
-                    .filter( r -> r.getRepositoryId().startsWith(REPOSITORY_PREFIX) )
-                    .filter( r -> r.getRepositoryId().endsWith("-" + stagingRepositoryId))
+                    .filter(r -> r.getType() == Status.closed)
+                    .filter(r -> r.getRepositoryId().startsWith(REPOSITORY_PREFIX))
+                    .filter(r -> r.getRepositoryId().endsWith("-" + stagingRepositoryId))
                     .findFirst()
-                    .orElseThrow(() -> new IllegalArgumentException("No repository found with id " + stagingRepositoryId));            
+                    .orElseThrow(() -> new IllegalArgumentException("No repository found with id " + stagingRepositoryId));
         });
     }
-    
+
     private <T> T withStagingRepositories(Function<InputStreamReader, T> function) throws IOException {
-        try ( CloseableHttpClient client = httpClientFactory.newClient() ) {
-            HttpGet get = new HttpGet("https://repository.apache.org/service/local/staging/profile_repositories");
-            get.addHeader("Accept", "application/json");
-            try ( CloseableHttpResponse response = client.execute(get)) {
-                try ( InputStream content = response.getEntity().getContent();
-                        InputStreamReader reader = new InputStreamReader(content)) {
-                    if ( response.getStatusLine().getStatusCode() != 200 )
+        try (CloseableHttpClient client = httpClientFactory.newClient()) {
+            HttpGet get = newGet("/service/local/staging/profile_repositories");
+            try (CloseableHttpResponse response = client.execute(get)) {
+                try (InputStream content = response.getEntity().getContent();
+                     InputStreamReader reader = new InputStreamReader(content)) {
+                    if (response.getStatusLine().getStatusCode() != 200) {
                         throw new IOException("Status line : " + response.getStatusLine());
-                    
+                    }
                     return function.apply(reader);
                 }
             }
-        }       
+        }
     }
 
     @NotNull
@@ -107,54 +119,24 @@ public class RepositoryService {
             readWriteLock.writeLock().lock();
             try {
                 if (!repositories.containsKey(repository.getRepositoryId())) {
+                    Path rootFolder = Files.createTempDirectory(repository.getRepositoryId() + "_");
+                    Set<Artifact> artifacts = getArtifacts(repository);
                     try (CloseableHttpClient client = httpClientFactory.newClient()) {
-                        HttpGet get =
-                                new HttpGet("https://repository.apache.org/service/local/lucene/search?g=org.apache.sling&repositoryId=" +
-                                        repository.getRepositoryId());
-                        get.addHeader("Accept", "application/json");
-                        try (CloseableHttpResponse response = client.execute(get)) {
-                            try (InputStream content = response.getEntity().getContent();
-                                 InputStreamReader reader = new InputStreamReader(content)) {
-                                JsonParser parser = new JsonParser();
-                                JsonObject json = parser.parse(reader).getAsJsonObject();
-                                JsonArray data = json.get("data").getAsJsonArray();
-                                Set<Artifact> artifacts = new HashSet<>();
-                                for (JsonElement dataElement : data) {
-                                    JsonObject dataElementJson = dataElement.getAsJsonObject();
-                                    String groupId = dataElementJson.get("groupId").getAsString();
-                                    String artifactId = dataElementJson.get("artifactId").getAsString();
-                                    String version = dataElementJson.get("version").getAsString();
-                                    JsonArray artifactLinksArray =
-                                            dataElementJson.get("artifactHits").getAsJsonArray().get(0).getAsJsonObject().get("artifactLinks")
-                                                    .getAsJsonArray();
-                                    for (JsonElement artifactLinkElement : artifactLinksArray) {
-                                        JsonObject artifactLinkJson = artifactLinkElement.getAsJsonObject();
-                                        String type = artifactLinkJson.get("extension").getAsString();
-                                        String classifier = null;
-                                        if (artifactLinkJson.has("classifier")) {
-                                            classifier = artifactLinkJson.get("classifier").getAsString();
-                                        }
-                                        artifacts.add(new Artifact(groupId,artifactId, version, classifier, type));
-                                    }
-                                }
-                                Path rootFolder = Files.createTempDirectory(repository.getRepositoryId() + "_");
-                                for (Artifact artifact : artifacts) {
-                                    String fileRelativePath = artifact.getRepositoryRelativePath();
-                                    String relativeFolderPath = fileRelativePath.substring(0, fileRelativePath.lastIndexOf('/'));
-                                    Path artifactFolderPath = Files.createDirectories(rootFolder.resolve(relativeFolderPath));
-                                    downloadArtifactFile(repository, client, artifactFolderPath, fileRelativePath);
-                                    downloadArtifactFile(repository, client, artifactFolderPath,
-                                            artifact.getRepositoryRelativeSignaturePath());
-                                    downloadArtifactFile(repository, client, artifactFolderPath,
-                                            artifact.getRepositoryRelativeSha1SumPath());
-                                    downloadArtifactFile(repository, client, artifactFolderPath,
-                                            artifact.getRepositoryRelativeMd5SumPath());
-                                }
-                                localRepository = new LocalRepository(repository, artifacts, rootFolder);
-                                repositories.put(localRepository.getRepositoryId(), localRepository);
-                            }
+                        for (Artifact artifact : artifacts) {
+                            String fileRelativePath = artifact.getRepositoryRelativePath();
+                            String relativeFolderPath = fileRelativePath.substring(0, fileRelativePath.lastIndexOf('/'));
+                            Path artifactFolderPath = Files.createDirectories(rootFolder.resolve(relativeFolderPath));
+                            downloadFileFromRepository(repository, client, artifactFolderPath, fileRelativePath);
+                            downloadFileFromRepository(repository, client, artifactFolderPath,
+                                    artifact.getRepositoryRelativeSignaturePath());
+                            downloadFileFromRepository(repository, client, artifactFolderPath,
+                                    artifact.getRepositoryRelativeSha1SumPath());
+                            downloadFileFromRepository(repository, client, artifactFolderPath,
+                                    artifact.getRepositoryRelativeMd5SumPath());
                         }
                     }
+                    localRepository = new LocalRepository(repository, artifacts, rootFolder);
+                    repositories.put(localRepository.getRepositoryId(), localRepository);
                 }
                 readWriteLock.readLock().lock();
             } finally {
@@ -171,8 +153,58 @@ public class RepositoryService {
         }
     }
 
-    private void downloadArtifactFile(@NotNull StagingRepository repository, CloseableHttpClient client, Path artifactFolderPath,
-                                      String relativeFilePath) throws IOException {
+    public Set<Artifact> getArtifacts(StagingRepository repository) throws IOException {
+        Set<Artifact> artifacts = new HashSet<>();
+        try (CloseableHttpClient client = httpClientFactory.newClient()) {
+            HttpGet get =
+                    newGet("/service/local/lucene/search?g=org.apache.sling&repositoryId=" +
+                            repository.getRepositoryId());
+            try (CloseableHttpResponse response = client.execute(get)) {
+                try (InputStream content = response.getEntity().getContent();
+                     InputStreamReader reader = new InputStreamReader(content)) {
+                    JsonParser parser = new JsonParser();
+                    JsonObject json = parser.parse(reader).getAsJsonObject();
+                    JsonArray data = json.get("data").getAsJsonArray();
+
+                    for (JsonElement dataElement : data) {
+                        JsonObject dataElementJson = dataElement.getAsJsonObject();
+                        String groupId = dataElementJson.get("groupId").getAsString();
+                        String artifactId = dataElementJson.get("artifactId").getAsString();
+                        String version = dataElementJson.get("version").getAsString();
+                        JsonArray artifactLinksArray =
+                                dataElementJson.get("artifactHits").getAsJsonArray().get(0).getAsJsonObject().get("artifactLinks")
+                                        .getAsJsonArray();
+                        for (JsonElement artifactLinkElement : artifactLinksArray) {
+                            JsonObject artifactLinkJson = artifactLinkElement.getAsJsonObject();
+                            String type = artifactLinkJson.get("extension").getAsString();
+                            String classifier = null;
+                            if (artifactLinkJson.has("classifier")) {
+                                classifier = artifactLinkJson.get("classifier").getAsString();
+                            }
+                            artifacts.add(new Artifact(repository, groupId, artifactId, version, classifier, type));
+                        }
+                    }
+                }
+            }
+        }
+        return artifacts;
+    }
+
+    public void processArtifactStream(Artifact artifact, Consumer<InputStream> consumer) throws IOException {
+        try (CloseableHttpClient client = httpClientFactory.newClient()) {
+            HttpGet get = new HttpGet(artifact.getUri());
+            try (CloseableHttpResponse response = client.execute(get)) {
+                int statusCode = response.getStatusLine().getStatusCode();
+                if (statusCode != 200) {
+                    throw new IOException(String.format("Got %d instead of 200 when retrieving %s.", statusCode, get.getURI()));
+                }
+                consumer.accept(response.getEntity().getContent());
+            }
+        }
+    }
+
+    private void downloadFileFromRepository(@NotNull StagingRepository repository, @NotNull CloseableHttpClient client,
+                                            @NotNull Path artifactFolderPath, @NotNull String relativeFilePath) throws IOException {
         String fileName = relativeFilePath.substring(relativeFilePath.lastIndexOf('/') + 1);
         Path filePath = Files.createFile(artifactFolderPath.resolve(fileName));
         HttpGet get = new HttpGet(repository.getRepositoryURI() + "/" + relativeFilePath);
@@ -183,4 +215,11 @@ public class RepositoryService {
             }
         }
     }
+
+    private HttpGet newGet(String suffix) {
+        HttpGet get = new HttpGet(nexusUrlPrefix + suffix);
+        get.addHeader("Accept", CONTENT_TYPE_JSON);
+        return get;
+    }
+
 }
diff --git a/src/test/java/org/apache/sling/cli/impl/ci/CIStatusValidatorTest.java b/src/test/java/org/apache/sling/cli/impl/ci/CIStatusValidatorTest.java
index 7320c0b..d891ef2 100644
--- a/src/test/java/org/apache/sling/cli/impl/ci/CIStatusValidatorTest.java
+++ b/src/test/java/org/apache/sling/cli/impl/ci/CIStatusValidatorTest.java
@@ -16,12 +16,6 @@
  */
 package org.apache.sling.cli.impl.ci;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -29,16 +23,23 @@ import java.nio.file.Path;
 
 import org.apache.sling.cli.impl.ci.CIStatusValidator.ValidationResult;
 import org.apache.sling.cli.impl.nexus.Artifact;
+import org.apache.sling.cli.impl.nexus.StagingRepository;
 import org.junit.Test;
 
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
 public class CIStatusValidatorTest {
 
     private CIStatusValidator validator = new CIStatusValidator() {
 
-        protected JsonObject fetchCIStatus(String ciEndpoint) throws UnsupportedOperationException, IOException {
+        protected JsonObject fetchCIStatus(String ciEndpoint) throws UnsupportedOperationException {
             InputStreamReader reader = null;
             if ("https://api.github.com/repos/apache/sling-repo-pom/commits/repo-pom-1.0/status".equals(ciEndpoint)) {
                 reader = new InputStreamReader(CIStatusValidatorTest.class.getResourceAsStream("/ci/failure.json"));
@@ -46,16 +47,20 @@ public class CIStatusValidatorTest {
                     .equals(ciEndpoint)) {
                 reader = new InputStreamReader(CIStatusValidatorTest.class.getResourceAsStream("/ci/success.json"));
             }
+            if (reader == null) {
+                throw new NullPointerException("No reader was found for " + ciEndpoint);
+            }
             JsonParser parser = new JsonParser();
             return parser.parse(reader).getAsJsonObject();
         }
 
     };
-    private static Artifact JAR = new Artifact("org.apache.sling", "sample-artifact", "1.0", "", "jar");
-    private static Artifact NON_REPO_POM_ARTIFACT = new Artifact("org.apache.sling", "no-repo-pom", "1.0", "", "pom");
+    private static final StagingRepository REPOSITORY = mock(StagingRepository.class);
+    private static Artifact JAR = new Artifact(REPOSITORY, "org.apache.sling", "sample-artifact", "1.0", "", "jar");
+    private static Artifact NON_REPO_POM_ARTIFACT = new Artifact(REPOSITORY, "org.apache.sling", "no-repo-pom", "1.0", "", "pom");
     private static Path NON_REPO_POM_FILE;
-    private static Artifact POM_ARTIFACT = new Artifact("org.apache.sling", "repo-pom", "1.0", "", "pom");
-    private static Artifact SUCCESSFUL_POM_ARTIFACT = new Artifact("org.apache.sling", "successful-pom", "1.0", "",
+    private static Artifact POM_ARTIFACT = new Artifact(REPOSITORY, "org.apache.sling", "repo-pom", "1.0", "", "pom");
+    private static Artifact SUCCESSFUL_POM_ARTIFACT = new Artifact(REPOSITORY, "org.apache.sling", "successful-pom", "1.0", "",
             "pom");
     private static Path POM_FILE;
 
diff --git a/src/test/java/org/apache/sling/cli/impl/http/HttpExchangeHandler.java b/src/test/java/org/apache/sling/cli/impl/http/HttpExchangeHandler.java
new file mode 100644
index 0000000..660d34c
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/http/HttpExchangeHandler.java
@@ -0,0 +1,46 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.http;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.commons.io.IOUtils;
+
+import com.sun.net.httpserver.HttpExchange;
+
+public interface HttpExchangeHandler {
+
+    default void serveFileFromClasspath(HttpExchange ex, String classpathLocation) throws IOException {
+        InputStream in = getClass().getResourceAsStream(classpathLocation);
+        if ( in == null  ) {
+            ex.sendResponseHeaders(404, -1);
+            return;
+        }
+
+        ex.sendResponseHeaders(200, 0);
+        try ( OutputStream out = ex.getResponseBody() ) {
+            IOUtils.copy(in, out);
+        }
+    }
+
+    boolean tryHandle(HttpExchange ex) throws IOException;
+
+}
diff --git a/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java b/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java
index 8d84a3a..a2674b1 100644
--- a/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java
+++ b/src/test/java/org/apache/sling/cli/impl/jira/JiraAction.java
@@ -1,19 +1,21 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 package org.apache.sling.cli.impl.jira;
 
 import java.io.IOException;
@@ -23,12 +25,13 @@ import java.io.OutputStreamWriter;
 import java.util.function.Consumer;
 
 import org.apache.commons.io.IOUtils;
+import org.apache.sling.cli.impl.http.HttpExchangeHandler;
 import org.apache.sling.cli.impl.jira.ErrorResponse;
 
 import com.google.gson.Gson;
 import com.sun.net.httpserver.HttpExchange;
 
-public interface JiraAction {
+public interface JiraAction extends HttpExchangeHandler {
     
     default void error(HttpExchange httpExchange, Gson gson, Consumer<ErrorResponse> c) throws IOException {
         try ( OutputStreamWriter out = new OutputStreamWriter(httpExchange.getResponseBody()) ) {
@@ -39,18 +42,5 @@ public interface JiraAction {
         }
     }
     
-    default void serveFileFromClasspath(HttpExchange ex, String classpathLocation) throws IOException {
-        InputStream in = getClass().getResourceAsStream(classpathLocation);
-        if ( in == null  ) {
-            ex.sendResponseHeaders(404, -1);
-            return;
-        }
-     
-        ex.sendResponseHeaders(200, 0);
-        try ( OutputStream out = ex.getResponseBody() ) {
-            IOUtils.copy(in, out);
-        }
-    }
-    
-    boolean tryHandle(HttpExchange ex) throws IOException;
+
 }
diff --git a/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java b/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java
index 9dcffcd..5c411e9 100644
--- a/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java
+++ b/src/test/java/org/apache/sling/cli/impl/jira/MockJira.java
@@ -16,11 +16,11 @@
  */
 package org.apache.sling.cli.impl.jira;
 
-import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.sling.cli.impl.http.HttpExchangeHandler;
 import org.junit.rules.ExternalResource;
 
 import com.sun.net.httpserver.Authenticator;
@@ -64,24 +64,21 @@ public class MockJira extends ExternalResource {
             }
         });
         
-        List<JiraAction> actions = new ArrayList<>();
+        List<HttpExchangeHandler> actions = new ArrayList<>();
         actions.add(new ListVersionsJiraAction());
         actions.add(new GetRelatedIssueCountsForVersionsJiraAction());
         actions.add(new CreateVersionJiraAction());
         actions.add(new IssuesSearchJiraAction());
         
         // fallback, always executed
-        actions.add(new JiraAction() {
-            @Override
-            public boolean tryHandle(HttpExchange ex) throws IOException {
-                ex.sendResponseHeaders(400, -1);
-                return true;
-            }
+        actions.add(ex -> {
+            ex.sendResponseHeaders(400, -1);
+            return true;
         });
         
         rootContext.setHandler(httpExchange -> {
             
-            for ( JiraAction action : actions ) {
+            for ( HttpExchangeHandler action : actions ) {
                 if ( action.tryHandle(httpExchange) ) {
                     break;
                 }
diff --git a/src/test/java/org/apache/sling/cli/impl/nexus/MockNexus.java b/src/test/java/org/apache/sling/cli/impl/nexus/MockNexus.java
new file mode 100644
index 0000000..d4a9cee
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/nexus/MockNexus.java
@@ -0,0 +1,92 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.nexus;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.cli.impl.http.HttpExchangeHandler;
+import org.junit.rules.ExternalResource;
+
+import com.sun.net.httpserver.Authenticator;
+import com.sun.net.httpserver.BasicAuthenticator;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpPrincipal;
+import com.sun.net.httpserver.HttpServer;
+
+public class MockNexus extends ExternalResource {
+
+    static final String NEXUS_USER = "asf-user";
+    static final String NEXUS_PASSWORD = "asf-password";
+
+    private HttpServer server;
+
+    @Override
+    protected void before() throws Throwable {
+        server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
+        HttpContext rootContext = server.createContext("/");
+        rootContext.setAuthenticator(new BasicAuthenticator(getClass().getSimpleName()) {
+
+            @Override
+            public boolean checkCredentials(String username, String password) {
+                return NEXUS_USER.equals(username) && NEXUS_PASSWORD.equals(password);
+            }
+
+            @Override
+            public Result authenticate(HttpExchange t) {
+                if ( t.getRequestMethod().contentEquals("GET") ) {
+                    if (!"/service/local/staging/profile_repositories".equals(t.getRequestURI().getPath())) {
+                        return new Authenticator.Success(new HttpPrincipal("anonymous", getClass().getSimpleName()));
+                    }
+                }
+                return super.authenticate(t);
+            }
+        });
+
+        List<HttpExchangeHandler> handlers = new ArrayList<>();
+        handlers.add(new QueryLuceneIndexHandler());
+        handlers.add(new StagingRepositoriesHandler());
+        handlers.add(new RepositoryContentHandler());
+        handlers.add(ex -> {
+            ex.sendResponseHeaders(400, -1);
+            return true;
+        });
+
+        rootContext.setHandler(exchange -> {
+            for (HttpExchangeHandler handler : handlers) {
+                if (handler.tryHandle(exchange)) {
+                    break;
+                }
+            }
+        });
+
+        server.start();
+    }
+
+    @Override
+    protected void after() {
+        server.stop(0);
+    }
+
+    int getBoundPort() {
+        return server.getAddress().getPort();
+    }
+}
diff --git a/src/test/java/org/apache/sling/cli/impl/nexus/QueryLuceneIndexHandler.java b/src/test/java/org/apache/sling/cli/impl/nexus/QueryLuceneIndexHandler.java
new file mode 100644
index 0000000..e5ae980
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/nexus/QueryLuceneIndexHandler.java
@@ -0,0 +1,62 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.nexus;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.sling.cli.impl.http.HttpExchangeHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.net.httpserver.HttpExchange;
+
+public class QueryLuceneIndexHandler implements HttpExchangeHandler {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(QueryLuceneIndexHandler.class);
+
+    @Override
+    public boolean tryHandle(HttpExchange ex) throws IOException {
+        if ( !ex.getRequestMethod().equals("GET") ||
+                !ex.getRequestURI().getPath().equals("/service/local/lucene/search")) {
+            return false;
+        }
+        String group = null;
+        String repositoryId = null;
+        List<NameValuePair> parameters = URLEncodedUtils.parse(ex.getRequestURI(), StandardCharsets.UTF_8);
+        for (NameValuePair pair : parameters) {
+            if ("g".equalsIgnoreCase(pair.getName())) {
+                group = pair.getValue();
+            }
+            if ("repositoryId".equalsIgnoreCase(pair.getName())) {
+                repositoryId = pair.getValue();
+            }
+        }
+        if (StringUtils.isEmpty(group)) {
+            LOGGER.warn("Expected a group (g) parameter. Skipping handler.");
+            return false;
+        }
+        serveFileFromClasspath(ex, "/nexus/" + repositoryId + "/lucene.json");
+        return true;
+    }
+}
diff --git a/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryContentHandler.java b/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryContentHandler.java
new file mode 100644
index 0000000..084490f
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryContentHandler.java
@@ -0,0 +1,37 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.nexus;
+
+import java.io.IOException;
+
+import org.apache.sling.cli.impl.http.HttpExchangeHandler;
+
+import com.sun.net.httpserver.HttpExchange;
+
+public class RepositoryContentHandler implements HttpExchangeHandler {
+
+    @Override
+    public boolean tryHandle(HttpExchange ex) throws IOException {
+        if (!"GET".equals(ex.getRequestMethod()) && !ex.getRequestURI().getPath().startsWith("/content/repositories/")) {
+            return false;
+        }
+        serveFileFromClasspath(ex, "/nexus/" + ex.getRequestURI().getPath().substring(22));
+        return true;
+    }
+}
diff --git a/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java b/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java
new file mode 100644
index 0000000..4591f43
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/nexus/RepositoryServiceTest.java
@@ -0,0 +1,161 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.nexus;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.cli.impl.CredentialsService;
+import org.apache.sling.cli.impl.http.HttpClientFactory;
+import org.apache.sling.cli.impl.jira.SystemPropertiesRule;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class RepositoryServiceTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryServiceTest.class);
+    private static final Map<String, String> SYSTEM_PROPS = new HashMap<>();
+
+    static {
+        SYSTEM_PROPS.put("asf.username", "asf-user");
+        SYSTEM_PROPS.put("asf.password", "asf-password");
+        SYSTEM_PROPS.put("jira.username", "jira-user");
+        SYSTEM_PROPS.put("jira.password", "jira-password");
+    }
+
+    private RepositoryService repositoryService;
+
+    @Rule
+    public final OsgiContext context = new OsgiContext();
+
+    @Rule
+    public final SystemPropertiesRule sysProps = new SystemPropertiesRule(SYSTEM_PROPS);
+
+    @Rule
+    public MockNexus nexus = new MockNexus();
+
+    @Before
+    public void prepareDependencies() {
+        context.registerInjectActivateService(new CredentialsService());
+        context.registerInjectActivateService(new HttpClientFactory(), "nexus.host", "localhost", "nexus.port", nexus.getBoundPort());
+        repositoryService = context.registerInjectActivateService(new RepositoryService(), "nexus.url.prefix",
+                "http://localhost:" + nexus.getBoundPort());
+    }
+
+    @Test
+    public void testLuceneSearch() throws IOException {
+        Set<Artifact> artifacts = repositoryService.getArtifacts(getStagingRepository());
+        assertEquals(5, artifacts.size());
+    }
+
+    @Test
+    public void testRepositoryFind() throws IOException {
+        StagingRepository stagingRepository = repositoryService.find(0);
+        assertNotNull(stagingRepository);
+    }
+
+    @Test
+    public void testRepositoryList() throws IOException {
+        List<StagingRepository> stagingRepositories = repositoryService.list();
+        assertEquals(2, stagingRepositories.size());
+        Set<String> repositoriesIds = new HashSet<>(Set.of("orgapachesling-0", "orgapachesling-1"));
+        for (StagingRepository repository : stagingRepositories) {
+            assertEquals("http://localhost:" + nexus.getBoundPort() + "/content/repositories/" + repository.getRepositoryId(),
+                    repository.repositoryURI);
+            repositoriesIds.remove(repository.getRepositoryId());
+        }
+        assertTrue(repositoriesIds.isEmpty());
+    }
+
+    @Test
+    public void testArtifactStream() throws IOException {
+        Set<Artifact> artifacts = repositoryService.getArtifacts(getStagingRepository());
+        AtomicReference<Boolean> processed = new AtomicReference<>();
+        processed.set(false);
+        for (Artifact artifact : artifacts) {
+            if ("pom".equals(artifact.getType())) {
+                repositoryService.processArtifactStream(artifact, inputStream -> {
+                    try (InputStream stream = inputStream) {
+                        assertEquals(IOUtils.resourceToString("/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0" +
+                                        ".0/adapter-annotations-1.0.0.pom", StandardCharsets.UTF_8),
+                                IOUtils.toString(stream, StandardCharsets.UTF_8));
+                        processed.set(true);
+                    } catch (IOException e) {
+                        fail("Failed to read POM file.");
+                    }
+                });
+            }
+        }
+        assertTrue(processed.get());
+    }
+
+    @Test
+    public void testDownloadRepository() throws IOException {
+        StagingRepository stagingRepository = getStagingRepository();
+        LocalRepository localRepository = repositoryService.download(stagingRepository);
+        assertNotNull(localRepository);
+        for (Artifact artifact : localRepository.getArtifacts()) {
+            assertTrue(Files.exists(localRepository.getRootFolder().resolve(artifact.getRepositoryRelativePath())));
+        }
+        List<Path> artifactFiles =
+                Files.walk(localRepository.getRootFolder()).filter(path -> path.toFile().isFile()).collect(Collectors.toList());
+        LOGGER.debug("Cleaning {}.", localRepository.getRootFolder());
+        for (Path artifactFile : artifactFiles) {
+            LOGGER.debug("Deleting file {}.", artifactFile.toString());
+            Files.delete(artifactFile);
+        }
+        List<Path> emptyDirectories =
+                Files.walk(localRepository.getRootFolder()).filter(path -> path.toFile().isDirectory()).collect(Collectors.toList());
+        Collections.reverse(emptyDirectories);
+        for (Path directory : emptyDirectories) {
+            LOGGER.debug("Deleting empty folder {}.", directory.toString());
+            Files.delete(directory);
+        }
+    }
+
+
+    private StagingRepository getStagingRepository() {
+        StagingRepository stagingRepository = new StagingRepository();
+        stagingRepository.setRepositoryId("orgapachesling-0");
+        stagingRepository.setRepositoryURI("http://localhost:" + nexus.getBoundPort() + "/content/repositories/orgapachesling-0");
+        return stagingRepository;
+    }
+}
diff --git a/src/test/java/org/apache/sling/cli/impl/nexus/StagingRepositoriesHandler.java b/src/test/java/org/apache/sling/cli/impl/nexus/StagingRepositoriesHandler.java
new file mode 100644
index 0000000..4bd432e
--- /dev/null
+++ b/src/test/java/org/apache/sling/cli/impl/nexus/StagingRepositoriesHandler.java
@@ -0,0 +1,50 @@
+/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements.  See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership.  The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License.  You may obtain a copy of the License at
+ ~
+ ~   http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied.  See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+package org.apache.sling.cli.impl.nexus;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.sling.cli.impl.http.HttpExchangeHandler;
+
+import com.sun.net.httpserver.HttpExchange;
+
+public class StagingRepositoriesHandler implements HttpExchangeHandler {
+
+    @Override
+    public boolean tryHandle(HttpExchange ex) throws IOException {
+        if ( !ex.getRequestMethod().equals("GET") ||
+                !ex.getRequestURI().getPath().equals("/service/local/staging/profile_repositories")) {
+            return false;
+        }
+        InputStream in = getClass().getResourceAsStream("/nexus/staging-repositories.json");
+        String json = IOUtils.toString(in, StandardCharsets.UTF_8);
+        String processedJson =
+                json.replaceAll("\\{nexusHost\\}", "http://localhost:" + ex.getHttpContext().getServer().getAddress().getPort());
+        byte[] bytes = processedJson.getBytes(StandardCharsets.UTF_8);
+        ex.sendResponseHeaders(200, bytes.length);
+        try ( OutputStream out = ex.getResponseBody() ) {
+            out.write(bytes);
+        }
+        return true;
+    }
+}
diff --git a/src/test/resources/nexus/orgapachesling-0/lucene.json b/src/test/resources/nexus/orgapachesling-0/lucene.json
new file mode 100644
index 0000000..6269fb0
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/lucene.json
@@ -0,0 +1,51 @@
+{
+    "totalCount": 4,
+    "from": -1,
+    "count": -1,
+    "tooManyResults": false,
+    "collapsed": false,
+    "repoDetails": [
+        {
+            "repositoryId": "orgapachesling-0",
+            "repositoryName": "orgapachesling-0 (staging: closed)",
+            "repositoryContentClass": "maven2",
+            "repositoryKind": "hosted",
+            "repositoryPolicy": "RELEASE",
+            "repositoryURL": "https://repository.apache.org/service/local/repositories/orgapachesling-0"
+        }
+    ],
+    "data": [
+        {
+            "groupId": "org.apache.sling",
+            "artifactId": "adapter-annotations",
+            "version": "1.0.0",
+            "latestRelease": "1.0.0",
+            "latestReleaseRepositoryId": "orgapachesling-0",
+            "artifactHits": [
+                {
+                    "repositoryId": "orgapachesling-0",
+                    "artifactLinks": [
+                        {
+                            "extension": "pom"
+                        },
+                        {
+                            "extension": "jar"
+                        },
+                        {
+                            "classifier": "sources",
+                            "extension": "jar"
+                        },
+                        {
+                            "classifier": "source-release",
+                            "extension": "zip"
+                        },
+                        {
+                            "classifier": "javadoc",
+                            "extension": "jar"
+                        }
+                    ]
+                }
+            ]
+        }
+    ]
+}
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar
new file mode 100644
index 0000000..4a264ac
Binary files /dev/null and b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar differ
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.asc b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.asc
new file mode 100644
index 0000000..e613888
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (Darwin)
+Comment: GPGTools - http://gpgtools.org
+
+iEYEABECAAYFAk8PEAMACgkQh9vwWhNLFFxjzgCdFSprSdQBK2iz6hQ4djpdTcw/
+0cEAnjoSYi20ctpXpWFQwJ0nxC+XVF1i
+=+rZ8
+-----END PGP SIGNATURE-----
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.md5 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.md5
new file mode 100644
index 0000000..2e210c7
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.md5
@@ -0,0 +1 @@
+ff1c30e7ba5b8e8134b5183d36decb45
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.sha1 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.sha1
new file mode 100644
index 0000000..ac368bb
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-javadoc.jar.sha1
@@ -0,0 +1 @@
+27ee4fd3f6379e270fc9eae00e81858d4a624017
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip
new file mode 100644
index 0000000..ffc0b6d
Binary files /dev/null and b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip differ
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.asc b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.asc
new file mode 100644
index 0000000..3271be8
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (Darwin)
+Comment: GPGTools - http://gpgtools.org
+
+iEYEABECAAYFAk8PEAMACgkQh9vwWhNLFFzVuwCfdAAGrCyliIMTTnLzTWEGbL2m
+YwQAnRsIWaTXSNhNtEwUgvOdna6FEMJ4
+=czQP
+-----END PGP SIGNATURE-----
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.md5 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.md5
new file mode 100644
index 0000000..e85aa81
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.md5
@@ -0,0 +1 @@
+43c7836ae85b9732e1d02b7453382e96
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.sha1 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.sha1
new file mode 100644
index 0000000..f95c1c9
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-source-release.zip.sha1
@@ -0,0 +1 @@
+01034c3a42c8c5f8236f4bdcc960200b82481e97
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar
new file mode 100644
index 0000000..c8a5778
Binary files /dev/null and b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar differ
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.asc b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.asc
new file mode 100644
index 0000000..56efcd3
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (Darwin)
+Comment: GPGTools - http://gpgtools.org
+
+iEYEABECAAYFAk8PEAMACgkQh9vwWhNLFFzVvwCfR1qv5+o6fbHf1Gqf0KnJrCKu
+2ukAnjWsOiwi6a8qT/vJo12I8lqSucuq
+=g/hS
+-----END PGP SIGNATURE-----
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.md5 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.md5
new file mode 100644
index 0000000..e6c59bf
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.md5
@@ -0,0 +1 @@
+f47f5abb8c35c312b546949fb01e59db
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.sha1 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.sha1
new file mode 100644
index 0000000..2c7c353
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0-sources.jar.sha1
@@ -0,0 +1 @@
+184809173a105bf9cf1b2df89ae5ce998202d671
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar
new file mode 100644
index 0000000..9979688
Binary files /dev/null and b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar differ
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.asc b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.asc
new file mode 100644
index 0000000..e219409
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (Darwin)
+Comment: GPGTools - http://gpgtools.org
+
+iEYEABECAAYFAk8PEAMACgkQh9vwWhNLFFwnwACggZgG3zgGqC5XPx4I+zSV+WPS
+vBoAn0YptiZ8QAG78pQiCfcXrivJg9IU
+=jKwg
+-----END PGP SIGNATURE-----
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.md5 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.md5
new file mode 100644
index 0000000..8c2a6b8
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.md5
@@ -0,0 +1 @@
+cd42d2136fcd03809a07b51bf29e76f2
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.sha1 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.sha1
new file mode 100644
index 0000000..f4df9fb
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.jar.sha1
@@ -0,0 +1 @@
+ed992b3c4ee3ebebfa5d5180854516d9ba09fa01
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom
new file mode 100644
index 0000000..b9a3013
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>sling</artifactId>
+        <groupId>org.apache.sling</groupId>
+        <version>12</version>
+        <relativePath>../../parent/pom.xml</relativePath>
+    </parent>
+    <groupId>org.apache.sling</groupId>
+    <artifactId>adapter-annotations</artifactId>
+    <version>1.0.0</version>
+    <name>Sling Adapter Annotations</name>
+    <description>Annotations used to generate Sling Adapter metadata</description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/adapter-annotations-1.0.0</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/adapter-annotations-1.0.0</developerConnection>
+        <url>http://svn.apache.org/viewvc/sling/tags/adapter-annotations-1.0.0</url>
+    </scm>
+</project>
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.asc b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.asc
new file mode 100644
index 0000000..36e8d4d
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.9 (Darwin)
+Comment: GPGTools - http://gpgtools.org
+
+iEYEABECAAYFAk8PEAMACgkQh9vwWhNLFFxzfwCeLOYa9WxKKq499NTO5vC8Yj9v
+rWsAmgIsA01WOQRZ0LsVr2FjcxwWc+Ej
+=aOoY
+-----END PGP SIGNATURE-----
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.md5 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.md5
new file mode 100644
index 0000000..9bffa54
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.md5
@@ -0,0 +1 @@
+292ecfb771bf6761527d4008f093b05d
\ No newline at end of file
diff --git a/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.sha1 b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.sha1
new file mode 100644
index 0000000..a84d136
--- /dev/null
+++ b/src/test/resources/nexus/orgapachesling-0/org/apache/sling/adapter-annotations/1.0.0/adapter-annotations-1.0.0.pom.sha1
@@ -0,0 +1 @@
+7ace1ca3c04a1cbdd3981e2f4855511bb3717e15
\ No newline at end of file
diff --git a/src/test/resources/nexus/staging-repositories.json b/src/test/resources/nexus/staging-repositories.json
new file mode 100644
index 0000000..1d418f7
--- /dev/null
+++ b/src/test/resources/nexus/staging-repositories.json
@@ -0,0 +1,52 @@
+{
+    "data": [
+        {
+            "profileId"            : "6a443ac86e2212",
+            "profileName"          : "org.apache.sling",
+            "profileType"          : "repository",
+            "repositoryId"         : "orgapachesling-0",
+            "type"                 : "closed",
+            "policy"               : "release",
+            "userId"               : "radu",
+            "userAgent"            : "Apache-Maven/3.6.1 (Java 1.8.0_222; Mac OS X 10.14.6)",
+            "ipAddress"            : "127.0.0.1",
+            "repositoryURI"        : "{nexusHost}/content/repositories/orgapachesling-0",
+            "created"              : "2019-09-13T00:00:00.000Z",
+            "createdDate"          : "Fri Sep 13 00:00:00 UTC 2019",
+            "createdTimestamp"     : 1568332800000,
+            "updated"              : "2019-09-13T00:00:00.000Z",
+            "updatedDate"          : "Fri Sep 13 00:00:00 UTC 2019",
+            "updatedTimestamp"     : 1568332800000,
+            "description"          : "Implicitly created (auto staging).",
+            "provider"             : "maven2",
+            "releaseRepositoryId"  : "releases",
+            "releaseRepositoryName": "Releases",
+            "notifications"        : 0,
+            "transitioning"        : false
+        },
+        {
+            "profileId"            : "6a443ac86e2212",
+            "profileName"          : "org.apache.sling",
+            "profileType"          : "repository",
+            "repositoryId"         : "orgapachesling-1",
+            "type"                 : "closed",
+            "policy"               : "release",
+            "userId"               : "radu",
+            "userAgent"            : "Apache-Maven/3.6.1 (Java 1.8.0_222; Mac OS X 10.14.6)",
+            "ipAddress"            : "127.0.0.1",
+            "repositoryURI"        : "{nexusHost}/content/repositories/orgapachesling-1",
+            "created"              : "2019-09-13T00:00:00.000Z",
+            "createdDate"          : "Fri Sep 13 00:00:00 UTC 2019",
+            "createdTimestamp"     : 1568332800000,
+            "updated"              : "2019-09-13T00:00:00.000Z",
+            "updatedDate"          : "Fri Sep 13 00:00:00 UTC 2019",
+            "updatedTimestamp"     : 1568332800000,
+            "description"          : "Implicitly created (auto staging).",
+            "provider"             : "maven2",
+            "releaseRepositoryId"  : "releases",
+            "releaseRepositoryName": "Releases",
+            "notifications"        : 0,
+            "transitioning"        : false
+        }
+    ]
+}