diff --git a/.ci/openshift-ci/test-gitlab-no-pat-oauth-flow-raw-devfile-url.sh b/.ci/openshift-ci/test-gitlab-no-pat-oauth-flow-raw-devfile-url.sh index 584cd11382f..12373cd7cbe 100644 --- a/.ci/openshift-ci/test-gitlab-no-pat-oauth-flow-raw-devfile-url.sh +++ b/.ci/openshift-ci/test-gitlab-no-pat-oauth-flow-raw-devfile-url.sh @@ -28,7 +28,7 @@ source "${SCRIPT_DIR}"/common.sh trap "catchFinish" EXIT SIGINT setupTestEnvironment ${OCP_NON_ADMIN_USER_NAME} -testFactoryResolverNoPatOAuthRaw ${PUBLIC_REPO_RAW_PATH_URL} ${PRIVATE_REPO_RAW_PATH_URL} +testFactoryResolverNoPatOAuth ${PUBLIC_REPO_RAW_PATH_URL} ${PRIVATE_REPO_RAW_PATH_URL} testCloneGitRepoNoProjectExists ${PUBLIC_REPO_WORKSPACE_NAME} ${PUBLIC_PROJECT_NAME} ${PUBLIC_REPO_RAW_PATH_URL} ${USER_CHE_NAMESPACE} deleteTestWorkspace ${PUBLIC_REPO_WORKSPACE_NAME} ${USER_CHE_NAMESPACE} diff --git a/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubURLParser.java b/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubURLParser.java index ac3b8b121da..f598da8d402 100644 --- a/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubURLParser.java +++ b/wsmaster/che-core-api-factory-github-common/src/main/java/org/eclipse/che/api/factory/server/github/AbstractGithubURLParser.java @@ -53,7 +53,7 @@ public abstract class AbstractGithubURLParser { private final Pattern githubPattern; private final String githubPatternTemplate = - "^%s/(?[^/]+)/(?[^/]++)((/)|(?:/tree/(?.++))|(/pull/(?\\d++)))?$"; + "%s/(?[^/]+)/(?[^/]++)((/)|(?:/((tree)|(blob))/(?.++))|(/pull/(?\\d++)))?$"; private final Pattern githubSSHPattern; @@ -207,7 +207,7 @@ private GithubUrl parse(String url, boolean authenticationRequired) throws ApiEx String branchName = null; String pullRequestId = null; if (isHTTPSUrl) { - branchName = matcher.group("branchName"); + branchName = getBranch(matcher.group("path")); pullRequestId = matcher.group("pullRequestId"); } @@ -254,6 +254,21 @@ private GithubUrl parse(String url, boolean authenticationRequired) throws ApiEx .withUrl(url); } + /* + * Get branch from the file path by extracting the segment before the devfile name. + * Example of a file path: "branch/devfile.yaml" => "branch" + */ + private String getBranch(String path) { + if (path != null && path.contains("/")) { + Optional devfileNameOptional = + devfileFilenamesProvider.getConfiguredDevfileFilenames().stream() + .filter(devfileName -> path.endsWith("/" + devfileName)) + .findAny(); + return devfileNameOptional.map(s -> path.substring(0, path.indexOf(s) - 1)).orElse(path); + } + return path; + } + private GithubPullRequest getPullRequest( String githubEndpoint, String pullRequestId, diff --git a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubURLParserTest.java b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubURLParserTest.java index e371e47da87..aadb784fc10 100644 --- a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubURLParserTest.java +++ b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubURLParserTest.java @@ -17,6 +17,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; +import static java.util.Arrays.asList; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -38,6 +39,7 @@ import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.eclipse.che.commons.subject.Subject; +import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -55,6 +57,7 @@ public class GithubURLParserTest { private GithubApiClient githubApiClient; private PersonalAccessTokenManager personalAccessTokenManager; + @Mock private DevfileFilenamesProvider devfileFilenamesProvider; /** Instance of component that will be tested. */ private GithubURLParser githubUrlParser; @@ -75,11 +78,7 @@ protected void start() throws ApiException { githubUrlParser = new GithubURLParser( - personalAccessTokenManager, - mock(DevfileFilenamesProvider.class), - githubApiClient, - null, - false); + personalAccessTokenManager, devfileFilenamesProvider, githubApiClient, null, false); } /** Check invalid url (not a GitHub one) */ @@ -96,13 +95,16 @@ public void checkRegexp(String url) { /** Compare parsing */ @Test(dataProvider = "parsing") - public void checkParsing(String url, String username, String repository, String branch) + public void checkParsing(String url, String username, String repository, String path) throws ApiException { + when(devfileFilenamesProvider.getConfiguredDevfileFilenames()) + .thenReturn(asList("devfile.yaml", ".devfile.yaml")); + GithubUrl githubUrl = githubUrlParser.parse(url); assertEquals(githubUrl.getUsername(), username); assertEquals(githubUrl.getRepository(), repository); - assertEquals(githubUrl.getBranch(), branch); + assertEquals(githubUrl.getBranch(), path); } /** Compare parsing */ @@ -160,12 +162,26 @@ public Object[][] expectedParsing() { {"https://github.com/eclipse/repositorygit", "eclipse", "repositorygit", null}, {"https://github.com/eclipse/che/tree/4.2.x", "eclipse", "che", "4.2.x"}, {"https://github.com/eclipse/che/tree/master", "eclipse", "che", "master"}, + {"https://github.com/eclipse/che/tree/master/", "eclipse", "che", "master"}, { "https://github.com/eclipse/che/tree/branch/with/slash", "eclipse", "che", "branch/with/slash" }, + {"https://github.com/eclipse/che/blob/branch/path/to/", "eclipse", "che", "branch/path/to"}, + { + "https://github.com/eclipse/che/blob/branch/path/to/devfile.yaml", + "eclipse", + "che", + "branch/path/to" + }, + { + "https://github.com/eclipse/che/blob/branch/path/to/.devfile.yaml", + "eclipse", + "che", + "branch/path/to" + }, {"git@github.com:eclipse/che", "eclipse", "che", null}, {"git@github.com:eclipse/che123", "eclipse", "che123", null}, {"git@github.com:eclipse/che.git", "eclipse", "che", null}, diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java index c26e81c490b..48eba353395 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2024 Red Hat, Inc. + * Copyright (c) 2012-2025 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -13,7 +13,7 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static java.lang.String.format; -import static org.eclipse.che.api.factory.server.FactoryResolverPriority.HIGHEST; +import static org.eclipse.che.api.factory.server.FactoryResolverPriority.LOWEST; import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME; import com.fasterxml.jackson.databind.JsonNode; @@ -128,6 +128,6 @@ public RemoteFactoryUrl parseFactoryUrl(String factoryUrl) throws ApiException { @Override public FactoryResolverPriority priority() { - return HIGHEST; + return LOWEST; } }