feat: GitLab support nested repositories (#467)
* feat: GitLab support nested repositories Signed-off-by: Anatolii Bazko <abazko@redhat.com> --------- Signed-off-by: Anatolii Bazko <abazko@redhat.com>pull/469/head
parent
5a04496ded
commit
76445656a9
|
|
@ -29,12 +29,7 @@ class GitlabAuthorizingFileContentProvider extends AuthorizingFileContentProvide
|
|||
@Override
|
||||
protected boolean isPublicRepository(GitlabUrl remoteFactoryUrl) {
|
||||
try {
|
||||
urlFetcher.fetch(
|
||||
remoteFactoryUrl.getHostName()
|
||||
+ '/'
|
||||
+ remoteFactoryUrl.getUsername()
|
||||
+ '/'
|
||||
+ remoteFactoryUrl.getProject());
|
||||
urlFetcher.fetch(remoteFactoryUrl.getHostName() + '/' + remoteFactoryUrl.getSubGroups());
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ import org.eclipse.che.api.factory.server.urlfactory.DefaultFactoryUrl;
|
|||
/**
|
||||
* Representation of a gitlab URL, allowing to get details from it.
|
||||
*
|
||||
* <p>like https://gitlab.com/<username>/<repository>
|
||||
* https://gitlab.com/<username>/<repository>/-/tree/<branch>
|
||||
* <p>like https://gitlab.com/path/to/repository or
|
||||
* https://gitlab.com/path/to/repository/-/tree/<branch>
|
||||
*
|
||||
* @author Max Shaposhnyk
|
||||
*/
|
||||
|
|
@ -37,14 +37,14 @@ public class GitlabUrl extends DefaultFactoryUrl {
|
|||
/** Hostname of the gitlab URL */
|
||||
private String hostName;
|
||||
|
||||
/** Username part of the gitlab URL */
|
||||
private String username;
|
||||
|
||||
/** Project part of the gitlab URL */
|
||||
private String project;
|
||||
|
||||
/** Repository part of the gitlab URL. */
|
||||
private String repository;
|
||||
/**
|
||||
* Incorporates subgroups in the project path of the gitlab URL. See details at:
|
||||
* https://docs.gitlab.com/ee/user/group/subgroups/
|
||||
*/
|
||||
private String subGroups;
|
||||
|
||||
/** Branch name */
|
||||
private String branch;
|
||||
|
|
@ -80,20 +80,6 @@ public class GitlabUrl extends DefaultFactoryUrl {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets username of this gitlab url
|
||||
*
|
||||
* @return the username part
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public GitlabUrl withUsername(String userName) {
|
||||
this.username = userName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets project of this bitbucket url
|
||||
*
|
||||
|
|
@ -103,22 +89,16 @@ public class GitlabUrl extends DefaultFactoryUrl {
|
|||
return this.project;
|
||||
}
|
||||
|
||||
public GitlabUrl withProject(String project) {
|
||||
this.project = project;
|
||||
return this;
|
||||
public String getSubGroups() {
|
||||
return subGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets repository of this gitlab url
|
||||
*
|
||||
* @return the repository part
|
||||
*/
|
||||
public String getRepository() {
|
||||
return this.repository;
|
||||
}
|
||||
protected GitlabUrl withSubGroups(String subGroups) {
|
||||
this.subGroups = subGroups;
|
||||
|
||||
protected GitlabUrl withRepository(String repository) {
|
||||
this.repository = repository;
|
||||
String[] subGroupsItems = subGroups.split("/");
|
||||
this.project =
|
||||
subGroupsItems[subGroupsItems.length - 1]; // project (repository) name is the last item
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +184,7 @@ public class GitlabUrl extends DefaultFactoryUrl {
|
|||
.add(hostName)
|
||||
.add("api/v4/projects")
|
||||
// use URL-encoded path to the project as a selector instead of id
|
||||
.add(geProjectIdentifier())
|
||||
.add(encode(subGroups, Charsets.UTF_8))
|
||||
.add("repository")
|
||||
.add("files")
|
||||
.add(encode(fileName, Charsets.UTF_8))
|
||||
|
|
@ -217,22 +197,12 @@ public class GitlabUrl extends DefaultFactoryUrl {
|
|||
return resultUrl;
|
||||
}
|
||||
|
||||
private String geProjectIdentifier() {
|
||||
return repository != null
|
||||
? encode(username + "/" + project + "/" + repository, Charsets.UTF_8)
|
||||
: encode(username + "/" + project, Charsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides location to the repository part of the full gitlab URL.
|
||||
*
|
||||
* @return location of the repository.
|
||||
*/
|
||||
protected String repositoryLocation() {
|
||||
if (repository == null) {
|
||||
return hostName + "/" + this.username + "/" + this.project + ".git";
|
||||
} else {
|
||||
return hostName + "/" + this.username + "/" + this.project + "/" + repository + ".git";
|
||||
}
|
||||
return hostName + "/" + subGroups + ".git";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ package org.eclipse.che.api.factory.server.gitlab;
|
|||
import static java.lang.String.format;
|
||||
import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
|
||||
import static java.util.regex.Pattern.compile;
|
||||
import static org.eclipse.che.commons.lang.StringUtils.trimEnd;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
|
@ -33,7 +34,6 @@ import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException
|
|||
import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider;
|
||||
import org.eclipse.che.commons.annotation.Nullable;
|
||||
import org.eclipse.che.commons.env.EnvironmentContext;
|
||||
import org.eclipse.che.commons.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser of String Gitlab URLs and provide {@link GitlabUrl} objects.
|
||||
|
|
@ -46,10 +46,9 @@ public class GitlabUrlParser {
|
|||
private final PersonalAccessTokenManager personalAccessTokenManager;
|
||||
private static final List<String> gitlabUrlPatternTemplates =
|
||||
List.of(
|
||||
"^(?<host>%s)/(?<user>[^/]++)/(?<project>[^./]++).git",
|
||||
"^(?<host>%s)/(?<user>[^/]++)/(?<project>[^/]++)/(?<repository>[^.]++).git",
|
||||
"^(?<host>%s)/(?<user>[^/]++)/(?<project>[^/]++)(/)?(?<repository>[^/]++)?(/)?",
|
||||
"^(?<host>%s)/(?<user>[^/]++)/(?<project>[^/]++)(/)?(?<repository>[^/]++)?/-/tree/(?<branch>[^/]++)(/)?(?<subfolder>[^/]++)?");
|
||||
"^(?<host>%s)/(?<subgroups>([^/]++/?)+)/-/tree/(?<branch>[^/]++)(/)?(?<subfolder>[^/]++)?",
|
||||
"^(?<host>%s)/(?<subgroups>.*)"); // a wider one, should be the last in the
|
||||
// list
|
||||
private final List<Pattern> gitlabUrlPatterns = new ArrayList<>();
|
||||
private static final String OAUTH_PROVIDER_NAME = "gitlab";
|
||||
|
||||
|
|
@ -62,7 +61,7 @@ public class GitlabUrlParser {
|
|||
this.personalAccessTokenManager = personalAccessTokenManager;
|
||||
if (gitlabEndpoints != null) {
|
||||
for (String gitlabEndpoint : Splitter.on(",").split(gitlabEndpoints)) {
|
||||
String trimmedEndpoint = StringUtils.trimEnd(gitlabEndpoint, '/');
|
||||
String trimmedEndpoint = trimEnd(gitlabEndpoint, '/');
|
||||
for (String gitlabUrlPatternTemplate : gitlabUrlPatternTemplates) {
|
||||
gitlabUrlPatterns.add(compile(format(gitlabUrlPatternTemplate, trimmedEndpoint)));
|
||||
}
|
||||
|
|
@ -163,16 +162,13 @@ public class GitlabUrlParser {
|
|||
|
||||
private GitlabUrl parse(Matcher matcher) {
|
||||
String host = matcher.group("host");
|
||||
String userName = matcher.group("user");
|
||||
String project = matcher.group("project");
|
||||
String repository = null;
|
||||
String subGroups = trimEnd(matcher.group("subgroups"), '/');
|
||||
if (subGroups.endsWith(".git")) {
|
||||
subGroups = subGroups.substring(0, subGroups.length() - 4);
|
||||
}
|
||||
|
||||
String branch = null;
|
||||
String subfolder = null;
|
||||
try {
|
||||
repository = matcher.group("repository");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// ok no such group
|
||||
}
|
||||
try {
|
||||
branch = matcher.group("branch");
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
|
@ -186,9 +182,7 @@ public class GitlabUrlParser {
|
|||
|
||||
return new GitlabUrl()
|
||||
.withHostName(host)
|
||||
.withUsername(userName)
|
||||
.withProject(project)
|
||||
.withRepository(repository)
|
||||
.withSubGroups(subGroups)
|
||||
.withBranch(branch)
|
||||
.withSubfolder(subfolder)
|
||||
.withDevfileFilenames(devfileFilenamesProvider.getConfiguredDevfileFilenames());
|
||||
|
|
|
|||
|
|
@ -33,10 +33,7 @@ public class GitlabAuthorizingFileContentProviderTest {
|
|||
public void shouldExpandRelativePaths() throws Exception {
|
||||
URLFetcher urlFetcher = Mockito.mock(URLFetcher.class);
|
||||
GitlabUrl gitlabUrl =
|
||||
new GitlabUrl()
|
||||
.withHostName("https://gitlab.net")
|
||||
.withUsername("eclipse")
|
||||
.withProject("che");
|
||||
new GitlabUrl().withHostName("https://gitlab.net").withSubGroups("eclipse/che");
|
||||
FileContentProvider fileContentProvider =
|
||||
new GitlabAuthorizingFileContentProvider(gitlabUrl, urlFetcher, personalAccessTokenManager);
|
||||
var personalAccessToken = new PersonalAccessToken("foo", "che", "my-token");
|
||||
|
|
@ -52,8 +49,7 @@ public class GitlabAuthorizingFileContentProviderTest {
|
|||
@Test
|
||||
public void shouldPreserveAbsolutePaths() throws Exception {
|
||||
URLFetcher urlFetcher = Mockito.mock(URLFetcher.class);
|
||||
GitlabUrl gitlabUrl =
|
||||
new GitlabUrl().withHostName("gitlab.net").withUsername("eclipse").withProject("che");
|
||||
GitlabUrl gitlabUrl = new GitlabUrl().withHostName("gitlab.net").withSubGroups("eclipse/che");
|
||||
FileContentProvider fileContentProvider =
|
||||
new GitlabAuthorizingFileContentProvider(gitlabUrl, urlFetcher, personalAccessTokenManager);
|
||||
String url =
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public class GitlabFactoryParametersResolverTest {
|
|||
// when
|
||||
FactoryDto factory = (FactoryDto) gitlabFactoryParametersResolver.createFactory(params);
|
||||
// then
|
||||
verify(urlFactoryBuilder).buildDefaultDevfile(eq("proj"));
|
||||
verify(urlFactoryBuilder).buildDefaultDevfile(eq("repo"));
|
||||
assertEquals(factory, computedFactory);
|
||||
SourceDto source = factory.getDevfile().getProjects().get(0).getSource();
|
||||
assertEquals(source.getLocation(), gitlabUrl);
|
||||
|
|
|
|||
|
|
@ -72,12 +72,11 @@ public class GitlabUrlParserTest {
|
|||
/** Compare parsing */
|
||||
@Test(dataProvider = "parsing")
|
||||
public void checkParsing(
|
||||
String url, String user, String project, String repository, String branch, String subfolder) {
|
||||
String url, String project, String subGroups, String branch, String subfolder) {
|
||||
GitlabUrl gitlabUrl = gitlabUrlParser.parse(url);
|
||||
|
||||
assertEquals(gitlabUrl.getUsername(), user);
|
||||
assertEquals(gitlabUrl.getProject(), project);
|
||||
assertEquals(gitlabUrl.getRepository(), repository);
|
||||
assertEquals(gitlabUrl.getSubGroups(), subGroups);
|
||||
assertEquals(gitlabUrl.getBranch(), branch);
|
||||
assertEquals(gitlabUrl.getSubfolder(), subfolder);
|
||||
}
|
||||
|
|
@ -124,16 +123,31 @@ public class GitlabUrlParserTest {
|
|||
@DataProvider(name = "parsing")
|
||||
public Object[][] expectedParsing() {
|
||||
return new Object[][] {
|
||||
{"https://gitlab1.com/user/project1.git", "user", "project1", null, null, null},
|
||||
{"https://gitlab1.com/user/project/test1.git", "user", "project", "test1", null, null},
|
||||
{"https://gitlab1.com/user/project/", "user", "project", null, null, null},
|
||||
{"https://gitlab1.com/user/project/repo/", "user", "project", "repo", null, null},
|
||||
{"https://gitlab1.com/user/project/-/tree/master/", "user", "project", null, "master", null},
|
||||
{"https://gitlab1.com/user/project1.git", "project1", "user/project1", null, null},
|
||||
{"https://gitlab1.com/user/project/test1.git", "test1", "user/project/test1", null, null},
|
||||
{
|
||||
"https://gitlab1.com/user/project/group1/group2/test1.git",
|
||||
"test1",
|
||||
"user/project/group1/group2/test1",
|
||||
null,
|
||||
null
|
||||
},
|
||||
{"https://gitlab1.com/user/project/", "project", "user/project", null, null},
|
||||
{"https://gitlab1.com/user/project/repo/", "repo", "user/project/repo", null, null},
|
||||
{
|
||||
"https://gitlab1.com/user/project/-/tree/master/", "project", "user/project", "master", null
|
||||
},
|
||||
{
|
||||
"https://gitlab1.com/user/project/repo/-/tree/foo/subfolder",
|
||||
"user",
|
||||
"project",
|
||||
"repo",
|
||||
"user/project/repo",
|
||||
"foo",
|
||||
"subfolder"
|
||||
},
|
||||
{
|
||||
"https://gitlab1.com/user/project/group1/group2/repo/-/tree/foo/subfolder",
|
||||
"repo",
|
||||
"user/project/group1/group2/repo",
|
||||
"foo",
|
||||
"subfolder"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue