diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolver.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolver.java index dd4e158fe6..ef15064e3f 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolver.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerScmFileResolver.java @@ -11,7 +11,7 @@ */ package org.eclipse.che.api.factory.server.bitbucket; -import static org.eclipse.che.api.factory.server.DevfileToApiExceptionMapper.toApiException; +import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException; import java.io.IOException; import javax.inject.Inject; diff --git a/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketScmFileResolver.java b/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketScmFileResolver.java index 08addec80c..bd5abd52d8 100644 --- a/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketScmFileResolver.java +++ b/wsmaster/che-core-api-factory-bitbucket/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketScmFileResolver.java @@ -11,7 +11,7 @@ */ package org.eclipse.che.api.factory.server.bitbucket; -import static org.eclipse.che.api.factory.server.DevfileToApiExceptionMapper.toApiException; +import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException; import jakarta.validation.constraints.NotNull; import java.io.IOException; diff --git a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubApiClient.java b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubApiClient.java index f52a751ce2..03e08988a5 100644 --- a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubApiClient.java +++ b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubApiClient.java @@ -116,6 +116,25 @@ public class GithubApiClient { }); } + public GithubPullRequest getPullRequest( + String id, String username, String repoName, String authenticationToken) + throws ScmItemNotFoundException, ScmCommunicationException, ScmBadRequestException { + final URI uri = + apiServerUrl.resolve(String.format("/repos/%1s/%2s/pulls/%3s", username, repoName, id)); + HttpRequest request = buildGithubApiRequest(uri, authenticationToken); + LOG.trace("executeRequest={}", request); + return executeRequest( + httpClient, + request, + response -> { + try { + return OBJECT_MAPPER.readValue(response.body(), GithubPullRequest.class); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + /** * Returns the scopes of the OAuth token. * diff --git a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolver.java b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolver.java index ed27edaf9f..0401e63ac9 100644 --- a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolver.java +++ b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolver.java @@ -99,11 +99,17 @@ public class GithubFactoryParametersResolver extends DefaultFactoryParameterReso @Override public FactoryMetaDto createFactory(@NotNull final Map factoryParameters) throws ApiException { - // no need to check null value of url parameter as accept() method has performed the check - final GithubUrl githubUrl = githubUrlParser.parse(factoryParameters.get(URL_PARAMETER_NAME)); boolean skipAuthentication = factoryParameters.get(ERROR_QUERY_NAME) != null && factoryParameters.get(ERROR_QUERY_NAME).equals("access_denied"); + // no need to check null value of url parameter as accept() method has performed the check + final GithubUrl githubUrl; + if (skipAuthentication) { + githubUrl = + githubUrlParser.parseWithoutAuthentication(factoryParameters.get(URL_PARAMETER_NAME)); + } else { + githubUrl = githubUrlParser.parse(factoryParameters.get(URL_PARAMETER_NAME)); + } // create factory from the following location if location exists, else create default factory return urlFactoryBuilder diff --git a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubPullRequest.java b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubPullRequest.java new file mode 100644 index 0000000000..de90c0a73d --- /dev/null +++ b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubPullRequest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012-2022 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/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.che.api.factory.server.github; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +class GithubRepo { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} + +@JsonIgnoreProperties(ignoreUnknown = true) +class GithubHead { + private String ref; + private GithubUser user; + private GithubRepo repo; + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public GithubUser getUser() { + return user; + } + + public void setUser(GithubUser user) { + this.user = user; + } + + public GithubRepo getRepo() { + return repo; + } + + public void setRepo(GithubRepo repo) { + this.repo = repo; + } +} + +@JsonIgnoreProperties(ignoreUnknown = true) +public class GithubPullRequest { + private String state; + private GithubHead head; + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public GithubHead getHead() { + return head; + } + + public void setHead(GithubHead head) { + this.head = head; + } +} diff --git a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolver.java b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolver.java index 5a6bdf2364..fe52583d68 100644 --- a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolver.java +++ b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolver.java @@ -11,7 +11,7 @@ */ package org.eclipse.che.api.factory.server.github; -import static org.eclipse.che.api.factory.server.DevfileToApiExceptionMapper.toApiException; +import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException; import jakarta.validation.constraints.NotNull; import java.io.IOException; diff --git a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubURLParser.java b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubURLParser.java index 41fd74ed40..f768db5136 100644 --- a/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubURLParser.java +++ b/wsmaster/che-core-api-factory-github/src/main/java/org/eclipse/che/api/factory/server/github/GithubURLParser.java @@ -11,13 +11,29 @@ */ package org.eclipse.che.api.factory.server.github; +import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException; + import jakarta.validation.constraints.NotNull; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; import javax.inject.Singleton; +import org.eclipse.che.api.core.ApiException; +import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; +import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; +import org.eclipse.che.api.factory.server.scm.exception.ScmBadRequestException; +import org.eclipse.che.api.factory.server.scm.exception.ScmCommunicationException; +import org.eclipse.che.api.factory.server.scm.exception.ScmConfigurationPersistenceException; +import org.eclipse.che.api.factory.server.scm.exception.ScmItemNotFoundException; +import org.eclipse.che.api.factory.server.scm.exception.ScmUnauthorizedException; +import org.eclipse.che.api.factory.server.scm.exception.UnknownScmProviderException; +import org.eclipse.che.api.factory.server.scm.exception.UnsatisfiedScmPreconditionException; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; -import org.eclipse.che.api.workspace.server.devfile.URLFetcher; +import org.eclipse.che.commons.env.EnvironmentContext; +import org.eclipse.che.commons.subject.Subject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Parser of String Github URLs and provide {@link GithubUrl} objects. @@ -27,15 +43,19 @@ import org.eclipse.che.api.workspace.server.devfile.URLFetcher; @Singleton public class GithubURLParser { - /** Fetcher to grab PR data */ - private final URLFetcher urlFetcher; - + private static final Logger LOG = LoggerFactory.getLogger(GithubURLParser.class); + private final PersonalAccessTokenManager tokenManager; private final DevfileFilenamesProvider devfileFilenamesProvider; + private final GithubApiClient apiClient; @Inject - public GithubURLParser(URLFetcher urlFetcher, DevfileFilenamesProvider devfileFilenamesProvider) { - this.urlFetcher = urlFetcher; + public GithubURLParser( + PersonalAccessTokenManager tokenManager, + DevfileFilenamesProvider devfileFilenamesProvider, + GithubApiClient apiClient) { + this.tokenManager = tokenManager; this.devfileFilenamesProvider = devfileFilenamesProvider; + this.apiClient = apiClient; } /** @@ -46,17 +66,19 @@ public class GithubURLParser { Pattern.compile( "^(?:http)(?:s)?(?:\\:\\/\\/)github.com/(?[^/]++)/(?[^/]++)((/)|(?:/tree/(?[^/]++)(?:/(?.*))?)|(/pull/(?[^/]++)))?$"); - /** Regexp to find repository and branch name from PR link */ - protected static final Pattern PR_DATA_PATTERN = - Pattern.compile( - ".*class=\"State[\\s]State--(?closed|open|merged).*[^\\\\/]+)\\/(?[^\\:]+):(?[^\\\"]+).*", - Pattern.DOTALL); - public boolean isValid(@NotNull String url) { return GITHUB_PATTERN.matcher(url).matches(); } - public GithubUrl parse(String url) { + public GithubUrl parseWithoutAuthentication(String url) throws ApiException { + return parse(url, false); + } + + public GithubUrl parse(String url) throws ApiException { + return parse(url, true); + } + + private GithubUrl parse(String url, boolean authenticationRequired) throws ApiException { // Apply github url to the regexp Matcher matcher = GITHUB_PATTERN.matcher(url); if (!matcher.matches()) { @@ -75,25 +97,42 @@ public class GithubURLParser { String pullRequestId = matcher.group("pullRequestId"); if (pullRequestId != null) { - // there is a Pull Request ID, analyze content to extract repository and branch to use - String prData = this.urlFetcher.fetchSafely(url); - Matcher prMatcher = PR_DATA_PATTERN.matcher(prData); - if (prMatcher.matches()) { - String prState = prMatcher.group("prState"); - if (!"open".equalsIgnoreCase(prState)) { - throw new IllegalArgumentException( - String.format( - "The given Pull Request url %s is not Opened, (found %s), thus it can't be opened as branch may have been removed.", - url, prState)); + try { + String githubEndpoint = "https://github.com"; + Subject subject = EnvironmentContext.getCurrent().getSubject(); + PersonalAccessToken personalAccessToken = null; + Optional tokenOptional = tokenManager.get(subject, githubEndpoint); + if (tokenOptional.isPresent()) { + personalAccessToken = tokenOptional.get(); + } else if (authenticationRequired) { + personalAccessToken = tokenManager.fetchAndSave(subject, githubEndpoint); } - repoUser = prMatcher.group("prRepoUser"); - repoName = prMatcher.group("prRepoName"); - branchName = prMatcher.group("prBranch"); - } else { - throw new IllegalArgumentException( - String.format( - "The given Pull Request github url %s is not a valid Pull Request URL github url. Unable to extract the data", - url)); + if (personalAccessToken != null) { + GithubPullRequest pullRequest = + this.apiClient.getPullRequest( + pullRequestId, repoUser, repoName, personalAccessToken.getToken()); + String prState = pullRequest.getState(); + if (!"open".equalsIgnoreCase(prState)) { + throw new IllegalArgumentException( + String.format( + "The given Pull Request url %s is not Opened, (found %s), thus it can't be opened as branch may have been removed.", + url, prState)); + } + GithubHead pullRequestHead = pullRequest.getHead(); + repoUser = pullRequestHead.getUser().getLogin(); + repoName = pullRequestHead.getRepo().getName(); + branchName = pullRequestHead.getRef(); + } + } catch (ScmUnauthorizedException e) { + throw toApiException(e); + } catch (ScmCommunicationException + | UnsatisfiedScmPreconditionException + | ScmConfigurationPersistenceException e) { + LOG.error("Failed to authenticate to GitHub", e); + } catch (ScmItemNotFoundException | ScmBadRequestException e) { + LOG.error("Failed retrieve GitHub Pull Request", e); + } catch (UnknownScmProviderException e) { + LOG.warn(e.getMessage()); } } diff --git a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolverTest.java index 8b22271456..286da3e590 100644 --- a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolverTest.java +++ b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubFactoryParametersResolverTest.java @@ -21,6 +21,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -100,7 +101,9 @@ public class GithubFactoryParametersResolverTest { @BeforeMethod protected void init() { - githubUrlParser = new GithubURLParser(urlFetcher, devfileFilenamesProvider); + githubUrlParser = + new GithubURLParser( + personalAccessTokenManager, devfileFilenamesProvider, mock(GithubApiClient.class)); assertNotNull(this.githubUrlParser); githubFactoryParametersResolver = new GithubFactoryParametersResolver( diff --git a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolverTest.java b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolverTest.java index 60f43b14cb..b7e8017396 100644 --- a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolverTest.java +++ b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubScmFileResolverTest.java @@ -13,6 +13,7 @@ package org.eclipse.che.api.factory.server.github; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.*; @@ -43,7 +44,9 @@ public class GithubScmFileResolverTest { @BeforeMethod protected void init() { - githubURLParser = new GithubURLParser(urlFetcher, devfileFilenamesProvider); + githubURLParser = + new GithubURLParser( + personalAccessTokenManager, devfileFilenamesProvider, mock(GithubApiClient.class)); assertNotNull(this.githubURLParser); githubScmFileResolver = new GithubScmFileResolver( 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 ada9f50af8..ca34afc520 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 @@ -12,17 +12,23 @@ package org.eclipse.che.api.factory.server.github; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.lenient; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import java.util.Optional; +import org.eclipse.che.api.core.ApiException; +import org.eclipse.che.api.factory.server.scm.PersonalAccessToken; +import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; -import org.eclipse.che.api.workspace.server.devfile.URLFetcher; +import org.eclipse.che.commons.subject.Subject; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; @@ -35,23 +41,23 @@ import org.testng.annotations.Test; @Listeners(MockitoTestNGListener.class) public class GithubURLParserTest { - @Mock private URLFetcher urlFetcher; @Mock private DevfileFilenamesProvider devfileFilenamesProvider; /** Instance of component that will be tested. */ @InjectMocks private GithubURLParser githubUrlParser; + @InjectMocks + private PersonalAccessTokenManager personalAccessTokenManager = + mock(PersonalAccessTokenManager.class); + + @InjectMocks private GithubApiClient githubApiClient = mock(GithubApiClient.class); + /** Check invalid url (not a github one) */ @Test(expectedExceptions = IllegalArgumentException.class) - public void invalidUrl() { + public void invalidUrl() throws ApiException { githubUrlParser.parse("http://www.eclipse.org"); } - @BeforeMethod - public void init() { - lenient().when(urlFetcher.fetchSafely(any(String.class))).thenReturn(""); - } - /** Check URLs are valid with regexp */ @Test(dataProvider = "UrlsProvider") public void checkRegexp(String url) { @@ -61,7 +67,8 @@ public class GithubURLParserTest { /** Compare parsing */ @Test(dataProvider = "parsing") public void checkParsing( - String url, String username, String repository, String branch, String subfolder) { + String url, String username, String repository, String branch, String subfolder) + throws ApiException { GithubUrl githubUrl = githubUrlParser.parse(url); assertEquals(githubUrl.getUsername(), username); @@ -72,7 +79,8 @@ public class GithubURLParserTest { /** Compare parsing */ @Test(dataProvider = "parsingBadRepository") - public void checkParsingBadRepositoryDoNotModifiesInitialInput(String url, String repository) { + public void checkParsingBadRepositoryDoNotModifiesInitialInput(String url, String repository) + throws ApiException { GithubUrl githubUrl = githubUrlParser.parse(url); assertEquals(githubUrl.getRepository(), repository); } @@ -144,39 +152,9 @@ public class GithubURLParserTest { /** Check Pull Request with data inside the repository */ @Test - public void checkPullRequestFromRepository() { + public void checkPullRequestFromRepository() throws ApiException { String url = "https://github.com/eclipse/che/pull/21276"; - when(urlFetcher.fetchSafely(url)) - .thenReturn( - " \n" - + "
\n" - + "
\n" - + " \n" - + " Open\n" - + "\n" - + "
\n" - + "\n" - + "\n" - + "\n" - + "
\n" - + " che-bot\n" - + "\n" - + " wants to merge\n" - + " 1\n" - + " commit into\n" - + "\n" - + "\n" - + "\n" - + " main\n" - + "\n" - + "
\n" - + "
\n" - + " \n" - + " base:\n" - + " main\n" - + " \n" - + " "); GithubUrl githubUrl = githubUrlParser.parse(url); assertEquals(githubUrl.getUsername(), "eclipse"); @@ -186,38 +164,26 @@ public class GithubURLParserTest { /** Check Pull Request with data outside the repository (fork) */ @Test - public void checkPullRequestFromForkedRepository() { + public void checkPullRequestFromForkedRepository() throws Exception { + PersonalAccessToken personalAccessToken = mock(PersonalAccessToken.class); + GithubPullRequest githubPullRequest = mock(GithubPullRequest.class); + GithubHead githubHead = mock(GithubHead.class); + GithubRepo githubRepo = mock(GithubRepo.class); + GithubUser githubUser = mock(GithubUser.class); + when(githubUser.getLogin()).thenReturn("eclipse"); + when(githubRepo.getName()).thenReturn("che"); + when(githubHead.getRef()).thenReturn("main"); + when(githubHead.getRepo()).thenReturn(githubRepo); + when(githubHead.getUser()).thenReturn(githubUser); + when(githubPullRequest.getState()).thenReturn("open"); + when(githubPullRequest.getHead()).thenReturn(githubHead); + when(personalAccessToken.getToken()).thenReturn("token"); + when(personalAccessTokenManager.get(any(Subject.class), anyString())) + .thenReturn(Optional.of(personalAccessToken)); + when(githubApiClient.getPullRequest(anyString(), anyString(), anyString(), anyString())) + .thenReturn(githubPullRequest); String url = "https://github.com/eclipse/che/pull/20189"; - when(urlFetcher.fetchSafely(url)) - .thenReturn( - "
\n" - + "
\n" - + " \n" - + " Open\n" - + "\n" - + "
\n" - + "\n" - + "\n" - + "\n" - + "
\n" - + " apupier\n" - + "\n" - + " wants to merge\n" - + " 1\n" - + " commit into\n" - + "\n" - + "\n" - + "\n" - + " eclipse:main\n" - + "\n" - + "
\n" - + "
\n" - + " \n" - + " base:\n" - + " main\n" - + " \n" - + " "); GithubUrl githubUrl = githubUrlParser.parse(url); assertEquals(githubUrl.getUsername(), "eclipse"); @@ -225,98 +191,31 @@ public class GithubURLParserTest { assertEquals(githubUrl.getBranch(), "main"); } + @Test + public void checkPullRequestFromForkedRepositoryWithoutAuthentication() throws Exception { + String url = "https://github.com/eclipse/che/pull/21276"; + GithubUrl githubUrl = githubUrlParser.parseWithoutAuthentication(url); + + assertEquals(githubUrl.getUsername(), "eclipse"); + assertEquals(githubUrl.getRepository(), "che"); + verify(personalAccessTokenManager, never()).fetchAndSave(any(Subject.class), anyString()); + } + /** Check Pull Request is failing with Merged state */ @Test( expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*found merged.*") - public void checkPullRequestMergedState() { + public void checkPullRequestMergedState() throws Exception { + PersonalAccessToken personalAccessToken = mock(PersonalAccessToken.class); + GithubPullRequest githubPullRequest = mock(GithubPullRequest.class); + when(githubPullRequest.getState()).thenReturn("merged"); + when(personalAccessToken.getToken()).thenReturn("token"); + when(personalAccessTokenManager.get(any(Subject.class), anyString())) + .thenReturn(Optional.of(personalAccessToken)); + when(githubApiClient.getPullRequest(anyString(), anyString(), anyString(), anyString())) + .thenReturn(githubPullRequest); String url = "https://github.com/eclipse/che/pull/11103"; - when(urlFetcher.fetchSafely(url)) - .thenReturn( - "
\n" - + "
\n" - + " \n" - + " Merged\n" - + "\n" - + "
\n" - + "\n" - + "\n" - + "\n" - + "
\n" - + " benoitf\n" - + " merged 1 commit into\n" - + "\n" - + "\n" - + "\n" - + " master\n" - + "\n" - + "from\n" - + "\n" - + "cleanup-e2e-theia\n" - + " \n" - + " \n" - + "\n" - + " \n" - + " \n" - + "\n" - + "\n" - + "\n" - + "\n" - + " Sep 7, 2018\n" - + "\n" - + "
\n" - + "
\n" - + ""); - githubUrlParser.parse(url); - } - - /** Check Pull Request is failing with Closed state */ - @Test( - expectedExceptions = IllegalArgumentException.class, - expectedExceptionsMessageRegExp = ".*found closed.*") - public void checkPullRequestClosedState() { - - String url = "https://github.com/eclipse/che/pull/20754"; - when(urlFetcher.fetchSafely(url)) - .thenReturn( - "
\n" - + "
\n" - + "
\n" - + " \n" - + " Closed\n" - + "\n" - + "
\n" - + "\n" - + "\n" - + "\n" - + "
\n" - + " Ohrimenko1988\n" - + "\n" - + " wants to merge\n" - + " 10\n" - + " commits into\n" - + "\n" - + "\n" - + "\n" - + " eclipse:7.38.x\n" - + "\n" - + "from\n" - + "\n" - + "Ohrimenko1988:iokhrime-chromedriver-7.38.x\n" - + " \n" - + " \n" - + "\n" - + " \n" - + " \n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "
\n" - + "
\n" - + ""); githubUrlParser.parse(url); } } diff --git a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubUrlTest.java b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubUrlTest.java index 52056f8708..8c329f8ccc 100644 --- a/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubUrlTest.java +++ b/wsmaster/che-core-api-factory-github/src/test/java/org/eclipse/che/api/factory/server/github/GithubUrlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -18,6 +18,7 @@ import static org.testng.Assert.assertNotNull; import java.util.Arrays; import java.util.Iterator; +import org.eclipse.che.api.core.ApiException; import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl.DevfileLocation; import org.mockito.InjectMocks; @@ -45,7 +46,7 @@ public class GithubUrlTest { /** Setup objects/ */ @BeforeMethod - protected void init() { + protected void init() throws ApiException { when(devfileFilenamesProvider.getConfiguredDevfileFilenames()) .thenReturn(Arrays.asList("devfile.yaml", "foo.bar")); this.githubUrl = this.githubUrlParser.parse("https://github.com/eclipse/che"); diff --git a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolver.java b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolver.java index e4439c7a6e..bc187a9a64 100644 --- a/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolver.java +++ b/wsmaster/che-core-api-factory-gitlab/src/main/java/org/eclipse/che/api/factory/server/gitlab/GitlabScmFileResolver.java @@ -11,7 +11,7 @@ */ package org.eclipse.che.api.factory.server.gitlab; -import static org.eclipse.che.api.factory.server.DevfileToApiExceptionMapper.toApiException; +import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException; import java.io.IOException; import javax.inject.Inject; diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/DevfileToApiExceptionMapper.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ApiExceptionMapper.java similarity index 67% rename from wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/DevfileToApiExceptionMapper.java rename to wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ApiExceptionMapper.java index 5b1fba8afc..2fd8431daa 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/DevfileToApiExceptionMapper.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/ApiExceptionMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -23,24 +23,34 @@ import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl.DevfileLoc import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException; /** - * Helps to convert {@link DevfileException}s with some specific causes into REST-friendly {@link + * Helps to convert {@link Exception}s with some specific causes into REST-friendly {@link * ApiException} */ -public class DevfileToApiExceptionMapper { +public class ApiExceptionMapper { public static ApiException toApiException(DevfileException devfileException) { - ApiException cause = getApiException(devfileException); - return (cause != null) - ? cause + ApiException apiException = getApiException(devfileException.getCause()); + return (apiException != null) + ? apiException : new BadRequestException( "Error occurred during file content retrieval." + "Cause: " + devfileException.getMessage()); } + public static ApiException toApiException(ScmUnauthorizedException scmUnauthorizedException) { + ApiException apiException = getApiException(scmUnauthorizedException); + return (apiException != null) + ? apiException + : new BadRequestException( + "Error occurred during SCM authorisation." + + "Cause: " + + scmUnauthorizedException.getMessage()); + } + public static ApiException toApiException( DevfileException devfileException, DevfileLocation location) { - ApiException cause = getApiException(devfileException); + ApiException cause = getApiException(devfileException.getCause()); return (cause != null) ? cause : new BadRequestException( @@ -50,10 +60,9 @@ public class DevfileToApiExceptionMapper { + devfileException.getMessage()); } - private static ApiException getApiException(DevfileException devfileException) { - Throwable cause = devfileException.getCause(); - if (cause instanceof ScmUnauthorizedException) { - ScmUnauthorizedException scmCause = (ScmUnauthorizedException) cause; + private static ApiException getApiException(Throwable throwable) { + if (throwable instanceof ScmUnauthorizedException) { + ScmUnauthorizedException scmCause = (ScmUnauthorizedException) throwable; return new UnauthorizedException( "SCM Authentication required", 401, @@ -61,14 +70,14 @@ public class DevfileToApiExceptionMapper { "oauth_version", scmCause.getOauthVersion(), "oauth_provider", scmCause.getOauthProvider(), "oauth_authentication_url", scmCause.getAuthenticateUrl())); - } else if (cause instanceof UnknownScmProviderException) { + } else if (throwable instanceof UnknownScmProviderException) { return new ServerException( "Provided location is unknown or misconfigured on the server side. Error message: " - + cause.getMessage()); - } else if (cause instanceof ScmCommunicationException) { + + throwable.getMessage()); + } else if (throwable instanceof ScmCommunicationException) { return new ServerException( "There is an error happened when communicate with SCM server. Error message: " - + cause.getMessage()); + + throwable.getMessage()); } return null; } diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java index b21ded50d3..f4a87e337b 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/urlfactory/URLFactoryBuilder.java @@ -12,7 +12,7 @@ package org.eclipse.che.api.factory.server.urlfactory; import static com.google.common.base.Strings.isNullOrEmpty; -import static org.eclipse.che.api.factory.server.DevfileToApiExceptionMapper.toApiException; +import static org.eclipse.che.api.factory.server.ApiExceptionMapper.toApiException; import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION; import static org.eclipse.che.api.workspace.server.devfile.Constants.CURRENT_API_VERSION; import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE; diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DevfileToApiExceptionMapperTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/ApiExceptionMapperTest.java similarity index 83% rename from wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DevfileToApiExceptionMapperTest.java rename to wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/ApiExceptionMapperTest.java index ab939dc418..2765dc2314 100644 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/DevfileToApiExceptionMapperTest.java +++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/ApiExceptionMapperTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2021 Red Hat, Inc. + * Copyright (c) 2012-2022 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/ @@ -25,7 +25,7 @@ import org.eclipse.che.api.factory.server.scm.exception.UnknownScmProviderExcept import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException; import org.testng.annotations.Test; -public class DevfileToApiExceptionMapperTest { +public class ApiExceptionMapperTest { @Test public void shouldReturnUnauthorizedExceptionIfCauseIsScmUnauthorized() { @@ -35,8 +35,7 @@ public class DevfileToApiExceptionMapperTest { "msg", "gitlab", "2.0", "http://gitlab.com/oauth/authenticate"); ApiException exception = - DevfileToApiExceptionMapper.toApiException( - new DevfileException("text", scmUnauthorizedException)); + ApiExceptionMapper.toApiException(new DevfileException("text", scmUnauthorizedException)); assertTrue(exception instanceof UnauthorizedException); assertEquals(((ExtendedError) exception.getServiceError()).getErrorCode(), 401); assertEquals(((ExtendedError) exception.getServiceError()).getAttributes().size(), 3); @@ -55,8 +54,7 @@ public class DevfileToApiExceptionMapperTest { UnknownScmProviderException scmProviderException = new UnknownScmProviderException("unknown", "http://gitlab.com/oauth/authenticate"); ApiException exception = - DevfileToApiExceptionMapper.toApiException( - new DevfileException("text", scmProviderException)); + ApiExceptionMapper.toApiException(new DevfileException("text", scmProviderException)); assertTrue(exception instanceof ServerException); } @@ -65,8 +63,7 @@ public class DevfileToApiExceptionMapperTest { ScmCommunicationException communicationException = new ScmCommunicationException("unknown"); ApiException exception = - DevfileToApiExceptionMapper.toApiException( - new DevfileException("text", communicationException)); + ApiExceptionMapper.toApiException(new DevfileException("text", communicationException)); assertTrue(exception instanceof ServerException); } @@ -75,8 +72,7 @@ public class DevfileToApiExceptionMapperTest { ScmItemNotFoundException itemNotFoundException = new ScmItemNotFoundException("unknown"); ApiException exception = - DevfileToApiExceptionMapper.toApiException( - new DevfileException("text", itemNotFoundException)); + ApiExceptionMapper.toApiException(new DevfileException("text", itemNotFoundException)); assertTrue(exception instanceof BadRequestException); } }