Skip to content

Commit

Permalink
Gh18838 factory devfile2 (#18868)
Browse files Browse the repository at this point in the history
Signed-off-by: Michal Vala <mvala@redhat.com>
  • Loading branch information
sparkoo authored Feb 3, 2021
1 parent 07929cb commit ef05a7c
Show file tree
Hide file tree
Showing 32 changed files with 818 additions and 245 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.eclipse.che.api.devfile.shared.dto.UserDevfileDto;
import org.eclipse.che.api.workspace.server.devfile.DevfileEntityProvider;
import org.eclipse.che.api.workspace.server.devfile.DevfileParser;
import org.eclipse.che.api.workspace.server.devfile.DevfileVersionDetector;
import org.eclipse.che.api.workspace.server.devfile.schema.DevfileSchemaProvider;
import org.eclipse.che.api.workspace.server.devfile.validator.DevfileIntegrityValidator;
import org.eclipse.che.api.workspace.server.devfile.validator.DevfileSchemaValidator;
Expand Down Expand Up @@ -70,7 +71,7 @@ public class UserDevfilePermissionsFilterTest {
private DevfileEntityProvider devfileEntityProvider =
new DevfileEntityProvider(
new DevfileParser(
new DevfileSchemaValidator(new DevfileSchemaProvider()),
new DevfileSchemaValidator(new DevfileSchemaProvider(), new DevfileVersionDetector()),
new DevfileIntegrityValidator(Collections.emptyMap())));

@SuppressWarnings("unused")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
import org.eclipse.che.api.devfile.shared.dto.UserDevfileDto;
import org.eclipse.che.api.workspace.server.devfile.DevfileEntityProvider;
import org.eclipse.che.api.workspace.server.devfile.DevfileParser;
import org.eclipse.che.api.workspace.server.devfile.DevfileVersionDetector;
import org.eclipse.che.api.workspace.server.devfile.schema.DevfileSchemaProvider;
import org.eclipse.che.api.workspace.server.devfile.validator.DevfileIntegrityValidator;
import org.eclipse.che.api.workspace.server.devfile.validator.DevfileSchemaValidator;
Expand Down Expand Up @@ -98,7 +99,7 @@ public class DevfileServiceTest {

private DevfileParser devfileParser =
new DevfileParser(
new DevfileSchemaValidator(new DevfileSchemaProvider()),
new DevfileSchemaValidator(new DevfileSchemaProvider(), new DevfileVersionDetector()),
new DevfileIntegrityValidator(Collections.emptyMap()));
DevfileEntityProvider devfileEntityProvider = new DevfileEntityProvider(devfileParser);
UserDevfileEntityProvider userDevfileEntityProvider =
Expand Down Expand Up @@ -514,7 +515,7 @@ public Object[][] invalidUserDevfiles() {
newDto(DevfileDto.class)
.withApiVersion(null)
.withMetadata(newDto(MetadataDto.class).withName("name"))),
"Devfile schema validation failed. Error: The object must have a property whose name is \"apiVersion\"."
"Devfile schema validation failed. Error: Neither of `apiVersion` or `schemaVersion` found. This is not a valid devfile."
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
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;
Expand All @@ -27,6 +25,8 @@
import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager;
import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
import org.eclipse.che.api.factory.shared.dto.FactoryVisitor;
import org.eclipse.che.api.workspace.server.devfile.FileContentProvider;
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
import org.eclipse.che.api.workspace.shared.dto.devfile.ProjectDto;
Expand Down Expand Up @@ -80,7 +80,7 @@ public boolean accept(@NotNull final Map<String, String> factoryParameters) {
* @throws BadRequestException when data are invalid
*/
@Override
public FactoryDto createFactory(@NotNull final Map<String, String> factoryParameters)
public FactoryMetaDto createFactory(@NotNull final Map<String, String> factoryParameters)
throws BadRequestException {

// no need to check null value of url parameter as accept() method has performed the check
Expand All @@ -92,41 +92,50 @@ public FactoryDto createFactory(@NotNull final Map<String, String> factoryParame
bitbucketUrl, urlFetcher, gitCredentialManager, personalAccessTokenManager);

// create factory from the following location if location exists, else create default factory
FactoryDto factory =
urlFactoryBuilder
.createFactoryFromDevfile(
bitbucketUrl, fileContentProvider, extractOverrideParams(factoryParameters))
.orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo"));

if (factory.getDevfile() == null) {
// initialize default devfile
factory.setDevfile(urlFactoryBuilder.buildDefaultDevfile(bitbucketUrl.getRepository()));
return urlFactoryBuilder
.createFactoryFromDevfile(
bitbucketUrl, fileContentProvider, extractOverrideParams(factoryParameters))
.orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo"))
.acceptVisitor(new BitbucketFactoryVisitor(bitbucketUrl));
}

/**
* Visitor that puts the default devfile or updates devfile projects into the Bitbucket Factory,
* if needed.
*/
private class BitbucketFactoryVisitor implements FactoryVisitor {

private final BitbucketUrl bitbucketUrl;

private BitbucketFactoryVisitor(BitbucketUrl bitbucketUrl) {
this.bitbucketUrl = bitbucketUrl;
}

List<ProjectDto> 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(
@Override
public FactoryDto visit(FactoryDto factory) {
if (factory.getDevfile() == null) {
// initialize default devfile
factory.setDevfile(urlFactoryBuilder.buildDefaultDevfile(bitbucketUrl.getRepository()));
}

updateProjects(
factory.getDevfile(),
() ->
newDto(ProjectDto.class)
.withSource(
newDto(SourceDto.class)
.withLocation(bitbucketUrl.repositoryLocation())
.withType("git")
.withBranch(bitbucketUrl.getBranch()))
.withName(bitbucketUrl.getRepository()),
project -> {
final String location = project.getSource().getLocation();
if (location.equals(bitbucketUrl.repositoryLocation())) {
project.getSource().setBranch(bitbucketUrl.getBranch());
}
});

return factory;
}
return factory;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ public void shouldGenerateDevfileForFactoryWithNoDevfileOrJson() throws Exceptio
.thenReturn(Optional.empty());
Map<String, String> params = ImmutableMap.of(URL_PARAMETER_NAME, bitbucketUrl);
// when
FactoryDto factory = bitbucketServerFactoryParametersResolver.createFactory(params);
FactoryDto factory =
(FactoryDto) bitbucketServerFactoryParametersResolver.createFactory(params);
// then
verify(urlFactoryBuilder).buildDefaultDevfile(eq("repo"));
assertEquals(factory, computedFactory);
Expand All @@ -129,7 +130,8 @@ public void shouldSetDefaultProjectIntoDevfileIfNotSpecified() throws Exception

Map<String, String> params = ImmutableMap.of(URL_PARAMETER_NAME, bitbucketUrl);
// when
FactoryDto factory = bitbucketServerFactoryParametersResolver.createFactory(params);
FactoryDto factory =
(FactoryDto) bitbucketServerFactoryParametersResolver.createFactory(params);
// then
assertNotNull(factory.getDevfile());
SourceDto source = factory.getDevfile().getProjects().get(0).getSource();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@
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.core.ServerException;
import org.eclipse.che.api.factory.server.DefaultFactoryParameterResolver;
import org.eclipse.che.api.factory.server.urlfactory.ProjectConfigDtoMerger;
import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
import org.eclipse.che.api.factory.shared.dto.FactoryVisitor;
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.devfile.ProjectDto;
Expand Down Expand Up @@ -82,57 +81,66 @@ public boolean accept(@NotNull final Map<String, String> factoryParameters) {
* @throws BadRequestException when data are invalid
*/
@Override
public FactoryDto createFactory(@NotNull final Map<String, String> factoryParameters)
throws BadRequestException, ServerException {
public FactoryMetaDto createFactory(@NotNull final Map<String, String> factoryParameters)
throws BadRequestException {

// 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));

// create factory from the following location if location exists, else create default factory
FactoryDto factory =
urlFactoryBuilder
.createFactoryFromDevfile(
githubUrl,
new GithubFileContentProvider(githubUrl, urlFetcher),
extractOverrideParams(factoryParameters))
.orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo"));

if (factory.getWorkspace() != null) {
return projectConfigDtoMerger.merge(
factory,
() -> {
// Compute project configuration
return newDto(ProjectConfigDto.class)
.withSource(githubSourceStorageBuilder.buildWorkspaceConfigSource(githubUrl))
.withName(githubUrl.getRepository())
.withPath("/".concat(githubUrl.getRepository()));
});
} else if (factory.getDevfile() == null) {
// initialize default devfile
factory.setDevfile(urlFactoryBuilder.buildDefaultDevfile(githubUrl.getRepository()));
return urlFactoryBuilder
.createFactoryFromDevfile(
githubUrl,
new GithubFileContentProvider(githubUrl, urlFetcher),
extractOverrideParams(factoryParameters))
.orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo"))
.acceptVisitor(new GithubFactoryVisitor(githubUrl));
}

/**
* Visitor that puts the default devfile or updates devfile projects into the Github Factory, if
* needed.
*/
private class GithubFactoryVisitor implements FactoryVisitor {

private final GithubUrl githubUrl;

private GithubFactoryVisitor(GithubUrl githubUrl) {
this.githubUrl = githubUrl;
}

List<ProjectDto> projects = factory.getDevfile().getProjects();
// if no projects set, set the default one from GitHub url
if (projects.isEmpty()) {
factory
.getDevfile()
.setProjects(
Collections.singletonList(
newDto(ProjectDto.class)
.withSource(githubSourceStorageBuilder.buildDevfileSource(githubUrl))
.withName(githubUrl.getRepository())));
} else {
// update existing project with same repository, set current branch if needed
projects.forEach(
@Override
public FactoryDto visit(FactoryDto factory) {
if (factory.getWorkspace() != null) {
return projectConfigDtoMerger.merge(
factory,
() -> {
// Compute project configuration
return newDto(ProjectConfigDto.class)
.withSource(githubSourceStorageBuilder.buildWorkspaceConfigSource(githubUrl))
.withName(githubUrl.getRepository())
.withPath("/".concat(githubUrl.getRepository()));
});
} else if (factory.getDevfile() == null) {
// initialize default devfile
factory.setDevfile(urlFactoryBuilder.buildDefaultDevfile(githubUrl.getRepository()));
}

updateProjects(
factory.getDevfile(),
() ->
newDto(ProjectDto.class)
.withSource(githubSourceStorageBuilder.buildDevfileSource(githubUrl))
.withName(githubUrl.getRepository()),
project -> {
final String location = project.getSource().getLocation();
if (location.equals(githubUrl.repositoryLocation())
|| location.equals(githubUrl.repositoryLocation() + ".git")) {
project.getSource().setBranch(githubUrl.getBranch());
}
});

return factory;
}
return factory;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public void shouldGenerateDevfileForFactoryWithNoDevfile() throws Exception {
.thenReturn(Optional.empty());
Map<String, String> params = ImmutableMap.of(URL_PARAMETER_NAME, githubUrl);
// when
FactoryDto factory = githubFactoryParametersResolver.createFactory(params);
FactoryDto factory = (FactoryDto) githubFactoryParametersResolver.createFactory(params);
// then
verify(urlFactoryBuilder).buildDefaultDevfile(eq("che"));
assertEquals(factory, computedFactory);
Expand All @@ -165,7 +165,7 @@ public void shouldReturnFactoryFromRepositoryWithDevfile() throws Exception {

Map<String, String> params = ImmutableMap.of(URL_PARAMETER_NAME, githubUrl);
// when
FactoryDto factory = githubFactoryParametersResolver.createFactory(params);
FactoryDto factory = (FactoryDto) githubFactoryParametersResolver.createFactory(params);
// then
assertNotNull(factory.getDevfile());
assertNull(factory.getWorkspace());
Expand All @@ -191,7 +191,7 @@ public void shouldSetDefaultProjectIntoDevfileIfNotSpecified() throws Exception

Map<String, String> params = ImmutableMap.of(URL_PARAMETER_NAME, githubUrl);
// when
FactoryDto factory = githubFactoryParametersResolver.createFactory(params);
FactoryDto factory = (FactoryDto) githubFactoryParametersResolver.createFactory(params);
// then
assertNotNull(factory.getDevfile());
SourceDto source = factory.getDevfile().getProjects().get(0).getSource();
Expand All @@ -218,7 +218,7 @@ public void shouldSetBranchIntoDevfileIfNotMatchesCurrent() throws Exception {

Map<String, String> params = ImmutableMap.of(URL_PARAMETER_NAME, githubUrl);
// when
FactoryDto factory = githubFactoryParametersResolver.createFactory(params);
FactoryDto factory = (FactoryDto) githubFactoryParametersResolver.createFactory(params);
// then
assertNotNull(factory.getDevfile());
SourceDto source = factory.getDevfile().getProjects().get(0).getSource();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* 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.shared.dto;

import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.MANDATORY;

import java.util.List;
import java.util.Map;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.rest.shared.dto.Hyperlinks;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.dto.shared.DTO;

/**
* Factory DTO for Devfile v2. As che-server don't know the structure of Devfile v2, we're using
* just generic {@code Map<String, Object>} here.
*/
@DTO
public interface FactoryDevfileV2Dto extends FactoryMetaDto, Hyperlinks {

@Override
default FactoryMetaDto acceptVisitor(FactoryVisitor visitor) {
return visitor.visit(this);
}

@Override
FactoryDevfileV2Dto withV(String v);

@FactoryParameter(obligation = MANDATORY)
Map<String, Object> getDevfile();

void setDevfile(Map<String, Object> devfile);

FactoryDevfileV2Dto withDevfile(Map<String, Object> devfile);

@Override
FactoryDevfileV2Dto withSource(String source);

@Override
FactoryDevfileV2Dto withLinks(List<Link> links);
}
Loading

0 comments on commit ef05a7c

Please sign in to comment.