parent
07929cb591
commit
ef05a7c9eb
|
|
@ -41,6 +41,7 @@ import org.eclipse.che.api.devfile.server.model.impl.UserDevfileImpl;
|
|||
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;
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import org.eclipse.che.api.devfile.server.spi.UserDevfileDao;
|
|||
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;
|
||||
|
|
@ -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 =
|
||||
|
|
@ -514,7 +515,7 @@ public class DevfileServiceTest {
|
|||
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."
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ 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;
|
||||
|
|
@ -27,6 +25,8 @@ import org.eclipse.che.api.factory.server.scm.GitCredentialManager;
|
|||
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;
|
||||
|
|
@ -80,7 +80,7 @@ public class BitbucketServerAuthorizingFactoryParametersResolver
|
|||
* @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
|
||||
|
|
@ -92,41 +92,50 @@ public class BitbucketServerAuthorizingFactoryParametersResolver
|
|||
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"));
|
||||
return urlFactoryBuilder
|
||||
.createFactoryFromDevfile(
|
||||
bitbucketUrl, fileContentProvider, extractOverrideParams(factoryParameters))
|
||||
.orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo"))
|
||||
.acceptVisitor(new BitbucketFactoryVisitor(bitbucketUrl));
|
||||
}
|
||||
|
||||
if (factory.getDevfile() == null) {
|
||||
// initialize default devfile
|
||||
factory.setDevfile(urlFactoryBuilder.buildDefaultDevfile(bitbucketUrl.getRepository()));
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,8 @@ public class BitbucketServerAuthorizingFactoryParametersResolverTest {
|
|||
.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);
|
||||
|
|
@ -129,7 +130,8 @@ public class BitbucketServerAuthorizingFactoryParametersResolverTest {
|
|||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -15,18 +15,17 @@ 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.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;
|
||||
|
|
@ -82,49 +81,57 @@ public class GithubFactoryParametersResolver extends DefaultFactoryParameterReso
|
|||
* @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"));
|
||||
return urlFactoryBuilder
|
||||
.createFactoryFromDevfile(
|
||||
githubUrl,
|
||||
new GithubFileContentProvider(githubUrl, urlFetcher),
|
||||
extractOverrideParams(factoryParameters))
|
||||
.orElseGet(() -> newDto(FactoryDto.class).withV(CURRENT_VERSION).withSource("repo"))
|
||||
.acceptVisitor(new GithubFactoryVisitor(githubUrl));
|
||||
}
|
||||
|
||||
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()));
|
||||
/**
|
||||
* 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())
|
||||
|
|
@ -132,7 +139,8 @@ public class GithubFactoryParametersResolver extends DefaultFactoryParameterReso
|
|||
project.getSource().setBranch(githubUrl.getBranch());
|
||||
}
|
||||
});
|
||||
|
||||
return factory;
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ public class GithubFactoryParametersResolverTest {
|
|||
.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);
|
||||
|
|
@ -165,7 +165,7 @@ public class GithubFactoryParametersResolverTest {
|
|||
|
||||
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());
|
||||
|
|
@ -191,7 +191,7 @@ public class GithubFactoryParametersResolverTest {
|
|||
|
||||
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();
|
||||
|
|
@ -218,7 +218,7 @@ public class GithubFactoryParametersResolverTest {
|
|||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
package org.eclipse.che.api.factory.shared.dto;
|
||||
|
||||
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.MANDATORY;
|
||||
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
|
||||
|
||||
import java.util.List;
|
||||
|
|
@ -24,28 +23,50 @@ import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
|||
import org.eclipse.che.dto.shared.DTO;
|
||||
|
||||
/**
|
||||
* Factory of version 4.0
|
||||
* Factory of version 4.0.
|
||||
*
|
||||
* <p>This 'implementation' of {@link FactoryMetaDto} is used for Devfile v1.
|
||||
*
|
||||
* @author Max Shaposhnik
|
||||
*/
|
||||
@DTO
|
||||
public interface FactoryDto extends Factory, Hyperlinks {
|
||||
public interface FactoryDto extends FactoryMetaDto, Factory, Hyperlinks {
|
||||
|
||||
@Override
|
||||
@FactoryParameter(obligation = MANDATORY)
|
||||
String getV();
|
||||
|
||||
void setV(String v);
|
||||
|
||||
FactoryDto withV(String v);
|
||||
default FactoryMetaDto acceptVisitor(FactoryVisitor visitor) {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
DevfileDto getDevfile();
|
||||
|
||||
void setDevfile(DevfileDto workspace);
|
||||
void setDevfile(DevfileDto devfileDto);
|
||||
|
||||
FactoryDto withDevfile(DevfileDto devfileDto);
|
||||
|
||||
FactoryDto withV(String v);
|
||||
|
||||
@Override
|
||||
FactoryDto withName(String name);
|
||||
|
||||
@Override
|
||||
FactoryDto withPolicies(PoliciesDto policies);
|
||||
|
||||
@Override
|
||||
FactoryDto withIde(IdeDto ide);
|
||||
|
||||
@Override
|
||||
FactoryDto withId(String id);
|
||||
|
||||
@Override
|
||||
FactoryDto withSource(String source);
|
||||
|
||||
@Override
|
||||
FactoryDto withCreator(AuthorDto creator);
|
||||
|
||||
@Override
|
||||
FactoryDto withLinks(List<Link> links);
|
||||
|
||||
/** because factory DTO may have devfile, in that case, workspace may be optional */
|
||||
@Override
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
|
|
@ -54,59 +75,4 @@ public interface FactoryDto extends Factory, Hyperlinks {
|
|||
void setWorkspace(WorkspaceConfigDto workspace);
|
||||
|
||||
FactoryDto withWorkspace(WorkspaceConfigDto workspace);
|
||||
|
||||
@Override
|
||||
@FactoryParameter(obligation = OPTIONAL, trackedOnly = true)
|
||||
PoliciesDto getPolicies();
|
||||
|
||||
void setPolicies(PoliciesDto policies);
|
||||
|
||||
FactoryDto withPolicies(PoliciesDto policies);
|
||||
|
||||
@Override
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
AuthorDto getCreator();
|
||||
|
||||
void setCreator(AuthorDto creator);
|
||||
|
||||
FactoryDto withCreator(AuthorDto creator);
|
||||
|
||||
@Override
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
IdeDto getIde();
|
||||
|
||||
void setIde(IdeDto ide);
|
||||
|
||||
FactoryDto withIde(IdeDto ide);
|
||||
|
||||
@Override
|
||||
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
|
||||
String getId();
|
||||
|
||||
void setId(String id);
|
||||
|
||||
FactoryDto withId(String id);
|
||||
|
||||
/**
|
||||
* Indicates filename in repository from which the factory was created (for example, .devfile) or
|
||||
* just contains 'repo' value if factory was created from bare GitHub repository. For custom raw
|
||||
* URL's (pastebin, gist etc) value is {@code null}
|
||||
*/
|
||||
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
|
||||
String getSource();
|
||||
|
||||
void setSource(String source);
|
||||
|
||||
FactoryDto withSource(String source);
|
||||
|
||||
@Override
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
FactoryDto withName(String name);
|
||||
|
||||
@Override
|
||||
FactoryDto withLinks(List<Link> links);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.shared.dto;
|
||||
|
||||
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.MANDATORY;
|
||||
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;
|
||||
|
||||
import java.util.List;
|
||||
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;
|
||||
|
||||
/** Ancestor for Factory DTOs that does not know about devfile version it will hold. */
|
||||
public interface FactoryMetaDto extends Hyperlinks {
|
||||
|
||||
/**
|
||||
* Gives an option to update the factory based on devfile version. See {@link FactoryVisitor}.
|
||||
*
|
||||
* @param visitor visitor that should update the factory
|
||||
* @return updated factory
|
||||
*/
|
||||
FactoryMetaDto acceptVisitor(FactoryVisitor visitor);
|
||||
|
||||
@FactoryParameter(obligation = MANDATORY)
|
||||
String getV();
|
||||
|
||||
void setV(String v);
|
||||
|
||||
FactoryMetaDto withV(String v);
|
||||
|
||||
/**
|
||||
* Indicates filename in repository from which the factory was created (for example, .devfile) or
|
||||
* just contains 'repo' value if factory was created from bare GitHub repository. For custom raw
|
||||
* URL's (pastebin, gist etc) value is {@code null}
|
||||
*/
|
||||
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
|
||||
String getSource();
|
||||
|
||||
void setSource(String source);
|
||||
|
||||
FactoryMetaDto withSource(String source);
|
||||
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
String getName();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
FactoryMetaDto withName(String name);
|
||||
|
||||
@FactoryParameter(obligation = OPTIONAL, setByServer = true)
|
||||
String getId();
|
||||
|
||||
void setId(String id);
|
||||
|
||||
FactoryMetaDto withId(String id);
|
||||
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
AuthorDto getCreator();
|
||||
|
||||
void setCreator(AuthorDto creator);
|
||||
|
||||
FactoryMetaDto withCreator(AuthorDto creator);
|
||||
|
||||
@Override
|
||||
FactoryMetaDto withLinks(List<Link> links);
|
||||
|
||||
@FactoryParameter(obligation = OPTIONAL, trackedOnly = true)
|
||||
PoliciesDto getPolicies();
|
||||
|
||||
void setPolicies(PoliciesDto policies);
|
||||
|
||||
FactoryMetaDto withPolicies(PoliciesDto policies);
|
||||
|
||||
@FactoryParameter(obligation = OPTIONAL)
|
||||
IdeDto getIde();
|
||||
|
||||
void setIde(IdeDto ide);
|
||||
|
||||
FactoryMetaDto withIde(IdeDto ide);
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Visitor that allows us to do necessary updates to the factory, like include default devfile, set
|
||||
* project url, set branch of the project etc.
|
||||
*/
|
||||
public interface FactoryVisitor {
|
||||
|
||||
/**
|
||||
* Visit factory with devfile v1.
|
||||
*
|
||||
* <p>Implementation should update given factory with needed changes and give it back.
|
||||
*
|
||||
* @param factoryDto factory to visit
|
||||
* @return updated factory
|
||||
*/
|
||||
FactoryDto visit(FactoryDto factoryDto);
|
||||
|
||||
/**
|
||||
* Visit factory with devfile v2.
|
||||
*
|
||||
* <p>Implementation should update given factory and give it back.
|
||||
*
|
||||
* <p>Che-server does not know devfile v2 structure so most likely we don't want to do anything
|
||||
* with it. The default implementation is here for that reason.
|
||||
*
|
||||
* @param factoryDto factory to visit
|
||||
* @return update factory
|
||||
*/
|
||||
default FactoryDevfileV2Dto visit(FactoryDevfileV2Dto factoryDto) {
|
||||
// most likely nothing to do with Devfile v2 factory as we don't know or touch the structure
|
||||
return factoryDto;
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,10 @@
|
|||
<findbugs.failonerror>false</findbugs.failonerror>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
|
|
|
|||
|
|
@ -19,8 +19,12 @@ import java.net.MalformedURLException;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
|
@ -28,9 +32,11 @@ import org.eclipse.che.api.core.BadRequestException;
|
|||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.factory.server.urlfactory.DefaultFactoryUrl;
|
||||
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.workspace.server.devfile.URLFetcher;
|
||||
import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.DevfileDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.devfile.ProjectDto;
|
||||
|
||||
/**
|
||||
* Default {@link FactoryParametersResolver} implementation. Tries to resolve factory based on
|
||||
|
|
@ -65,7 +71,7 @@ public class DefaultFactoryParameterResolver implements FactoryParametersResolve
|
|||
* @param factoryParameters map containing factory data parameters provided through URL
|
||||
*/
|
||||
@Override
|
||||
public FactoryDto createFactory(@NotNull final Map<String, String> factoryParameters)
|
||||
public FactoryMetaDto createFactory(@NotNull final Map<String, String> factoryParameters)
|
||||
throws BadRequestException, ServerException {
|
||||
// This should never be null, because our contract in #accept prohibits that
|
||||
String devfileLocation = factoryParameters.get(URL_PARAMETER_NAME);
|
||||
|
|
@ -100,4 +106,25 @@ public class DefaultFactoryParameterResolver implements FactoryParametersResolve
|
|||
.filter(e -> e.getKey().startsWith(OVERRIDE_PREFIX))
|
||||
.collect(toMap(e -> e.getKey().substring(OVERRIDE_PREFIX.length()), Entry::getValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* If devfile has no projects, put there one provided by given `projectSupplier`. Otherwise update
|
||||
* all projects with given `projectModifier`.
|
||||
*
|
||||
* @param devfile of the projects to update
|
||||
* @param projectSupplier provides default project
|
||||
* @param projectModifier updates existing projects
|
||||
*/
|
||||
protected void updateProjects(
|
||||
DevfileDto devfile,
|
||||
Supplier<ProjectDto> projectSupplier,
|
||||
Consumer<ProjectDto> projectModifier) {
|
||||
List<ProjectDto> projects = devfile.getProjects();
|
||||
if (projects.isEmpty()) {
|
||||
devfile.setProjects(Collections.singletonList(projectSupplier.get()));
|
||||
} else {
|
||||
// update existing project with same repository, set current branch if needed
|
||||
projects.forEach(projectModifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
package org.eclipse.che.api.factory.server;
|
||||
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
|
||||
/** Interface for validations of factory urls on accept stage. */
|
||||
public interface FactoryAcceptValidator {
|
||||
|
|
@ -24,5 +24,5 @@ public interface FactoryAcceptValidator {
|
|||
* @param factory factory object to validate
|
||||
* @throws BadRequestException in case if factory is not valid
|
||||
*/
|
||||
void validateOnAccept(FactoryDto factory) throws BadRequestException;
|
||||
void validateOnAccept(FactoryMetaDto factory) throws BadRequestException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import javax.ws.rs.HttpMethod;
|
|||
import javax.ws.rs.core.UriBuilder;
|
||||
import org.eclipse.che.api.core.rest.ServiceContext;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.Link;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
|
||||
/**
|
||||
* Helper class for creation links.
|
||||
|
|
@ -43,7 +43,7 @@ public class FactoryLinksHelper {
|
|||
* @return list of factory links
|
||||
*/
|
||||
public static List<Link> createLinks(
|
||||
FactoryDto factory, ServiceContext serviceContext, String userName) {
|
||||
FactoryMetaDto factory, ServiceContext serviceContext, String userName) {
|
||||
final List<Link> links = new LinkedList<>();
|
||||
final UriBuilder uriBuilder = serviceContext.getServiceUriBuilder();
|
||||
final String factoryId = factory.getId();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import java.util.Map;
|
|||
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.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
|
||||
/**
|
||||
* Defines a resolver that will produce factories for some parameters
|
||||
|
|
@ -39,6 +39,6 @@ public interface FactoryParametersResolver {
|
|||
* @param factoryParameters map containing factory data parameters provided through URL
|
||||
* @throws BadRequestException when data are invalid
|
||||
*/
|
||||
FactoryDto createFactory(@NotNull Map<String, String> factoryParameters)
|
||||
FactoryMetaDto createFactory(@NotNull Map<String, String> factoryParameters)
|
||||
throws BadRequestException, ServerException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import org.eclipse.che.api.core.ApiException;
|
|||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.rest.Service;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
import org.eclipse.che.api.user.server.UserManager;
|
||||
|
||||
/**
|
||||
|
|
@ -78,7 +78,7 @@ public class FactoryService extends Service {
|
|||
@ApiResponse(code = 400, message = "Missed required parameters, failed to validate factory"),
|
||||
@ApiResponse(code = 500, message = "Internal server error")
|
||||
})
|
||||
public FactoryDto resolveFactory(
|
||||
public FactoryMetaDto resolveFactory(
|
||||
@ApiParam(value = "Parameters provided to create factories") Map<String, String> parameters,
|
||||
@ApiParam(
|
||||
value = "Whether or not to validate values like it is done when accepting a Factory",
|
||||
|
|
@ -93,7 +93,7 @@ public class FactoryService extends Service {
|
|||
requiredNotNull(parameters, "Factory build parameters");
|
||||
|
||||
// search matching resolver and create factory from matching resolver
|
||||
FactoryDto resolvedFactory =
|
||||
FactoryMetaDto resolvedFactory =
|
||||
factoryParametersResolverHolder
|
||||
.getFactoryParametersResolver(parameters)
|
||||
.createFactory(parameters);
|
||||
|
|
@ -103,11 +103,14 @@ public class FactoryService extends Service {
|
|||
if (validate) {
|
||||
acceptValidator.validateOnAccept(resolvedFactory);
|
||||
}
|
||||
return injectLinks(resolvedFactory);
|
||||
|
||||
resolvedFactory = injectLinks(resolvedFactory);
|
||||
|
||||
return resolvedFactory;
|
||||
}
|
||||
|
||||
/** Injects factory links. If factory is named then accept named link will be injected. */
|
||||
private FactoryDto injectLinks(FactoryDto factory) {
|
||||
private FactoryMetaDto injectLinks(FactoryMetaDto factory) {
|
||||
String username = null;
|
||||
if (factory.getCreator() != null && factory.getCreator().getUserId() != null) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ package org.eclipse.che.api.factory.server.impl;
|
|||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.factory.server.FactoryAcceptValidator;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
|
||||
/** Factory accept stage validator. */
|
||||
@Singleton
|
||||
|
|
@ -22,7 +22,7 @@ public class FactoryAcceptValidatorImpl extends FactoryBaseValidator
|
|||
implements FactoryAcceptValidator {
|
||||
|
||||
@Override
|
||||
public void validateOnAccept(FactoryDto factory) throws BadRequestException {
|
||||
public void validateOnAccept(FactoryMetaDto factory) throws BadRequestException {
|
||||
validateCurrentTimeBetweenSinceUntil(factory);
|
||||
validateProjectActions(factory);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.regex.Pattern;
|
|||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.factory.server.FactoryConstants;
|
||||
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.IdeActionDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.IdeDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.OnAppLoadedDto;
|
||||
|
|
@ -94,7 +95,7 @@ public abstract class FactoryBaseValidator {
|
|||
* @throws BadRequestException if since date greater than current date<br>
|
||||
* @throws BadRequestException if until date less than current date<br>
|
||||
*/
|
||||
protected void validateCurrentTimeBetweenSinceUntil(FactoryDto factory)
|
||||
protected void validateCurrentTimeBetweenSinceUntil(FactoryMetaDto factory)
|
||||
throws BadRequestException {
|
||||
final PoliciesDto policies = factory.getPolicies();
|
||||
if (policies == null) {
|
||||
|
|
@ -149,7 +150,7 @@ public abstract class FactoryBaseValidator {
|
|||
* @param factory factory to validate
|
||||
* @throws BadRequestException when factory actions is invalid
|
||||
*/
|
||||
protected void validateProjectActions(FactoryDto factory) throws BadRequestException {
|
||||
protected void validateProjectActions(FactoryMetaDto factory) throws BadRequestException {
|
||||
final IdeDto ide = factory.getIde();
|
||||
if (ide == null) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_E
|
|||
import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE;
|
||||
import static org.eclipse.che.dto.server.DtoFactory.newDto;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
|
@ -28,9 +29,12 @@ import javax.inject.Named;
|
|||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl.DevfileLocation;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDevfileV2Dto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
import org.eclipse.che.api.workspace.server.DtoConverter;
|
||||
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.FileContentProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.OverrideParameterException;
|
||||
|
|
@ -57,15 +61,18 @@ public class URLFactoryBuilder {
|
|||
private final String defaultChePlugins;
|
||||
|
||||
private final DevfileParser devfileParser;
|
||||
private final DevfileVersionDetector devfileVersionDetector;
|
||||
|
||||
@Inject
|
||||
public URLFactoryBuilder(
|
||||
@Named("che.factory.default_editor") String defaultCheEditor,
|
||||
@Named("che.factory.default_plugins") String defaultChePlugins,
|
||||
DevfileParser devfileParser) {
|
||||
DevfileParser devfileParser,
|
||||
DevfileVersionDetector devfileVersionDetector) {
|
||||
this.defaultCheEditor = defaultCheEditor;
|
||||
this.defaultChePlugins = defaultChePlugins;
|
||||
this.devfileParser = devfileParser;
|
||||
this.devfileVersionDetector = devfileVersionDetector;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -83,7 +90,7 @@ public class URLFactoryBuilder {
|
|||
* @param overrideProperties map of overridden properties to apply in devfile
|
||||
* @return a factory or null if devfile is not found
|
||||
*/
|
||||
public Optional<FactoryDto> createFactoryFromDevfile(
|
||||
public Optional<FactoryMetaDto> createFactoryFromDevfile(
|
||||
RemoteFactoryUrl remoteFactoryUrl,
|
||||
FileContentProvider fileContentProvider,
|
||||
Map<String, String> overrideProperties)
|
||||
|
|
@ -109,17 +116,11 @@ public class URLFactoryBuilder {
|
|||
if (isNullOrEmpty(devfileYamlContent)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
DevfileImpl devfile = devfileParser.parseYaml(devfileYamlContent, overrideProperties);
|
||||
devfileParser.resolveReference(devfile, fileContentProvider);
|
||||
devfile = ensureToUseGenerateName(devfile);
|
||||
|
||||
FactoryDto factoryDto =
|
||||
newDto(FactoryDto.class)
|
||||
.withV(CURRENT_VERSION)
|
||||
.withDevfile(DtoConverter.asDto(devfile))
|
||||
.withSource(location.filename().isPresent() ? location.filename().get() : null);
|
||||
return Optional.of(factoryDto);
|
||||
try {
|
||||
JsonNode parsedDevfile = devfileParser.parseYamlRaw(devfileYamlContent);
|
||||
return Optional.of(
|
||||
createFactory(parsedDevfile, overrideProperties, fileContentProvider, location));
|
||||
} catch (DevfileException | OverrideParameterException e) {
|
||||
throw new BadRequestException(
|
||||
"Error occurred during creation a workspace from devfile located at `"
|
||||
|
|
@ -131,6 +132,41 @@ public class URLFactoryBuilder {
|
|||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts given devfile json into factory based on the devfile version.
|
||||
*
|
||||
* @param overrideProperties map of overridden properties to apply in devfile
|
||||
* @param fileContentProvider service-specific devfile related file content provider
|
||||
* @param location devfile's location
|
||||
* @return new factory created from the given devfile
|
||||
* @throws OverrideParameterException when any issue when overriding parameters occur
|
||||
* @throws DevfileException when devfile is not valid or we can't work with it
|
||||
*/
|
||||
private FactoryMetaDto createFactory(
|
||||
JsonNode devfileJson,
|
||||
Map<String, String> overrideProperties,
|
||||
FileContentProvider fileContentProvider,
|
||||
DevfileLocation location)
|
||||
throws OverrideParameterException, DevfileException {
|
||||
|
||||
if (devfileVersionDetector.devfileMajorVersion(devfileJson) == 1) {
|
||||
DevfileImpl devfile = devfileParser.parseJsonNode(devfileJson, overrideProperties);
|
||||
devfileParser.resolveReference(devfile, fileContentProvider);
|
||||
devfile = ensureToUseGenerateName(devfile);
|
||||
|
||||
return newDto(FactoryDto.class)
|
||||
.withV(CURRENT_VERSION)
|
||||
.withDevfile(DtoConverter.asDto(devfile))
|
||||
.withSource(location.filename().isPresent() ? location.filename().get() : null);
|
||||
|
||||
} else {
|
||||
return newDto(FactoryDevfileV2Dto.class)
|
||||
.withV(CURRENT_VERSION)
|
||||
.withDevfile(devfileParser.convertYamlToMap(devfileJson))
|
||||
.withSource(location.filename().isPresent() ? location.filename().get() : null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates devfile with only `generateName` and no `name`. We take `generateName` with precedence.
|
||||
* See doc of {@link URLFactoryBuilder#createFactoryFromDevfile(RemoteFactoryUrl,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.eclipse.che.api.core.BadRequestException;
|
|||
import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl;
|
||||
import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
|
||||
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.URLFetcher;
|
||||
import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.schema.DevfileSchemaProvider;
|
||||
|
|
@ -66,7 +67,8 @@ public class DefaultFactoryParameterResolverTest {
|
|||
// given
|
||||
|
||||
// we need to set up an "almost real" devfile converter which is a little bit involved
|
||||
DevfileSchemaValidator validator = new DevfileSchemaValidator(new DevfileSchemaProvider());
|
||||
DevfileSchemaValidator validator =
|
||||
new DevfileSchemaValidator(new DevfileSchemaProvider(), new DevfileVersionDetector());
|
||||
|
||||
Map<String, ComponentIntegrityValidator> validators = new HashMap<>();
|
||||
validators.put(EDITOR_COMPONENT_TYPE, new NoopComponentIntegrityValidator());
|
||||
|
|
@ -78,7 +80,8 @@ public class DefaultFactoryParameterResolverTest {
|
|||
|
||||
DevfileParser devfileParser = new DevfileParser(validator, integrityValidator);
|
||||
|
||||
URLFactoryBuilder factoryBuilder = new URLFactoryBuilder("editor", "plugin", devfileParser);
|
||||
URLFactoryBuilder factoryBuilder =
|
||||
new URLFactoryBuilder("editor", "plugin", devfileParser, new DevfileVersionDetector());
|
||||
|
||||
DefaultFactoryParameterResolver res =
|
||||
new DefaultFactoryParameterResolver(factoryBuilder, urlFetcher);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import static org.eclipse.che.api.workspace.server.devfile.Constants.KUBERNETES_
|
|||
import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_EDITOR_ATTRIBUTE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_TOOLING_PLUGINS_ATTRIBUTE;
|
||||
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.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
|
@ -25,16 +26,23 @@ import static org.mockito.Mockito.when;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl.DevfileLocation;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDevfileV2Dto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryDto;
|
||||
import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto;
|
||||
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.FileContentProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
|
|
@ -68,12 +76,15 @@ public class URLFactoryBuilderTest {
|
|||
|
||||
@Mock private DevfileParser devfileParser;
|
||||
|
||||
@Mock private DevfileVersionDetector devfileVersionDetector;
|
||||
|
||||
/** Tested instance. */
|
||||
private URLFactoryBuilder urlFactoryBuilder;
|
||||
|
||||
@BeforeClass
|
||||
public void setUp() {
|
||||
this.urlFactoryBuilder = new URLFactoryBuilder(defaultEditor, defaultPlugin, devfileParser);
|
||||
this.urlFactoryBuilder =
|
||||
new URLFactoryBuilder(defaultEditor, defaultPlugin, devfileParser, devfileVersionDetector);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -103,9 +114,12 @@ public class URLFactoryBuilderTest {
|
|||
workspaceConfigImpl.setDefaultEnv("name");
|
||||
|
||||
when(urlFetcher.fetchSafely(anyString())).thenReturn("random_content");
|
||||
when(devfileParser.parseYaml(anyString(), anyMap())).thenReturn(devfile);
|
||||
when(devfileParser.parseYamlRaw(anyString()))
|
||||
.thenReturn(new ObjectNode(JsonNodeFactory.instance));
|
||||
when(devfileParser.parseJsonNode(any(JsonNode.class), anyMap())).thenReturn(devfile);
|
||||
when(devfileVersionDetector.devfileMajorVersion(any(JsonNode.class))).thenReturn(1);
|
||||
|
||||
FactoryDto factory =
|
||||
FactoryMetaDto factory =
|
||||
urlFactoryBuilder
|
||||
.createFactoryFromDevfile(
|
||||
new DefaultFactoryUrl().withDevfileFileLocation(myLocation),
|
||||
|
|
@ -115,6 +129,67 @@ public class URLFactoryBuilderTest {
|
|||
|
||||
assertNotNull(factory);
|
||||
assertNull(factory.getSource());
|
||||
assertTrue(factory instanceof FactoryDto);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDevfileV2() throws BadRequestException, DevfileException {
|
||||
String myLocation = "http://foo-location/";
|
||||
Map<String, Object> devfileAsMap = Map.of("hello", "there", "how", "are", "you", "?");
|
||||
|
||||
JsonNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
when(devfileParser.parseYamlRaw(anyString())).thenReturn(devfile);
|
||||
when(devfileParser.convertYamlToMap(devfile)).thenReturn(devfileAsMap);
|
||||
when(devfileVersionDetector.devfileMajorVersion(devfile)).thenReturn(2);
|
||||
|
||||
FactoryMetaDto factory =
|
||||
urlFactoryBuilder
|
||||
.createFactoryFromDevfile(
|
||||
new DefaultFactoryUrl().withDevfileFileLocation(myLocation),
|
||||
s -> myLocation + ".list",
|
||||
emptyMap())
|
||||
.get();
|
||||
|
||||
assertNotNull(factory);
|
||||
assertNull(factory.getSource());
|
||||
assertTrue(factory instanceof FactoryDevfileV2Dto);
|
||||
assertEquals(((FactoryDevfileV2Dto) factory).getDevfile(), devfileAsMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDevfileV2WithFilename() throws BadRequestException, DevfileException {
|
||||
String myLocation = "http://foo-location/";
|
||||
Map<String, Object> devfileAsMap = Map.of("hello", "there", "how", "are", "you", "?");
|
||||
|
||||
JsonNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
when(devfileParser.parseYamlRaw(anyString())).thenReturn(devfile);
|
||||
when(devfileParser.convertYamlToMap(devfile)).thenReturn(devfileAsMap);
|
||||
when(devfileVersionDetector.devfileMajorVersion(devfile)).thenReturn(2);
|
||||
|
||||
RemoteFactoryUrl githubLikeRemoteUrl =
|
||||
() ->
|
||||
Collections.singletonList(
|
||||
new DevfileLocation() {
|
||||
@Override
|
||||
public Optional<String> filename() {
|
||||
return Optional.of("devfile.yaml");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String location() {
|
||||
return myLocation;
|
||||
}
|
||||
});
|
||||
|
||||
FactoryMetaDto factory =
|
||||
urlFactoryBuilder
|
||||
.createFactoryFromDevfile(githubLikeRemoteUrl, s -> myLocation + ".list", emptyMap())
|
||||
.get();
|
||||
|
||||
assertNotNull(factory);
|
||||
assertEquals(factory.getSource(), "devfile.yaml");
|
||||
assertTrue(factory instanceof FactoryDevfileV2Dto);
|
||||
assertEquals(((FactoryDevfileV2Dto) factory).getDevfile(), devfileAsMap);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
|
|
@ -145,8 +220,7 @@ public class URLFactoryBuilderTest {
|
|||
|
||||
@Test(dataProvider = "devfiles")
|
||||
public void checkThatDtoHasCorrectNames(DevfileImpl devfile, String expectedGenerateName)
|
||||
throws BadRequestException, ServerException, DevfileException, IOException,
|
||||
OverrideParameterException {
|
||||
throws BadRequestException, DevfileException, IOException, OverrideParameterException {
|
||||
DefaultFactoryUrl defaultFactoryUrl = mock(DefaultFactoryUrl.class);
|
||||
FileContentProvider fileContentProvider = mock(FileContentProvider.class);
|
||||
when(defaultFactoryUrl.devfileFileLocations())
|
||||
|
|
@ -163,12 +237,16 @@ public class URLFactoryBuilderTest {
|
|||
return "http://foo.bar/anything";
|
||||
}
|
||||
}));
|
||||
when(devfileParser.parseYaml(anyString(), anyMap())).thenReturn(devfile);
|
||||
when(fileContentProvider.fetchContent(anyString())).thenReturn("anything");
|
||||
when(devfileParser.parseYamlRaw("anything"))
|
||||
.thenReturn(new ObjectNode(JsonNodeFactory.instance));
|
||||
when(devfileParser.parseJsonNode(any(JsonNode.class), anyMap())).thenReturn(devfile);
|
||||
when(devfileVersionDetector.devfileMajorVersion(any(JsonNode.class))).thenReturn(1);
|
||||
FactoryDto factory =
|
||||
urlFactoryBuilder
|
||||
.createFactoryFromDevfile(defaultFactoryUrl, fileContentProvider, emptyMap())
|
||||
.get();
|
||||
(FactoryDto)
|
||||
urlFactoryBuilder
|
||||
.createFactoryFromDevfile(defaultFactoryUrl, fileContentProvider, emptyMap())
|
||||
.get();
|
||||
|
||||
assertNull(factory.getDevfile().getMetadata().getName());
|
||||
assertEquals(factory.getDevfile().getMetadata().getGenerateName(), expectedGenerateName);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
package org.eclipse.che.api.workspace.server.devfile;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Constants {
|
||||
|
|
@ -24,8 +23,7 @@ public class Constants {
|
|||
|
||||
public static final String CURRENT_API_VERSION = "1.0.0";
|
||||
|
||||
public static final List<String> SUPPORTED_VERSIONS =
|
||||
Collections.singletonList(CURRENT_API_VERSION);
|
||||
public static final List<String> SUPPORTED_VERSIONS = List.of(CURRENT_API_VERSION, "2.0.0");
|
||||
|
||||
public static final String EDITOR_COMPONENT_TYPE = "cheEditor";
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import static org.eclipse.che.api.workspace.server.devfile.Constants.KUBERNETES_
|
|||
import static org.eclipse.che.api.workspace.server.devfile.Constants.OPENSHIFT_COMPONENT_TYPE;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
|
|
@ -47,8 +48,8 @@ import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl;
|
|||
@Singleton
|
||||
public class DevfileParser {
|
||||
|
||||
private ObjectMapper yamlMapper;
|
||||
private ObjectMapper jsonMapper;
|
||||
private final ObjectMapper yamlMapper;
|
||||
private final ObjectMapper jsonMapper;
|
||||
private final DevfileSchemaValidator schemaValidator;
|
||||
private final DevfileIntegrityValidator integrityValidator;
|
||||
private final OverridePropertiesApplier overridePropertiesApplier;
|
||||
|
|
@ -87,7 +88,7 @@ public class DevfileParser {
|
|||
*/
|
||||
public DevfileImpl parseYaml(String devfileContent) throws DevfileFormatException {
|
||||
try {
|
||||
return parse(devfileContent, yamlMapper, emptyMap());
|
||||
return parse(parseYamlRaw(devfileContent), yamlMapper, emptyMap());
|
||||
} catch (OverrideParameterException e) {
|
||||
// should never happen as we send empty overrides map
|
||||
throw new RuntimeException(e.getMessage());
|
||||
|
|
@ -95,28 +96,56 @@ public class DevfileParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates {@link DevfileImpl} from given devfile content in YAML and provides possibility to
|
||||
* override its values using key-value map, where key is an json-pointer-like string and value is
|
||||
* desired property value. NOTE: unlike json pointers, objects in arrays should be pointed by
|
||||
* their names, not by index. Examples:
|
||||
* Tries to parse given `yaml` into {@link JsonNode} and validates it with devfile schema.
|
||||
*
|
||||
* @param yaml to parse
|
||||
* @return parsed yaml
|
||||
* @throws DevfileFormatException if given yaml is empty or is not valid devfile
|
||||
*/
|
||||
public JsonNode parseYamlRaw(String yaml) throws DevfileFormatException {
|
||||
try {
|
||||
JsonNode devfileJson = yamlMapper.readTree(yaml);
|
||||
if (devfileJson == null) {
|
||||
throw new DevfileFormatException("Unable to parse Devfile - provided source is empty");
|
||||
}
|
||||
return devfileJson;
|
||||
} catch (JsonProcessingException jpe) {
|
||||
throw new DevfileFormatException("Can't parse devfile yaml.", jpe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* converts given devfile in {@link JsonNode} into {@link Map}.
|
||||
*
|
||||
* @param devfileJson json with devfile content
|
||||
* @return devfile in simple Map structure
|
||||
*/
|
||||
public Map<String, Object> convertYamlToMap(JsonNode devfileJson) {
|
||||
return yamlMapper.convertValue(devfileJson, new TypeReference<>() {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse given devfile in {@link JsonNode} format into our {@link DevfileImpl} and provides
|
||||
* possibility to override its values using key-value map, where key is an json-pointer-like
|
||||
* string and value is desired property value. NOTE: unlike json pointers, objects in arrays
|
||||
* should be pointed by their names, not by index. Examples:
|
||||
*
|
||||
* <ul>
|
||||
* <li>metadata.generateName : python-dev-
|
||||
* <li>projects.foo.source.type : git // foo is an project name
|
||||
* </ul>
|
||||
*
|
||||
* Performs schema and integrity validation of input data.
|
||||
* <p>Performs schema and integrity validation of input data.
|
||||
*
|
||||
* @param devfileContent raw content of devfile
|
||||
* @param overrideProperties map of overridden values
|
||||
* @return Devfile object created from the source content
|
||||
* @throws DevfileFormatException when any of schema or integrity validations fail
|
||||
* @throws DevfileFormatException when any yaml parsing error occurs
|
||||
* @throws OverrideParameterException when override properties is incorrect
|
||||
* @param devfile devfile parsed in Json
|
||||
* @param overrideProperties properties to override
|
||||
* @return devfile created from given {@link JsonNode}
|
||||
* @throws OverrideParameterException when any error when overriding parameters
|
||||
* @throws DevfileFormatException when given devfile is not valid devfile
|
||||
*/
|
||||
public DevfileImpl parseYaml(String devfileContent, Map<String, String> overrideProperties)
|
||||
throws DevfileFormatException, OverrideParameterException {
|
||||
return parse(devfileContent, yamlMapper, overrideProperties);
|
||||
public DevfileImpl parseJsonNode(JsonNode devfile, Map<String, String> overrideProperties)
|
||||
throws OverrideParameterException, DevfileFormatException {
|
||||
return parse(devfile, jsonMapper, overrideProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -137,31 +166,6 @@ public class DevfileParser {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link DevfileImpl} from given devfile content in JSON and provides possibility to
|
||||
* override its values using key-value map, where key is an json-pointer-like string and value is
|
||||
* desired property value. NOTE: unlike json pointers, objects in arrays should be pointed by
|
||||
* their names, not by index. Examples:
|
||||
*
|
||||
* <ul>
|
||||
* <li>metadata.generateName : python-dev-
|
||||
* <li>projects.foo.source.type : git // foo is an project name
|
||||
* </ul>
|
||||
*
|
||||
* Performs schema and integrity validation of input data.
|
||||
*
|
||||
* @param devfileContent raw content of devfile
|
||||
* @param overrideProperties map of overridden values
|
||||
* @return Devfile object created from the source content
|
||||
* @throws DevfileFormatException when any of schema or integrity validations fail
|
||||
* @throws DevfileFormatException when any yaml parsing error occurs
|
||||
* @throws OverrideParameterException when override properties is incorrect
|
||||
*/
|
||||
public DevfileImpl parseJson(String devfileContent, Map<String, String> overrideProperties)
|
||||
throws DevfileFormatException, OverrideParameterException {
|
||||
return parse(devfileContent, jsonMapper, overrideProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve devfile component references into their reference content.
|
||||
*
|
||||
|
|
@ -196,19 +200,26 @@ public class DevfileParser {
|
|||
private DevfileImpl parse(
|
||||
String content, ObjectMapper mapper, Map<String, String> overrideProperties)
|
||||
throws DevfileFormatException, OverrideParameterException {
|
||||
try {
|
||||
return parse(mapper.readTree(content), mapper, overrideProperties);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new DevfileFormatException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private DevfileImpl parse(
|
||||
JsonNode parsed, ObjectMapper mapper, Map<String, String> overrideProperties)
|
||||
throws DevfileFormatException, OverrideParameterException {
|
||||
if (parsed == null) {
|
||||
throw new DevfileFormatException("Unable to parse Devfile - provided source is empty");
|
||||
}
|
||||
DevfileImpl devfile;
|
||||
try {
|
||||
JsonNode parsed = mapper.readTree(content);
|
||||
if (parsed == null) {
|
||||
throw new DevfileFormatException("Unable to parse Devfile - provided source is empty");
|
||||
}
|
||||
parsed = overridePropertiesApplier.applyPropertiesOverride(parsed, overrideProperties);
|
||||
schemaValidator.validate(parsed);
|
||||
devfile = mapper.treeToValue(parsed, DevfileImpl.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new DevfileFormatException(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new DevfileFormatException("Unable to parse Devfile. Error: " + e.getMessage());
|
||||
}
|
||||
integrityValidator.validateDevfile(devfile);
|
||||
return devfile;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.workspace.server.devfile;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import javax.inject.Singleton;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
|
||||
/** Class that helps determine devfile versions. */
|
||||
@Singleton
|
||||
public class DevfileVersionDetector {
|
||||
|
||||
private final String DEVFILE_V1_VERSION_FIELD = "apiVersion";
|
||||
private final String DEVFILE_V2_VERSION_FIELD = "schemaVersion";
|
||||
|
||||
/**
|
||||
* Gives exact version of the devfile.
|
||||
*
|
||||
* @param devfile to inspect
|
||||
* @return exact version of the devfile
|
||||
* @throws DevfileException when can't find the field with version
|
||||
*/
|
||||
public String devfileVersion(JsonNode devfile) throws DevfileException {
|
||||
final String version;
|
||||
if (devfile.has(DEVFILE_V1_VERSION_FIELD)) {
|
||||
version = devfile.get(DEVFILE_V1_VERSION_FIELD).asText();
|
||||
} else if (devfile.has(DEVFILE_V2_VERSION_FIELD)) {
|
||||
version = devfile.get(DEVFILE_V2_VERSION_FIELD).asText();
|
||||
} else {
|
||||
throw new DevfileException(
|
||||
"Neither of `apiVersion` or `schemaVersion` found. This is not a valid devfile.");
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives major version of the devfile.
|
||||
*
|
||||
* <pre>
|
||||
* 1 -> 1
|
||||
* 1.0.0 -> 1
|
||||
* 1.99 -> 1
|
||||
* 2.0.0 -> 2
|
||||
* 2.1 -> 2
|
||||
* a.a -> DevfileException
|
||||
* a -> DevfileException
|
||||
* </pre>
|
||||
*
|
||||
* @param devfile to inspect
|
||||
* @return major version of the devfile
|
||||
* @throws DevfileException when can't find the field with version
|
||||
*/
|
||||
public int devfileMajorVersion(JsonNode devfile) throws DevfileException {
|
||||
String version = devfileVersion(devfile);
|
||||
|
||||
int dot = version.indexOf(".");
|
||||
final String majorVersion = dot > 0 ? version.substring(0, dot) : version;
|
||||
try {
|
||||
return Integer.parseInt(majorVersion);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new DevfileException(
|
||||
"Unable to parse devfile version. This is not a valid devfile.", nfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,8 @@ import java.util.Map;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.json.JsonReader;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileVersionDetector;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;
|
||||
import org.eclipse.che.api.workspace.server.devfile.schema.DevfileSchemaProvider;
|
||||
import org.leadpony.justify.api.JsonSchema;
|
||||
|
|
@ -36,15 +38,19 @@ import org.leadpony.justify.api.ProblemHandler;
|
|||
@Singleton
|
||||
public class DevfileSchemaValidator {
|
||||
|
||||
private final JsonValidationService service = JsonValidationService.newInstance();
|
||||
private ObjectMapper jsonMapper;
|
||||
private Map<String, JsonSchema> schemasByVersion;
|
||||
private ErrorMessageComposer errorMessageComposer;
|
||||
private final JsonValidationService service;
|
||||
private final ObjectMapper jsonMapper;
|
||||
private final Map<String, JsonSchema> schemasByVersion;
|
||||
private final ErrorMessageComposer errorMessageComposer;
|
||||
private final DevfileVersionDetector devfileVersionDetector;
|
||||
|
||||
@Inject
|
||||
public DevfileSchemaValidator(DevfileSchemaProvider schemaProvider) {
|
||||
public DevfileSchemaValidator(
|
||||
DevfileSchemaProvider schemaProvider, DevfileVersionDetector devfileVersionDetector) {
|
||||
this.service = JsonValidationService.newInstance();
|
||||
this.jsonMapper = new ObjectMapper();
|
||||
this.errorMessageComposer = new ErrorMessageComposer();
|
||||
this.devfileVersionDetector = devfileVersionDetector;
|
||||
try {
|
||||
this.schemasByVersion = new HashMap<>();
|
||||
for (String version : SUPPORTED_VERSIONS) {
|
||||
|
|
@ -59,19 +65,15 @@ public class DevfileSchemaValidator {
|
|||
try {
|
||||
List<Problem> validationErrors = new ArrayList<>();
|
||||
ProblemHandler handler = ProblemHandler.collectingTo(validationErrors);
|
||||
if (!contentNode.hasNonNull("apiVersion")) {
|
||||
throw new DevfileFormatException(
|
||||
"Devfile schema validation failed. Error: The object must have a property whose name is \"apiVersion\".");
|
||||
}
|
||||
String apiVersion = contentNode.get("apiVersion").asText();
|
||||
String devfileVersion = devfileVersionDetector.devfileVersion(contentNode);
|
||||
|
||||
if (!schemasByVersion.containsKey(apiVersion)) {
|
||||
if (!schemasByVersion.containsKey(devfileVersion)) {
|
||||
throw new DevfileFormatException(
|
||||
String.format(
|
||||
"Version '%s' of the devfile is not supported. Supported versions are '%s'.",
|
||||
apiVersion, SUPPORTED_VERSIONS));
|
||||
devfileVersion, SUPPORTED_VERSIONS));
|
||||
}
|
||||
JsonSchema schema = schemasByVersion.get(apiVersion);
|
||||
JsonSchema schema = schemasByVersion.get(devfileVersion);
|
||||
try (JsonReader reader =
|
||||
service.createReader(
|
||||
new StringReader(jsonMapper.writeValueAsString(contentNode)), schema, handler)) {
|
||||
|
|
@ -79,9 +81,11 @@ public class DevfileSchemaValidator {
|
|||
}
|
||||
if (!validationErrors.isEmpty()) {
|
||||
String error = errorMessageComposer.extractMessages(validationErrors, new StringBuilder());
|
||||
throw new DevfileFormatException(
|
||||
format("Devfile schema validation failed. Error: %s", error));
|
||||
throw new DevfileFormatException(error);
|
||||
}
|
||||
} catch (DevfileException dfe) {
|
||||
throw new DevfileFormatException(
|
||||
format("Devfile schema validation failed. Error: %s", dfe.getMessage()));
|
||||
} catch (IOException e) {
|
||||
throw new DevfileFormatException("Unable to validate Devfile. Error: " + e.getMessage());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"description": "This is a temporary dummy structure for devfile 2.0.0.",
|
||||
"type": "object",
|
||||
"title": "Devfile schema - Version 2.0.0",
|
||||
"required": [
|
||||
"schemaVersion"
|
||||
]
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ import org.eclipse.che.api.core.rest.CheJsonProvider;
|
|||
import org.eclipse.che.api.core.rest.shared.dto.ServiceError;
|
||||
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.URLFetcher;
|
||||
import org.eclipse.che.api.workspace.server.devfile.schema.DevfileSchemaProvider;
|
||||
import org.eclipse.che.api.workspace.server.devfile.validator.DevfileIntegrityValidator;
|
||||
|
|
@ -152,7 +153,7 @@ public class WorkspaceServiceTest {
|
|||
private DevfileEntityProvider devfileEntityProvider =
|
||||
new DevfileEntityProvider(
|
||||
new DevfileParser(
|
||||
new DevfileSchemaValidator(new DevfileSchemaProvider()),
|
||||
new DevfileSchemaValidator(new DevfileSchemaProvider(), new DevfileVersionDetector()),
|
||||
new DevfileIntegrityValidator(Collections.emptyMap())));
|
||||
|
||||
@Mock private WorkspaceManager wsManager;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.workspace.server.devfile;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class DevfileVersionTest {
|
||||
private final DevfileVersionDetector devfileVersionDetector = new DevfileVersionDetector();
|
||||
|
||||
@Test(expectedExceptions = DevfileException.class)
|
||||
public void shouldThrowExceptionWhenEmptyDevfile() throws DevfileException {
|
||||
JsonNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfileVersionDetector.devfileVersion(devfile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnApiVersion() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", "1.1.1");
|
||||
assertEquals(devfileVersionDetector.devfileVersion(devfile), "1.1.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnSchemaVersion() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("schemaVersion", "1.1.1");
|
||||
assertEquals(devfileVersionDetector.devfileVersion(devfile), "1.1.1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnApiVersionWhenBothDefined() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", "1");
|
||||
devfile.put("schemaVersion", "2");
|
||||
assertEquals(devfileVersionDetector.devfileVersion(devfile), "1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMainVersionFromSchemaVersion() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("schemaVersion", "10.1.1");
|
||||
assertEquals(devfileVersionDetector.devfileMajorVersion(devfile), 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMainVersionFromApiVersion() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", "11.1.1");
|
||||
assertEquals(devfileVersionDetector.devfileMajorVersion(devfile), 11);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = DevfileException.class)
|
||||
public void shouldThrowExceptionWhenVersionNotDefined() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfileVersionDetector.devfileMajorVersion(devfile);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMajorVersionWhenIsNumberString() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", "2");
|
||||
assertEquals(devfileVersionDetector.devfileMajorVersion(devfile), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnMajorVersionWhenIsNumber() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", 2);
|
||||
assertEquals(devfileVersionDetector.devfileMajorVersion(devfile), 2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = DevfileException.class)
|
||||
public void shouldThrowExceptionWhenVersionIsNotNumber() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", "a");
|
||||
devfileVersionDetector.devfileMajorVersion(devfile);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = DevfileException.class)
|
||||
public void shouldThrowExceptionWhenVersionIsNotSemverNumber() throws DevfileException {
|
||||
ObjectNode devfile = new ObjectNode(JsonNodeFactory.instance);
|
||||
devfile.put("apiVersion", "a.a");
|
||||
devfileVersionDetector.devfileMajorVersion(devfile);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import java.io.IOException;
|
||||
import org.eclipse.che.api.workspace.server.devfile.Constants;
|
||||
import org.eclipse.che.api.workspace.server.devfile.DevfileVersionDetector;
|
||||
import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException;
|
||||
import org.eclipse.che.api.workspace.server.devfile.schema.DevfileSchemaProvider;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
|
@ -34,7 +35,8 @@ public class DevfileSchemaValidatorTest {
|
|||
@BeforeClass
|
||||
public void setUp() {
|
||||
yamlMapper = new ObjectMapper(new YAMLFactory());
|
||||
schemaValidator = new DevfileSchemaValidator(new DevfileSchemaProvider());
|
||||
schemaValidator =
|
||||
new DevfileSchemaValidator(new DevfileSchemaProvider(), new DevfileVersionDetector());
|
||||
}
|
||||
|
||||
@Test(dataProvider = "validDevfiles")
|
||||
|
|
@ -76,6 +78,7 @@ public class DevfileSchemaValidatorTest {
|
|||
{"devfile/devfile_name_and_generatename.yaml"},
|
||||
{"devfile/devfile_with_sparse_checkout_dir.yaml"},
|
||||
{"devfile/devfile_name_and_generatename.yaml"},
|
||||
{"devfile/devfile_v2_just_schemaVersion.yaml"},
|
||||
{"command/devfile_command_with_preview_url.yaml"},
|
||||
{"command/devfile_command_with_preview_url_only_port.yaml"},
|
||||
};
|
||||
|
|
@ -105,7 +108,7 @@ public class DevfileSchemaValidatorTest {
|
|||
} catch (DevfileFormatException e) {
|
||||
assertEquals(
|
||||
e.getMessage(),
|
||||
"Version '111.111' of the devfile is not supported. "
|
||||
"Devfile schema validation failed. Error: Version '111.111' of the devfile is not supported. "
|
||||
+ "Supported versions are '"
|
||||
+ Constants.SUPPORTED_VERSIONS
|
||||
+ "'.");
|
||||
|
|
@ -136,7 +139,7 @@ public class DevfileSchemaValidatorTest {
|
|||
},
|
||||
{
|
||||
"devfile/devfile_missing_api_version.yaml",
|
||||
"The object must have a property whose name is \"apiVersion\"."
|
||||
"Neither of `apiVersion` or `schemaVersion` found. This is not a valid devfile."
|
||||
},
|
||||
{
|
||||
"devfile/devfile_with_undeclared_field.yaml",
|
||||
|
|
@ -253,6 +256,14 @@ public class DevfileSchemaValidatorTest {
|
|||
"command/devfile_command_with_preview_url_only_path.yaml",
|
||||
"(/commands/0/previewUrl):The object must have a property whose name is \"port\"."
|
||||
},
|
||||
{
|
||||
"devfile/devfile_v2_invalid_schemaVersion.yaml",
|
||||
"Version 'a.b.c' of the devfile is not supported. Supported versions are '[1.0.0, 2.0.0]'."
|
||||
},
|
||||
{
|
||||
"devfile/devfile_v2_unsupported_schemaVersion.yaml",
|
||||
"Version '22.33.44' of the devfile is not supported. Supported versions are '[1.0.0, 2.0.0]'."
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
---
|
||||
schemaVersion: a.b.c
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
---
|
||||
schemaVersion: 2.0.0
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# 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
|
||||
#
|
||||
|
||||
---
|
||||
schemaVersion: 22.33.44
|
||||
Loading…
Reference in New Issue