From bdb45ea62cfdd12437373f343d5492732280c5a7 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 20 Nov 2020 12:48:55 +0200 Subject: [PATCH 01/14] Add support for public bitbucket repositories --- assembly/assembly-wsmaster-war/pom.xml | 4 ++ .../che/api/deploy/WsMasterModule.java | 2 + .../webapp/WEB-INF/classes/che/che.properties | 3 + pom.xml | 5 ++ .../bitbucket/BitbucketURLParserTest.java | 72 +++++++++++++++++++ wsmaster/pom.xml | 1 + 6 files changed, 87 insertions(+) create mode 100644 wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java diff --git a/assembly/assembly-wsmaster-war/pom.xml b/assembly/assembly-wsmaster-war/pom.xml index 687775f619c..02590cc2b4e 100644 --- a/assembly/assembly-wsmaster-war/pom.xml +++ b/assembly/assembly-wsmaster-war/pom.xml @@ -131,6 +131,10 @@ org.eclipse.che.core che-core-api-factory + + org.eclipse.che.core + che-core-api-factory-bitbucket-server + org.eclipse.che.core che-core-api-factory-github diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index c5b6e0e4ad4..2f5b595b8cc 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -33,6 +33,7 @@ import org.eclipse.che.api.factory.server.FactoryCreateValidator; import org.eclipse.che.api.factory.server.FactoryEditValidator; import org.eclipse.che.api.factory.server.FactoryParametersResolver; +import org.eclipse.che.api.factory.server.bitbucket.BitbucketServerFactoryParametersResolver; import org.eclipse.che.api.factory.server.github.GithubFactoryParametersResolver; import org.eclipse.che.api.metrics.WsMasterMetricsModule; import org.eclipse.che.api.system.server.ServiceTermination; @@ -150,6 +151,7 @@ protected void configure() { Multibinder factoryParametersResolverMultibinder = Multibinder.newSetBinder(binder(), FactoryParametersResolver.class); factoryParametersResolverMultibinder.addBinding().to(GithubFactoryParametersResolver.class); + factoryParametersResolverMultibinder.addBinding().to(BitbucketServerFactoryParametersResolver.class); bind(org.eclipse.che.api.core.rest.ApiInfoService.class); bind(org.eclipse.che.api.ssh.server.SshService.class); diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 6b609f08fd0..405006d4e24 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -672,3 +672,6 @@ che.infra.kubernetes.async.storage.shutdown_timeout_min=120 # Defines the period with which the Asynchronous Storage Pod stopping ability will be performed (once in 30 minutes by default) che.infra.kubernetes.async.storage.shutdown_check_period_min=30 + + +bitbucket.endpoint=https://bitbucket-bitbucket.apps.cluster-afbc.afbc.example.opentlc.com \ No newline at end of file diff --git a/pom.xml b/pom.xml index 3815bbe8700..88de6ed9463 100644 --- a/pom.xml +++ b/pom.xml @@ -738,6 +738,11 @@ ${che.version} tests + + org.eclipse.che.core + che-core-api-factory-bitbucket-server + ${che.version} + org.eclipse.che.core che-core-api-factory-github diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java new file mode 100644 index 00000000000..c7fb70ac271 --- /dev/null +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012-2018 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.bitbucket; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; +import org.eclipse.che.api.workspace.server.devfile.URLFetcher; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +@Listeners(MockitoTestNGListener.class) +public class BitbucketURLParserTest { + + @Mock private URLFetcher urlFetcher; + @Mock private DevfileFilenamesProvider devfileFilenamesProvider; + + /** Instance of component that will be tested. */ + private BitbucketURLParser bitbucketURLParser; + + @BeforeClass + public void setUp() { + bitbucketURLParser = + new BitbucketURLParser("https://bitbucket.2mcl.com", urlFetcher, devfileFilenamesProvider); + } + + /** Check URLs are valid with regexp */ + @Test(dataProvider = "UrlsProvider") + public void checkRegexp(String url) { + assertTrue(bitbucketURLParser.isValid(url), "url " + url + " is invalid"); + } + + /** Compare parsing */ + @Test(dataProvider = "parsing") + public void checkParsing(String url, String project, String repository, String branch) { + BitbucketUrl bitbucketUrl = bitbucketURLParser.parse(url); + + assertEquals(bitbucketUrl.getProject(), project); + assertEquals(bitbucketUrl.getRepository(), repository); + assertEquals(bitbucketUrl.getBranch(), branch); + } + + @DataProvider(name = "UrlsProvider") + public Object[][] urls() { + return new Object[][] { + {"https://bitbucket.2mcl.com/scm/project/test1.git"}, + {"https://bitbucket.2mcl.com/scm/project/test1.git?at=branch"}, + }; + } + + @DataProvider(name = "parsing") + public Object[][] expectedParsing() { + return new Object[][] { + {"https://bitbucket.2mcl.com/scm/project/test1.git", "project", "test1", null}, + {"https://bitbucket.2mcl.com/scm/project/test1.git?at=branch", "project", "test1", "branch"} + }; + } +} diff --git a/wsmaster/pom.xml b/wsmaster/pom.xml index 6c7a796dc22..b966b402cf9 100644 --- a/wsmaster/pom.xml +++ b/wsmaster/pom.xml @@ -39,6 +39,7 @@ che-core-api-factory-shared che-core-api-factory che-core-api-factory-github + che-core-api-factory-bitbucket-server che-core-api-ssh che-core-api-ssh-shared wsmaster-local From 28aa456114e25c3bd8f9b4c5e80b13926b7ae411 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 20 Nov 2020 13:03:32 +0200 Subject: [PATCH 02/14] Add support for public bitbucket repositories --- .../pom.xml | 100 +++++++++ ...bucketServerFactoryParametersResolver.java | 127 ++++++++++++ .../server/bitbucket/BitbucketURLParser.java | 89 ++++++++ .../server/bitbucket/BitbucketUrl.java | 190 ++++++++++++++++++ 4 files changed, 506 insertions(+) create mode 100644 wsmaster/che-core-api-factory-bitbucket-server/pom.xml create mode 100644 wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java create mode 100644 wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java create mode 100644 wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java diff --git a/wsmaster/che-core-api-factory-bitbucket-server/pom.xml b/wsmaster/che-core-api-factory-bitbucket-server/pom.xml new file mode 100644 index 00000000000..7258eacc1b7 --- /dev/null +++ b/wsmaster/che-core-api-factory-bitbucket-server/pom.xml @@ -0,0 +1,100 @@ + + + + 4.0.0 + + che-master-parent + org.eclipse.che.core + 7.22.0-SNAPSHOT + + che-core-api-factory-bitbucket-server + jar + Che Core :: API :: Factory Resolver Bitbucket Server + + true + + + + com.google.guava + guava + + + javax.inject + javax.inject + + + javax.validation + validation-api + + + org.eclipse.che.core + che-core-api-core + + + org.eclipse.che.core + che-core-api-dto + + + org.eclipse.che.core + che-core-api-factory + + + org.eclipse.che.core + che-core-api-factory-shared + + + org.eclipse.che.core + che-core-api-workspace + + + org.eclipse.che.core + che-core-api-workspace-shared + + + org.eclipse.che.core + che-core-commons-annotations + + + ch.qos.logback + logback-classic + test + + + org.eclipse.che.core + che-core-commons-json + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-testng + test + + + org.slf4j + jcl-over-slf4j + test + + + org.testng + testng + test + + + diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java new file mode 100644 index 00000000000..23a483ce574 --- /dev/null +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2012-2018 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.bitbucket; + +import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION; +import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME; +import static org.eclipse.che.dto.server.DtoFactory.newDto; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.validation.constraints.NotNull; +import org.eclipse.che.api.core.BadRequestException; +import org.eclipse.che.api.factory.server.DefaultFactoryParameterResolver; +import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder; +import org.eclipse.che.api.factory.shared.dto.FactoryDto; +import org.eclipse.che.api.workspace.server.devfile.URLFetcher; +import org.eclipse.che.api.workspace.shared.dto.devfile.ProjectDto; +import org.eclipse.che.api.workspace.shared.dto.devfile.SourceDto; + +/** + * Provides Factory Parameters resolver for bitbucket repositories. + * + * @author Max Shaposhnyk + */ +@Singleton +public class BitbucketServerFactoryParametersResolver extends DefaultFactoryParameterResolver { + + /** Parser which will allow to check validity of URLs and create objects. */ + private BitbucketURLParser bitbucketURLParser; + + @Inject + public BitbucketServerFactoryParametersResolver( + URLFactoryBuilder urlFactoryBuilder, + URLFetcher urlFetcher, + BitbucketURLParser bitbucketURLParser) { + super(urlFactoryBuilder, urlFetcher); + this.bitbucketURLParser = bitbucketURLParser; + } + + /** + * Check if this resolver can be used with the given parameters. + * + * @param factoryParameters map of parameters dedicated to factories + * @return true if it will be accepted by the resolver implementation or false if it is not + * accepted + */ + @Override + public boolean accept(@NotNull final Map factoryParameters) { + return factoryParameters.containsKey(URL_PARAMETER_NAME) + && bitbucketURLParser.isValid(factoryParameters.get(URL_PARAMETER_NAME)); + } + + /** + * Create factory object based on provided parameters + * + * @param factoryParameters map containing factory data parameters provided through URL + * @throws BadRequestException when data are invalid + */ + @Override + public FactoryDto createFactory(@NotNull final Map factoryParameters) + throws BadRequestException { + + // no need to check null value of url parameter as accept() method has performed the check + final BitbucketUrl bitbucketUrl = + bitbucketURLParser.parse(factoryParameters.get(URL_PARAMETER_NAME)); + + // create factory from the following location if location exists, else create default factory + FactoryDto factory = + urlFactoryBuilder + .createFactoryFromDevfile( + bitbucketUrl, + fileName -> urlFetcher.fetch(bitbucketUrl.rawFileLocation(fileName)), + extractOverrideParams(factoryParameters)) + .orElseGet( + () -> + urlFactoryBuilder + .createFactoryFromJson(bitbucketUrl) + .orElseGet( + () -> + newDto(FactoryDto.class) + .withV(CURRENT_VERSION) + .withSource("repo"))); + + if (factory.getDevfile() == null) { + // initialize default devfile + factory.setDevfile(urlFactoryBuilder.buildDefaultDevfile(bitbucketUrl.getRepository())); + } + + List projects = factory.getDevfile().getProjects(); + // if no projects set, set the default one from Bitbucket url + if (projects.isEmpty()) { + factory + .getDevfile() + .setProjects( + Collections.singletonList( + newDto(ProjectDto.class) + .withSource( + newDto(SourceDto.class) + .withLocation(bitbucketUrl.repositoryLocation()) + .withType("git") + .withBranch(bitbucketUrl.getBranch())) + .withName(bitbucketUrl.getRepository()))); + } else { + // update existing project with same repository, set current branch if needed + projects.forEach( + project -> { + final String location = project.getSource().getLocation(); + if (location.equals(bitbucketUrl.repositoryLocation())) { + project.getSource().setBranch(bitbucketUrl.getBranch()); + } + }); + } + return factory; + } +} diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java new file mode 100644 index 00000000000..33c2d154f6d --- /dev/null +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2012-2018 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.bitbucket; + +import static java.lang.String.format; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import javax.validation.constraints.NotNull; +import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; +import org.eclipse.che.api.workspace.server.devfile.URLFetcher; +import org.eclipse.che.commons.annotation.Nullable; + +/** + * Parser of String Bitbucket URLs and provide {@link BitbucketUrl} objects. + * + * @author Max Shaposhnyk + */ +@Singleton +public class BitbucketURLParser { + + private final URLFetcher urlFetcher; + private final DevfileFilenamesProvider devfileFilenamesProvider; + private static final String bitbucketUrlPatternTemplate = + "^(?%s)/scm/(?[^/]++)/(?[^.]++).git(\\?at=)?(?[\\w\\d-_]*)"; + private Pattern bitbucketUrlPattern; + + @Inject + public BitbucketURLParser( + @Nullable @Named("bitbucket.endpoint") String bitbucketEndpoint, + URLFetcher urlFetcher, + DevfileFilenamesProvider devfileFilenamesProvider) { + if (bitbucketEndpoint != null) { + String trimmedEndpoint = + bitbucketEndpoint.endsWith("/") + ? bitbucketEndpoint.substring(0, bitbucketEndpoint.length() - 1) + : bitbucketEndpoint; + this.bitbucketUrlPattern = + Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint)); + } + this.urlFetcher = urlFetcher; + this.devfileFilenamesProvider = devfileFilenamesProvider; + } + + public boolean isValid(@NotNull String url) { + return bitbucketUrlPattern != null && bitbucketUrlPattern.matcher(url).matches(); + } + + /** + * Parses url-s like + * https://bitbucket.apps.cluster-cb82.cb82.example.opentlc.com/scm/test/test1.git into + * BitbucketUrl objects. + */ + public BitbucketUrl parse(String url) { + + Matcher matcher = bitbucketUrlPattern.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException( + String.format( + "The given github url %s is not a valid URL github url. It should start with https://github.com//", + url)); + } + + String host = matcher.group("host"); + String project = matcher.group("project"); + String repoName = matcher.group("repo"); + String branch = matcher.group("branch"); + + return new BitbucketUrl() + .withHostName(host) + .withProject(project) + .withRepository(repoName) + .withBranch(branch) + .withFactoryFilename(".factory.json") + .withDevfileFilenames(devfileFilenamesProvider.getConfiguredDevfileFilenames()); + } +} diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java new file mode 100644 index 00000000000..684f5d29244 --- /dev/null +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012-2018 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.bitbucket; + +import com.google.common.base.Strings; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.StringJoiner; +import java.util.stream.Collectors; +import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl; + +/** Representation of a bitbucket URL, allowing to get details from it. */ +public class BitbucketUrl implements RemoteFactoryUrl { + + /** Hostname of bitbucket URL */ + private String hostName; + + /** Project part of bitbucket URL */ + private String project; + + /** Repository part of the URL. */ + private String repository; + + /** Branch name */ + private String branch; + + /** Factory json filename */ + private String factoryFilename; + + /** Devfile filenames list */ + private final List devfileFilenames = new ArrayList<>(); + + /** + * Creation of this instance is made by the parser so user may not need to create a new instance + * directly + */ + protected BitbucketUrl() {} + + /** + * Gets hostname of this bitbucket url + * + * @return the project part + */ + public String getHostName() { + return this.hostName; + } + + public BitbucketUrl withHostName(String hostName) { + this.hostName = hostName; + return this; + } + + /** + * Gets project of this bitbucket url + * + * @return the project part + */ + public String getProject() { + return this.project; + } + + public BitbucketUrl withProject(String project) { + this.project = project; + return this; + } + + /** + * Gets repository of this bitbucket url + * + * @return the repository part + */ + public String getRepository() { + return this.repository; + } + + protected BitbucketUrl withRepository(String repository) { + this.repository = repository; + return this; + } + + protected BitbucketUrl withDevfileFilenames(List devfileFilenames) { + this.devfileFilenames.addAll(devfileFilenames); + return this; + } + + /** + * Gets factory file name of this bitbucket url + * + * @return the factory file name + */ + @Override + public String getFactoryFilename() { + return this.factoryFilename; + } + + protected BitbucketUrl withFactoryFilename(String factoryFilename) { + this.factoryFilename = factoryFilename; + return this; + } + + /** + * Gets branch of this bitbucket url + * + * @return the branch part + */ + public String getBranch() { + return this.branch; + } + + protected BitbucketUrl withBranch(String branch) { + if (!Strings.isNullOrEmpty(branch)) { + this.branch = branch; + } + return this; + } + + /** + * Provides location to raw content of the factory json file + * + * @return location of factory json file in a repository + */ + @Override + public String factoryFileLocation() { + return rawFileLocation(factoryFilename); + } + + /** + * Provides list of configured devfile filenames with locations + * + * @return list of devfile filenames and locations + */ + @Override + public List devfileFileLocations() { + return devfileFilenames.stream().map(this::createDevfileLocation).collect(Collectors.toList()); + } + + private DevfileLocation createDevfileLocation(String devfileFilename) { + return new DevfileLocation() { + @Override + public Optional filename() { + return Optional.of(devfileFilename); + } + + @Override + public String location() { + return rawFileLocation(devfileFilename); + } + }; + } + + /** + * Provides location to raw content of specified file + * + * @return location of specified file in a repository + */ + public String rawFileLocation(String fileName) { + StringJoiner joiner = + new StringJoiner("/") + .add(hostName) + .add("rest/api/latest/projects") + .add(project) + .add("repos") + .add(repository) + .add("raw") + .add(fileName); + if (branch != null) { + joiner.add("?at=" + branch); + } + return joiner.toString(); + } + + /** + * Provides location to the repository part of the full bitbucket URL. + * + * @return location of the repository. + */ + protected String repositoryLocation() { + return hostName + "/scm/" + this.project + "/" + this.repository + ".git"; + } +} From a54dfd64fc36aa53dadaf7783c68285aa0e121ce Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 20 Nov 2020 15:26:20 +0200 Subject: [PATCH 03/14] fixup property --- .../src/main/webapp/WEB-INF/classes/che/che.properties | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 405006d4e24..20919fd9d2e 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -673,5 +673,6 @@ che.infra.kubernetes.async.storage.shutdown_timeout_min=120 # Defines the period with which the Asynchronous Storage Pod stopping ability will be performed (once in 30 minutes by default) che.infra.kubernetes.async.storage.shutdown_check_period_min=30 - -bitbucket.endpoint=https://bitbucket-bitbucket.apps.cluster-afbc.afbc.example.opentlc.com \ No newline at end of file +# Bitbucket endpoint used for both factory and OAuth integrations. Should contain bitbucket server +# URL or NULL if no integration expected. +bitbucket.endpoint=NULL From a6d53539535536819f175d5b2f7bbd3c5b026645 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 23 Nov 2020 11:03:39 +0200 Subject: [PATCH 04/14] Minor fixups --- .../src/main/webapp/WEB-INF/classes/che/che.properties | 2 +- .../che/api/factory/server/bitbucket/BitbucketURLParser.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index 20919fd9d2e..1f744f3512b 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -675,4 +675,4 @@ che.infra.kubernetes.async.storage.shutdown_check_period_min=30 # Bitbucket endpoint used for both factory and OAuth integrations. Should contain bitbucket server # URL or NULL if no integration expected. -bitbucket.endpoint=NULL +bitbucket.server.endpoint=NULL diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 33c2d154f6d..fb540e5cf09 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -39,7 +39,7 @@ public class BitbucketURLParser { @Inject public BitbucketURLParser( - @Nullable @Named("bitbucket.endpoint") String bitbucketEndpoint, + @Nullable @Named("bitbucket.server.endpoint") String bitbucketEndpoint, URLFetcher urlFetcher, DevfileFilenamesProvider devfileFilenamesProvider) { if (bitbucketEndpoint != null) { @@ -69,7 +69,7 @@ public BitbucketUrl parse(String url) { if (!matcher.matches()) { throw new IllegalArgumentException( String.format( - "The given github url %s is not a valid URL github url. It should start with https://github.com//", + "The given url %s is not a valid Bitbucket server URL. Check either URL or server configuration.", url)); } From bb0bf640af76a94a9827965dfa48f6587a2593a7 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 23 Nov 2020 14:43:17 +0200 Subject: [PATCH 05/14] Add test class --- ...etServerFactoryParametersResolverTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java new file mode 100644 index 00000000000..a746931ec78 --- /dev/null +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2012-2018 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.bitbucket; + +import static java.util.Collections.singletonMap; +import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION; +import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME; +import static org.eclipse.che.api.workspace.server.devfile.Constants.CURRENT_API_VERSION; +import static org.eclipse.che.dto.server.DtoFactory.newDto; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import com.google.common.collect.ImmutableMap; +import java.util.Map; +import java.util.Optional; +import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider; +import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl; +import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder; +import org.eclipse.che.api.factory.shared.dto.FactoryDto; +import org.eclipse.che.api.workspace.server.devfile.URLFetcher; +import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto; +import org.eclipse.che.api.workspace.shared.dto.devfile.MetadataDto; +import org.eclipse.che.api.workspace.shared.dto.devfile.SourceDto; +import org.mockito.Mock; +import org.mockito.testng.MockitoTestNGListener; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; + +@Listeners(MockitoTestNGListener.class) +public class BitbucketServerFactoryParametersResolverTest { + + @Mock private URLFactoryBuilder urlFactoryBuilder; + + @Mock private URLFetcher urlFetcher; + + @Mock private DevfileFilenamesProvider devfileFilenamesProvider; + + BitbucketURLParser bitbucketURLParser; + + private BitbucketServerFactoryParametersResolver bitbucketServerFactoryParametersResolver; + + @BeforeMethod + protected void init() { + bitbucketURLParser = + new BitbucketURLParser("http://bitbucket.2mcl.com", urlFetcher, devfileFilenamesProvider); + assertNotNull(this.bitbucketURLParser); + bitbucketServerFactoryParametersResolver = + new BitbucketServerFactoryParametersResolver( + urlFactoryBuilder, urlFetcher, bitbucketURLParser); + assertNotNull(this.bitbucketServerFactoryParametersResolver); + } + + /** Check url which is not a bitbucket url can't be accepted by this resolver */ + @Test + public void checkInvalidAcceptUrl() { + Map parameters = singletonMap(URL_PARAMETER_NAME, "http://github.com"); + // shouldn't be accepted + assertFalse(bitbucketServerFactoryParametersResolver.accept(parameters)); + } + + /** Check bitbucket url will be be accepted by this resolver */ + @Test + public void checkValidAcceptUrl() { + Map parameters = + singletonMap(URL_PARAMETER_NAME, "http://bitbucket.2mcl.com/scm/test/repo.git"); + // should be accepted + assertTrue(bitbucketServerFactoryParametersResolver.accept(parameters)); + } + + @Test + public void shouldGenerateDevfileForFactoryWithNoDevfileOrJson() throws Exception { + + String bitbucketUrl = "http://bitbucket.2mcl.com/scm/test/repo.git"; + + FactoryDto computedFactory = generateDevfileFactory(); + + when(urlFactoryBuilder.buildDefaultDevfile(any())).thenReturn(computedFactory.getDevfile()); + + when(urlFactoryBuilder.createFactoryFromJson(any(RemoteFactoryUrl.class))) + .thenReturn(Optional.empty()); + when(urlFactoryBuilder.createFactoryFromDevfile(any(RemoteFactoryUrl.class), any(), anyMap())) + .thenReturn(Optional.empty()); + Map params = ImmutableMap.of(URL_PARAMETER_NAME, bitbucketUrl); + // when + FactoryDto factory = bitbucketServerFactoryParametersResolver.createFactory(params); + // then + verify(urlFactoryBuilder).buildDefaultDevfile(eq("repo")); + assertEquals(factory, computedFactory); + SourceDto source = factory.getDevfile().getProjects().get(0).getSource(); + assertEquals(source.getLocation(), bitbucketUrl); + assertNull(source.getBranch()); + } + + @Test + public void shouldSetDefaultProjectIntoDevfileIfNotSpecified() throws Exception { + + String bitbucketUrl = "http://bitbucket.2mcl.com/scm/test/repo.git?at=foobar"; + + FactoryDto computedFactory = generateDevfileFactory(); + + when(urlFactoryBuilder.createFactoryFromDevfile(any(RemoteFactoryUrl.class), any(), anyMap())) + .thenReturn(Optional.of(computedFactory)); + + Map params = ImmutableMap.of(URL_PARAMETER_NAME, bitbucketUrl); + // when + FactoryDto factory = bitbucketServerFactoryParametersResolver.createFactory(params); + // then + assertNotNull(factory.getDevfile()); + SourceDto source = factory.getDevfile().getProjects().get(0).getSource(); + assertEquals(source.getLocation(), "http://bitbucket.2mcl.com/scm/test/repo.git"); + assertEquals(source.getBranch(), "foobar"); + } + + private FactoryDto generateDevfileFactory() { + return newDto(FactoryDto.class) + .withV(CURRENT_VERSION) + .withSource("repo") + .withDevfile( + newDto(DevfileDto.class) + .withApiVersion(CURRENT_API_VERSION) + .withMetadata(newDto(MetadataDto.class).withName("che"))); + } +} From dbc0eb9d5deebd0a9f36baea7d9f7c07d482fe67 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 23 Nov 2020 18:28:15 +0200 Subject: [PATCH 06/14] Hardcode api version --- .../eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java index 684f5d29244..6c1ca1bbedd 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java @@ -167,7 +167,7 @@ public String rawFileLocation(String fileName) { StringJoiner joiner = new StringJoiner("/") .add(hostName) - .add("rest/api/latest/projects") + .add("rest/api/1.0/projects") .add(project) .add("repos") .add(repository) From 8ee556fe92df4feb971971f14fd14eaa0817e8b1 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 23 Nov 2020 18:43:25 +0200 Subject: [PATCH 07/14] Finbug issue --- wsmaster/che-core-api-factory-bitbucket-server/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/pom.xml b/wsmaster/che-core-api-factory-bitbucket-server/pom.xml index 7258eacc1b7..687b0eb2efa 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/pom.xml +++ b/wsmaster/che-core-api-factory-bitbucket-server/pom.xml @@ -23,7 +23,7 @@ jar Che Core :: API :: Factory Resolver Bitbucket Server - true + false From 4cf861f869762bbb51eda19524bc5ab038d4bee6 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 24 Nov 2020 17:18:08 +0200 Subject: [PATCH 08/14] Code fixups --- .../bitbucket/BitbucketServerFactoryParametersResolver.java | 2 +- .../api/factory/server/bitbucket/BitbucketURLParser.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java index 23a483ce574..001b6653c85 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java @@ -38,7 +38,7 @@ public class BitbucketServerFactoryParametersResolver extends DefaultFactoryParameterResolver { /** Parser which will allow to check validity of URLs and create objects. */ - private BitbucketURLParser bitbucketURLParser; + private final BitbucketURLParser bitbucketURLParser; @Inject public BitbucketServerFactoryParametersResolver( diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index fb540e5cf09..d4aa12ee3aa 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -65,6 +65,12 @@ public boolean isValid(@NotNull String url) { */ public BitbucketUrl parse(String url) { + if (bitbucketUrlPattern == null) { + throw new UnsupportedOperationException( + "The Bitbucket integration is not configured properly and cannot be used at this moment." + + "Please refer to docs to check the Bitbucket integration instructions"); + } + Matcher matcher = bitbucketUrlPattern.matcher(url); if (!matcher.matches()) { throw new IllegalArgumentException( From 62a8fa9a2e77b5b3b2946f8d2c00c89dec9a586b Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 24 Nov 2020 18:22:20 +0200 Subject: [PATCH 09/14] Fixups --- .../factory/server/bitbucket/BitbucketURLParser.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index d4aa12ee3aa..3b762c33775 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -35,21 +35,24 @@ public class BitbucketURLParser { private final DevfileFilenamesProvider devfileFilenamesProvider; private static final String bitbucketUrlPatternTemplate = "^(?%s)/scm/(?[^/]++)/(?[^.]++).git(\\?at=)?(?[\\w\\d-_]*)"; - private Pattern bitbucketUrlPattern; + private final Pattern bitbucketUrlPattern; @Inject public BitbucketURLParser( @Nullable @Named("bitbucket.server.endpoint") String bitbucketEndpoint, URLFetcher urlFetcher, DevfileFilenamesProvider devfileFilenamesProvider) { + String trimmedEndpoint = null; if (bitbucketEndpoint != null) { - String trimmedEndpoint = + trimmedEndpoint = bitbucketEndpoint.endsWith("/") ? bitbucketEndpoint.substring(0, bitbucketEndpoint.length() - 1) : bitbucketEndpoint; - this.bitbucketUrlPattern = - Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint)); } + this.bitbucketUrlPattern = + trimmedEndpoint != null + ? Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint)) + : null; this.urlFetcher = urlFetcher; this.devfileFilenamesProvider = devfileFilenamesProvider; } From 6979ee636a35961fd3b3c118e55e1ee39bd58443 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Fri, 27 Nov 2020 14:49:28 +0200 Subject: [PATCH 10/14] Merge with master --- .../pom.xml | 2 +- ...bucketServerFactoryParametersResolver.java | 10 +------- .../server/bitbucket/BitbucketURLParser.java | 1 - .../server/bitbucket/BitbucketUrl.java | 25 ------------------- ...etServerFactoryParametersResolverTest.java | 2 -- 5 files changed, 2 insertions(+), 38 deletions(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/pom.xml b/wsmaster/che-core-api-factory-bitbucket-server/pom.xml index 687b0eb2efa..6370c9e3a25 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/pom.xml +++ b/wsmaster/che-core-api-factory-bitbucket-server/pom.xml @@ -17,7 +17,7 @@ che-master-parent org.eclipse.che.core - 7.22.0-SNAPSHOT + 7.23.0-SNAPSHOT che-core-api-factory-bitbucket-server jar diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java index 001b6653c85..88a260c0b14 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolver.java @@ -83,15 +83,7 @@ public FactoryDto createFactory(@NotNull final Map factoryParame bitbucketUrl, fileName -> urlFetcher.fetch(bitbucketUrl.rawFileLocation(fileName)), extractOverrideParams(factoryParameters)) - .orElseGet( - () -> - urlFactoryBuilder - .createFactoryFromJson(bitbucketUrl) - .orElseGet( - () -> - newDto(FactoryDto.class) - .withV(CURRENT_VERSION) - .withSource("repo"))); + .orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo")); if (factory.getDevfile() == null) { // initialize default devfile diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index 3b762c33775..f7c401e3d23 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -92,7 +92,6 @@ public BitbucketUrl parse(String url) { .withProject(project) .withRepository(repoName) .withBranch(branch) - .withFactoryFilename(".factory.json") .withDevfileFilenames(devfileFilenamesProvider.getConfiguredDevfileFilenames()); } } diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java index 6c1ca1bbedd..fcdda2e9754 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketUrl.java @@ -93,21 +93,6 @@ protected BitbucketUrl withDevfileFilenames(List devfileFilenames) { return this; } - /** - * Gets factory file name of this bitbucket url - * - * @return the factory file name - */ - @Override - public String getFactoryFilename() { - return this.factoryFilename; - } - - protected BitbucketUrl withFactoryFilename(String factoryFilename) { - this.factoryFilename = factoryFilename; - return this; - } - /** * Gets branch of this bitbucket url * @@ -124,16 +109,6 @@ protected BitbucketUrl withBranch(String branch) { return this; } - /** - * Provides location to raw content of the factory json file - * - * @return location of factory json file in a repository - */ - @Override - public String factoryFileLocation() { - return rawFileLocation(factoryFilename); - } - /** * Provides list of configured devfile filenames with locations * diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java index a746931ec78..5ab683eb69a 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java @@ -94,8 +94,6 @@ public void shouldGenerateDevfileForFactoryWithNoDevfileOrJson() throws Exceptio when(urlFactoryBuilder.buildDefaultDevfile(any())).thenReturn(computedFactory.getDevfile()); - when(urlFactoryBuilder.createFactoryFromJson(any(RemoteFactoryUrl.class))) - .thenReturn(Optional.empty()); when(urlFactoryBuilder.createFactoryFromDevfile(any(RemoteFactoryUrl.class), any(), anyMap())) .thenReturn(Optional.empty()); Map params = ImmutableMap.of(URL_PARAMETER_NAME, bitbucketUrl); From dfcdfdc52e9d66d4d0b497e28720fd9d4abb529d Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 1 Dec 2020 18:13:26 +0200 Subject: [PATCH 11/14] Add multiple bitbucker servers support --- .../che/api/deploy/WsMasterModule.java | 4 +- .../webapp/WEB-INF/classes/che/che.properties | 6 +-- .../server/bitbucket/BitbucketURLParser.java | 42 ++++++++++++------- ...etServerFactoryParametersResolverTest.java | 3 +- .../bitbucket/BitbucketURLParserTest.java | 9 +++- 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java index c51f59c5ab8..da2efc5d392 100644 --- a/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java +++ b/assembly/assembly-wsmaster-war/src/main/java/org/eclipse/che/api/deploy/WsMasterModule.java @@ -152,7 +152,9 @@ protected void configure() { Multibinder factoryParametersResolverMultibinder = Multibinder.newSetBinder(binder(), FactoryParametersResolver.class); factoryParametersResolverMultibinder.addBinding().to(GithubFactoryParametersResolver.class); - factoryParametersResolverMultibinder.addBinding().to(BitbucketServerFactoryParametersResolver.class); + factoryParametersResolverMultibinder + .addBinding() + .to(BitbucketServerFactoryParametersResolver.class); bind(org.eclipse.che.api.core.rest.ApiInfoService.class); bind(org.eclipse.che.api.ssh.server.SshService.class); diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index a964abbba05..f8f585f97b1 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -686,6 +686,6 @@ che.infra.kubernetes.async.storage.shutdown_timeout_min=120 # Defines the period with which the Asynchronous Storage Pod stopping ability will be performed (once in 30 minutes by default) che.infra.kubernetes.async.storage.shutdown_check_period_min=30 -# Bitbucket endpoint used for both factory and OAuth integrations. Should contain bitbucket server -# URL or NULL if no integration expected. -bitbucket.server.endpoint=NULL +# Bitbucket endpoints used for factory integrations. +# Should contain comma separated bitbucket server URLs, or NULL if no integration expected. +bitbucket.server.endpoints=NULL diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index f7c401e3d23..fe4d5099fb3 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -13,6 +13,9 @@ import static java.lang.String.format; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; @@ -35,30 +38,32 @@ public class BitbucketURLParser { private final DevfileFilenamesProvider devfileFilenamesProvider; private static final String bitbucketUrlPatternTemplate = "^(?%s)/scm/(?[^/]++)/(?[^.]++).git(\\?at=)?(?[\\w\\d-_]*)"; - private final Pattern bitbucketUrlPattern; + private final List bitbucketUrlPatterns = new ArrayList<>(); @Inject public BitbucketURLParser( - @Nullable @Named("bitbucket.server.endpoint") String bitbucketEndpoint, + @Nullable @Named("bitbucket.server.endpoints") String[] bitbucketEndpoints, URLFetcher urlFetcher, DevfileFilenamesProvider devfileFilenamesProvider) { - String trimmedEndpoint = null; - if (bitbucketEndpoint != null) { - trimmedEndpoint = + this.urlFetcher = urlFetcher; + this.devfileFilenamesProvider = devfileFilenamesProvider; + if (bitbucketEndpoints == null) { + // nothing to initialize + return; + } + for (String bitbucketEndpoint : bitbucketEndpoints) { + String trimmedEndpoint = bitbucketEndpoint.endsWith("/") ? bitbucketEndpoint.substring(0, bitbucketEndpoint.length() - 1) : bitbucketEndpoint; + this.bitbucketUrlPatterns.add( + Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint))); } - this.bitbucketUrlPattern = - trimmedEndpoint != null - ? Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint)) - : null; - this.urlFetcher = urlFetcher; - this.devfileFilenamesProvider = devfileFilenamesProvider; } public boolean isValid(@NotNull String url) { - return bitbucketUrlPattern != null && bitbucketUrlPattern.matcher(url).matches(); + return !bitbucketUrlPatterns.isEmpty() + && bitbucketUrlPatterns.stream().anyMatch(pattern -> pattern.matcher(url).matches()); } /** @@ -68,20 +73,25 @@ public boolean isValid(@NotNull String url) { */ public BitbucketUrl parse(String url) { - if (bitbucketUrlPattern == null) { + if (bitbucketUrlPatterns.isEmpty()) { throw new UnsupportedOperationException( "The Bitbucket integration is not configured properly and cannot be used at this moment." + "Please refer to docs to check the Bitbucket integration instructions"); } - Matcher matcher = bitbucketUrlPattern.matcher(url); - if (!matcher.matches()) { + Optional validMatcherOpt = + bitbucketUrlPatterns + .stream() + .map(pattern -> pattern.matcher(url)) + .filter(Matcher::matches) + .findFirst(); + if (validMatcherOpt.isEmpty()) { throw new IllegalArgumentException( String.format( "The given url %s is not a valid Bitbucket server URL. Check either URL or server configuration.", url)); } - + Matcher matcher = validMatcherOpt.get(); String host = matcher.group("host"); String project = matcher.group("project"); String repoName = matcher.group("repo"); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java index 5ab683eb69a..19314a36214 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java @@ -60,7 +60,8 @@ public class BitbucketServerFactoryParametersResolverTest { @BeforeMethod protected void init() { bitbucketURLParser = - new BitbucketURLParser("http://bitbucket.2mcl.com", urlFetcher, devfileFilenamesProvider); + new BitbucketURLParser( + new String[] {"http://bitbucket.2mcl.com"}, urlFetcher, devfileFilenamesProvider); assertNotNull(this.bitbucketURLParser); bitbucketServerFactoryParametersResolver = new BitbucketServerFactoryParametersResolver( diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java index c7fb70ac271..8e6f9386dfd 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java @@ -35,7 +35,10 @@ public class BitbucketURLParserTest { @BeforeClass public void setUp() { bitbucketURLParser = - new BitbucketURLParser("https://bitbucket.2mcl.com", urlFetcher, devfileFilenamesProvider); + new BitbucketURLParser( + new String[] {"https://bitbucket.2mcl.com", "https://bbkt.com"}, + urlFetcher, + devfileFilenamesProvider); } /** Check URLs are valid with regexp */ @@ -59,6 +62,7 @@ public Object[][] urls() { return new Object[][] { {"https://bitbucket.2mcl.com/scm/project/test1.git"}, {"https://bitbucket.2mcl.com/scm/project/test1.git?at=branch"}, + {"https://bbkt.com/scm/project/test1.git"}, }; } @@ -66,7 +70,8 @@ public Object[][] urls() { public Object[][] expectedParsing() { return new Object[][] { {"https://bitbucket.2mcl.com/scm/project/test1.git", "project", "test1", null}, - {"https://bitbucket.2mcl.com/scm/project/test1.git?at=branch", "project", "test1", "branch"} + {"https://bitbucket.2mcl.com/scm/project/test1.git?at=branch", "project", "test1", "branch"}, + {"https://bbkt.com/scm/project/test1.git?at=branch", "project", "test1", "branch"} }; } } From 624a0075d0416b22ec5cdea6e636b822d82839c8 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Tue, 1 Dec 2020 18:26:09 +0200 Subject: [PATCH 12/14] Add test --- .../webapp/WEB-INF/classes/che/che.properties | 2 +- .../server/bitbucket/BitbucketURLParser.java | 18 ++++++++---------- .../bitbucket/BitbucketURLParserTest.java | 8 ++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index f8f585f97b1..c8137150e51 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -687,5 +687,5 @@ che.infra.kubernetes.async.storage.shutdown_timeout_min=120 che.infra.kubernetes.async.storage.shutdown_check_period_min=30 # Bitbucket endpoints used for factory integrations. -# Should contain comma separated bitbucket server URLs, or NULL if no integration expected. +# Should contain comma separated bitbucket server URLs, or NULL if no integration expected. bitbucket.server.endpoints=NULL diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index fe4d5099fb3..eb46e968e4a 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; @@ -79,19 +78,18 @@ public BitbucketUrl parse(String url) { + "Please refer to docs to check the Bitbucket integration instructions"); } - Optional validMatcherOpt = + Matcher matcher = bitbucketUrlPatterns .stream() .map(pattern -> pattern.matcher(url)) .filter(Matcher::matches) - .findFirst(); - if (validMatcherOpt.isEmpty()) { - throw new IllegalArgumentException( - String.format( - "The given url %s is not a valid Bitbucket server URL. Check either URL or server configuration.", - url)); - } - Matcher matcher = validMatcherOpt.get(); + .findFirst() + .orElseThrow( + () -> + new IllegalArgumentException( + format( + "The given url %s is not a valid Bitbucket server URL. Check either URL or server configuration.", + url))); String host = matcher.group("host"); String project = matcher.group("project"); String repoName = matcher.group("repo"); diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java index 8e6f9386dfd..b23bea43597 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java @@ -57,6 +57,14 @@ public void checkParsing(String url, String project, String repository, String b assertEquals(bitbucketUrl.getBranch(), branch); } + @Test( + expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = + "The given url https://github.com/org/repo is not a valid Bitbucket server URL. Check either URL or server configuration.") + public void shouldThrowExceptionWhenURLDintMatchAnyConfiguredServer() { + bitbucketURLParser.parse("https://github.com/org/repo"); + } + @DataProvider(name = "UrlsProvider") public Object[][] urls() { return new Object[][] { From d012000a0ee46c095f18bed268c4bac680cb54d6 Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 7 Dec 2020 11:56:07 +0200 Subject: [PATCH 13/14] Update assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties Fix language Co-authored-by: Michal Vala --- .../src/main/webapp/WEB-INF/classes/che/che.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties index c8137150e51..2295667cdf7 100644 --- a/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties +++ b/assembly/assembly-wsmaster-war/src/main/webapp/WEB-INF/classes/che/che.properties @@ -687,5 +687,5 @@ che.infra.kubernetes.async.storage.shutdown_timeout_min=120 che.infra.kubernetes.async.storage.shutdown_check_period_min=30 # Bitbucket endpoints used for factory integrations. -# Should contain comma separated bitbucket server URLs, or NULL if no integration expected. +# Comma separated list of bitbucket server URLs or NULL if no integration expected. bitbucket.server.endpoints=NULL From da9b4c9d933d924601cd79a15161726f3528d79f Mon Sep 17 00:00:00 2001 From: Max Shaposhnik Date: Mon, 7 Dec 2020 12:10:47 +0200 Subject: [PATCH 14/14] review fixups --- .../server/bitbucket/BitbucketURLParser.java | 23 +++++++++---------- ...etServerFactoryParametersResolverTest.java | 3 +-- .../bitbucket/BitbucketURLParserTest.java | 4 +--- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java index eb46e968e4a..da644c6afee 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/main/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParser.java @@ -13,6 +13,7 @@ import static java.lang.String.format; +import com.google.common.base.Splitter; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -41,22 +42,20 @@ public class BitbucketURLParser { @Inject public BitbucketURLParser( - @Nullable @Named("bitbucket.server.endpoints") String[] bitbucketEndpoints, + @Nullable @Named("bitbucket.server.endpoints") String bitbucketEndpoints, URLFetcher urlFetcher, DevfileFilenamesProvider devfileFilenamesProvider) { this.urlFetcher = urlFetcher; this.devfileFilenamesProvider = devfileFilenamesProvider; - if (bitbucketEndpoints == null) { - // nothing to initialize - return; - } - for (String bitbucketEndpoint : bitbucketEndpoints) { - String trimmedEndpoint = - bitbucketEndpoint.endsWith("/") - ? bitbucketEndpoint.substring(0, bitbucketEndpoint.length() - 1) - : bitbucketEndpoint; - this.bitbucketUrlPatterns.add( - Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint))); + if (bitbucketEndpoints != null) { + for (String bitbucketEndpoint : Splitter.on(",").split(bitbucketEndpoints)) { + String trimmedEndpoint = + bitbucketEndpoint.endsWith("/") + ? bitbucketEndpoint.substring(0, bitbucketEndpoint.length() - 1) + : bitbucketEndpoint; + this.bitbucketUrlPatterns.add( + Pattern.compile(format(bitbucketUrlPatternTemplate, trimmedEndpoint))); + } } } diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java index 19314a36214..5ab683eb69a 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketServerFactoryParametersResolverTest.java @@ -60,8 +60,7 @@ public class BitbucketServerFactoryParametersResolverTest { @BeforeMethod protected void init() { bitbucketURLParser = - new BitbucketURLParser( - new String[] {"http://bitbucket.2mcl.com"}, urlFetcher, devfileFilenamesProvider); + new BitbucketURLParser("http://bitbucket.2mcl.com", urlFetcher, devfileFilenamesProvider); assertNotNull(this.bitbucketURLParser); bitbucketServerFactoryParametersResolver = new BitbucketServerFactoryParametersResolver( diff --git a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java index b23bea43597..3c073fc50e4 100644 --- a/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java +++ b/wsmaster/che-core-api-factory-bitbucket-server/src/test/java/org/eclipse/che/api/factory/server/bitbucket/BitbucketURLParserTest.java @@ -36,9 +36,7 @@ public class BitbucketURLParserTest { public void setUp() { bitbucketURLParser = new BitbucketURLParser( - new String[] {"https://bitbucket.2mcl.com", "https://bbkt.com"}, - urlFetcher, - devfileFilenamesProvider); + "https://bitbucket.2mcl.com,https://bbkt.com", urlFetcher, devfileFilenamesProvider); } /** Check URLs are valid with regexp */