Fix repository resolution for ssh urls with context path

Co-authored-by: René Pfeuffer <rene.pfeuffer@cloudogu.com>
This commit is contained in:
Eduard Heimbuch
2023-02-23 10:57:43 +01:00
committed by SCM-Manager
parent 0361ae3c6c
commit f28eaeca15
5 changed files with 92 additions and 19 deletions

View File

@@ -21,10 +21,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.protocolcommand.git;
import com.google.common.base.Splitter;
import sonia.scm.ContextEntry;
import sonia.scm.NotFoundException;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.protocolcommand.RepositoryContext;
import sonia.scm.protocolcommand.RepositoryContextResolver;
import sonia.scm.repository.NamespaceAndName;
@@ -35,34 +38,43 @@ import sonia.scm.repository.RepositoryManager;
import javax.inject.Inject;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.Optional;
import static java.util.Optional.empty;
import static java.util.Optional.of;
public class GitRepositoryContextResolver implements RepositoryContextResolver {
private RepositoryManager repositoryManager;
private RepositoryLocationResolver locationResolver;
private final RepositoryManager repositoryManager;
private final RepositoryLocationResolver locationResolver;
private final ScmConfiguration configuration;
@Inject
public GitRepositoryContextResolver(RepositoryManager repositoryManager, RepositoryLocationResolver locationResolver) {
public GitRepositoryContextResolver(RepositoryManager repositoryManager, RepositoryLocationResolver locationResolver, ScmConfiguration configuration) {
this.repositoryManager = repositoryManager;
this.locationResolver = locationResolver;
this.configuration = configuration;
}
public RepositoryContext resolve(String[] args) {
NamespaceAndName namespaceAndName = extractNamespaceAndName(args);
NamespaceAndName namespaceAndName = extractNamespaceAndName(args).orElseThrow(() -> NotFoundException.notFound(ContextEntry.ContextBuilder.entity("path", String.join("/", args))));
Repository repository = repositoryManager.get(namespaceAndName);
Path path = locationResolver.forClass(Path.class).getLocation(repository.getId()).resolve("data");
return new RepositoryContext(repository, path);
}
private NamespaceAndName extractNamespaceAndName(String[] args) {
private Optional<NamespaceAndName> extractNamespaceAndName(String[] args) {
String path = args[args.length - 1];
Iterator<String> it = Splitter.on('/').omitEmptyStrings().split(path).iterator();
String type = it.next();
if (type.equals(configuration.getServerContextPath())) {
type = it.next();
}
if ("repo".equals(type)) {
String ns = it.next();
String name = it.next();
return new NamespaceAndName(ns, name);
return of((new NamespaceAndName(ns, name)));
}
return null;
return empty();
}
}

View File

@@ -21,26 +21,31 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.protocolcommand.git;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Answers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.NotFoundException;
import sonia.scm.config.ScmConfiguration;
import sonia.scm.protocolcommand.RepositoryContext;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryLocationResolver;
import sonia.scm.repository.RepositoryManager;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@@ -53,19 +58,47 @@ class GitRepositoryContextResolverTest {
RepositoryManager repositoryManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
RepositoryLocationResolver locationResolver;
@Mock(answer = Answers.CALLS_REAL_METHODS)
ScmConfiguration scmConfiguration;
@InjectMocks
GitRepositoryContextResolver resolver;
@BeforeEach
void mockConfiguration() {
when(scmConfiguration.getBaseUrl()).thenReturn("https://hog.hitchhiker.com/scm");
}
@Nested
class WithRepository {
@BeforeEach
void mockRepository(@TempDir Path repositoryPath) throws IOException {
when(scmConfiguration.getBaseUrl()).thenReturn("https://hog.hitchhiker.com/scm");
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(REPOSITORY);
when(locationResolver.forClass(any()).getLocation("id")).thenReturn(repositoryPath);
}
@Test
void shouldResolveCorrectRepository(@TempDir Path repositoryPath) {
RepositoryContext context = resolver.resolve(new String[]{"git", "repo/space/X/something/else"});
assertThat(context.getRepository()).isSameAs(REPOSITORY);
assertThat(context.getDirectory()).isEqualTo(repositoryPath.resolve("data"));
}
@Test
void shouldResolveCorrectRepositoryWithContextPath(@TempDir Path repositoryPath) throws IOException {
RepositoryContext context = resolver.resolve(new String[]{"git", "scm/repo/space/X/something/else"});
assertThat(context.getRepository()).isSameAs(REPOSITORY);
assertThat(context.getDirectory()).isEqualTo(repositoryPath.resolve("data"));
}
}
@Test
void shouldResolveCorrectRepository() throws IOException {
when(repositoryManager.get(new NamespaceAndName("space", "X"))).thenReturn(REPOSITORY);
Path repositoryPath = File.createTempFile("test", "scm").toPath();
when(locationResolver.forClass(any()).getLocation("id")).thenReturn(repositoryPath);
RepositoryContext context = resolver.resolve(new String[] {"git", "repo/space/X/something/else"});
assertThat(context.getRepository()).isSameAs(REPOSITORY);
assertThat(context.getDirectory()).isEqualTo(repositoryPath.resolve("data"));
void shouldRejectWrongContextPath() {
assertThrows(NotFoundException.class,
() -> resolver.resolve(new String[]{"git", "vogons/repo/space/X/something/else"}));
}
}