Skip to content

Commit

Permalink
Merge pull request #1056 from mkuznyetsov/CODENVY-365
Browse files Browse the repository at this point in the history
CODENVY-365 Allow factory to contain projects with keepDir function
  • Loading branch information
Michail Kuznetsov committed Apr 15, 2016
2 parents 862e7cf + ceab81a commit e94589e
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,12 @@ public RegisteredProject importProject(String path, SourceStorage sourceStorage,
List<? extends ProjectConfig> projects = workspaceConfig.getProjects();
for (ProjectConfig project : projects) {
if (normalizePath.equals(project.getPath())) {
// TODO Needed for factory project importing with keepDir. It needs to find more appropriate solution
List<String> innerProjects = projectRegistry.getProjects(normalizePath);
for (String innerProject : innerProjects) {
RegisteredProject registeredProject = projectRegistry.getProject(innerProject);
projectRegistry.putProject(registeredProject, asFolder(registeredProject.getPath()), true, false);
}
return projectRegistry.putProject(project, folder, true, false);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.factory.server.builder.FactoryBuilder;
Expand Down Expand Up @@ -596,10 +597,17 @@ private List<Link> createLinks(Factory factory, Set<FactoryImage> images, UriInf
private void excludeProjectsWithoutLocation(WorkspaceImpl usersWorkspace, String projectPath) throws BadRequestException {
final boolean notEmptyPath = projectPath != null;
//Condition for sifting valid project in user's workspace
Predicate<ProjectConfigImpl> predicate = projectConfig -> !(notEmptyPath && !projectPath.equals(projectConfig.getPath()))
&& projectConfig.getSource() != null
&& !isNullOrEmpty(projectConfig.getSource().getType())
&& !isNullOrEmpty(projectConfig.getSource().getLocation());
Predicate<ProjectConfigImpl> predicate = projectConfig -> {
// if project is a subproject (it's path contains another project) , then location can be null
final boolean isSubProject = projectConfig.getPath().indexOf('/', 1) != -1;
final boolean hasNotEmptySource = projectConfig.getSource() != null
&& projectConfig.getSource().getType() != null
&& projectConfig.getSource().getLocation() != null;

return !(notEmptyPath && !projectPath.equals(projectConfig.getPath()))
&& (isSubProject ? true : hasNotEmptySource);
};

//Filtered out projects by path and source storage presence.
final List<ProjectConfigImpl> filtered = usersWorkspace.getConfig()
.getProjects()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.eclipse.che.api.core.ApiException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.factory.FactoryParameter;
import org.eclipse.che.api.core.model.project.ProjectConfig;
import org.eclipse.che.api.core.model.project.SourceStorage;
import org.eclipse.che.api.factory.server.FactoryConstants;
import org.eclipse.che.api.factory.server.LegacyConverter;
Expand Down Expand Up @@ -144,7 +145,7 @@ public void checkValid(Factory factory) throws ConflictException {
default:
throw new ConflictException(FactoryConstants.INVALID_VERSION_MESSAGE);
}
validateCompatibility(factory, Factory.class, usedFactoryVersionMethodProvider, v, "");
validateCompatibility(factory, null, Factory.class, usedFactoryVersionMethodProvider, v, "");
}

/**
Expand All @@ -169,6 +170,8 @@ public Factory convertToLatest(Factory factory) throws ApiException {
*
* @param object
* - object to validate factory parameters
* @param object
* - parent object
* @param methodsProvider
* - class that provides methods with {@link org.eclipse.che.api.core.factory.FactoryParameter}
* annotations
Expand All @@ -181,12 +184,13 @@ public Factory convertToLatest(Factory factory) throws ApiException {
* @throws org.eclipse.che.api.core.ConflictException
*/
void validateCompatibility(Object object,
Object parent,
Class methodsProvider,
Class allowedMethodsProvider,
Version version,
String parentName) throws ConflictException {
// validate source
if (SourceStorageDto.class.equals(methodsProvider)) {
if (SourceStorageDto.class.equals(methodsProvider) && !hasSubprojectInPath(parent)) {
sourceStorageParametersValidator.validate((SourceStorage)object, version);
}

Expand Down Expand Up @@ -239,7 +243,7 @@ void validateCompatibility(Object object,
// use recursion if parameter is DTO object
if (method.getReturnType().isAnnotationPresent(DTO.class)) {
// validate inner objects such Git ot ProjectAttributes
validateCompatibility(parameterValue, method.getReturnType(), method.getReturnType(), version, fullName);
validateCompatibility(parameterValue, object, method.getReturnType(), method.getReturnType(), version, fullName);
} else if (Map.class.isAssignableFrom(method.getReturnType())) {
Type tp = ((ParameterizedType)method.getGenericReturnType()).getActualTypeArguments()[1];

Expand All @@ -248,7 +252,7 @@ void validateCompatibility(Object object,
if (secMapParamClass.isAnnotationPresent(DTO.class)) {
Map<Object, Object> map = (Map)parameterValue;
for (Map.Entry<Object, Object> entry : map.entrySet()) {
validateCompatibility(entry.getValue(), secMapParamClass, secMapParamClass, version,
validateCompatibility(entry.getValue(), object, secMapParamClass, secMapParamClass, version,
fullName + "." + entry.getKey());
}
} else {
Expand All @@ -263,7 +267,7 @@ void validateCompatibility(Object object,
if (secListParamClass.isAnnotationPresent(DTO.class)) {
List<Object> list = (List)parameterValue;
for (Object entry : list) {
validateCompatibility(entry, secListParamClass, secListParamClass, version, fullName);
validateCompatibility(entry, object, secListParamClass, secListParamClass, version, fullName);
}
} else {
throw new RuntimeException("This type of fields is not supported by factory.");
Expand All @@ -273,4 +277,10 @@ void validateCompatibility(Object object,
}
}
}

private boolean hasSubprojectInPath(Object parent) {
return parent != null
&& ProjectConfig.class.isAssignableFrom(parent.getClass())
&& ((ProjectConfig)parent).getPath().indexOf('/', 1) != -1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,24 @@ protected void validateProjects(Factory factory) throws BadRequestException {
"digits or these following special characters -._.");
}

final String location = project.getSource().getLocation();
final String parameterLocationName = "project.storage.location";
if (isNullOrEmpty(location)) {
throw new BadRequestException(format(FactoryConstants.PARAMETRIZED_ILLEGAL_PARAMETER_VALUE_MESSAGE,
parameterLocationName,
location));
}
try {
URLDecoder.decode(location, "UTF-8");
} catch (IllegalArgumentException | UnsupportedEncodingException e) {
throw new BadRequestException(format(FactoryConstants.PARAMETRIZED_ILLEGAL_PARAMETER_VALUE_MESSAGE,
parameterLocationName,
location));
if (project.getPath().indexOf('/', 1) == -1) {

final String location = project.getSource().getLocation();
final String parameterLocationName = "project.source.location";

if (isNullOrEmpty(location)) {
throw new BadRequestException(format(FactoryConstants.PARAMETRIZED_ILLEGAL_PARAMETER_VALUE_MESSAGE,
parameterLocationName,
location));
}

try {
URLDecoder.decode(location, "UTF-8");
} catch (IllegalArgumentException | UnsupportedEncodingException e) {
throw new BadRequestException(format(FactoryConstants.PARAMETRIZED_ILLEGAL_PARAMETER_VALUE_MESSAGE,
parameterLocationName,
location));
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -963,11 +963,13 @@ public void shouldGenerateFactoryJsonIncludeAllProjects() throws Exception {
wsConfig.setProjects(Arrays.asList(dto.createDto(ProjectConfigDto.class)
.withSource(dto.createDto(SourceStorageDto.class)
.withType("git")
.withLocation("location")),
.withLocation("location"))
.withPath("path"),
dto.createDto(ProjectConfigDto.class)
.withSource(dto.createDto(SourceStorageDto.class)
.withType("git")
.withLocation("location"))));
.withLocation("location"))
.withPath("path")));
wsConfig.setName("wsname");
wsConfig.setDefaultEnv("env1");
wsConfig.setEnvironments(Collections.singletonList(dto.createDto(EnvironmentDto.class).withName("env1")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
@Listeners(value = {MockitoTestNGListener.class})
public class FactoryBaseValidatorTest {
private static final String VALID_REPOSITORY_URL = "http://github.com/codenvy/cloudide";
private static final String VALID_PROJECT_PATH = "/cloudide";
private static final String ID = "id";

@Mock
Expand Down Expand Up @@ -105,28 +106,28 @@ public void setUp() throws ParseException, NotFoundException, ServerException {

@Test
public void shouldBeAbleToValidateFactoryUrlObject() throws ApiException {
factory = prepareFactoryWithGivenStorage("git", VALID_REPOSITORY_URL);
factory = prepareFactoryWithGivenStorage("git", VALID_REPOSITORY_URL, VALID_PROJECT_PATH);
validator.validateProjects(factory);
validator.validateProjects(factory);
validator.validateAccountId(factory);
}

@Test
public void shouldBeAbleToValidateFactoryUrlObjectIfStorageIsESBWSO2() throws ApiException {
factory = prepareFactoryWithGivenStorage("esbwso2", VALID_REPOSITORY_URL);
factory = prepareFactoryWithGivenStorage("esbwso2", VALID_REPOSITORY_URL, VALID_PROJECT_PATH);
validator.validateProjects(factory);
validator.validateProjects(factory);
validator.validateAccountId(factory);
}

@Test(expectedExceptions = ApiException.class,
expectedExceptionsMessageRegExp =
"The parameter project.storage.location has a value submitted http://codenvy.com/git/04%2 with a value that is " +
"The parameter project.source.location has a value submitted http://codenvy.com/git/04%2 with a value that is " +
"unexpected. " +
"For more information, please visit http://docs.codenvy.com/user/project-lifecycle/#configuration-reference")
public void shouldNotValidateIfStorageLocationContainIncorrectEncodedSymbol() throws ApiException {
// given
factory = prepareFactoryWithGivenStorage("git", "http://codenvy.com/git/04%2");
factory = prepareFactoryWithGivenStorage("git", "http://codenvy.com/git/04%2", VALID_PROJECT_PATH);

// when, then
validator.validateProjects(factory);
Expand All @@ -136,7 +137,7 @@ public void shouldNotValidateIfStorageLocationContainIncorrectEncodedSymbol() th
@Test
public void shouldValidateIfStorageLocationIsCorrectSsh() throws ApiException {
// given
factory = prepareFactoryWithGivenStorage("git", "ssh://codenvy@review.gerrithub.io:29418/codenvy/exampleProject");
factory = prepareFactoryWithGivenStorage("git", "ssh://codenvy@review.gerrithub.io:29418/codenvy/exampleProject", "example-project");

// when, then
validator.validateProjects(factory);
Expand All @@ -145,7 +146,16 @@ public void shouldValidateIfStorageLocationIsCorrectSsh() throws ApiException {
@Test
public void shouldValidateIfStorageLocationIsCorrectHttps() throws ApiException {
// given
factory = prepareFactoryWithGivenStorage("git","https://github.com/codenvy/example.git");
factory = prepareFactoryWithGivenStorage("git","https://github.com/codenvy/example.git", "/example");

// when, then
validator.validateProjects(factory);
}

@Test
public void shouldValidateSubProjectWithNoLocation() throws ApiException {
// given
factory = prepareFactoryWithGivenStorage("git","null", "/cloudide/core");

// when, then
validator.validateProjects(factory);
Expand All @@ -158,9 +168,9 @@ public void shouldNotValidateIfStorageOrStorageLocationIsInvalid(Factory factory

@DataProvider(name = "badAdvancedFactoryUrlProvider")
public Object[][] invalidParametersFactoryUrlProvider() throws UnsupportedEncodingException {
Factory adv1 = prepareFactoryWithGivenStorage("notagit", VALID_REPOSITORY_URL);
Factory adv2 = prepareFactoryWithGivenStorage("git", null);
Factory adv3 = prepareFactoryWithGivenStorage("git", "");
Factory adv1 = prepareFactoryWithGivenStorage("notagit", VALID_REPOSITORY_URL, VALID_PROJECT_PATH );
Factory adv2 = prepareFactoryWithGivenStorage("git", null, VALID_PROJECT_PATH);
Factory adv3 = prepareFactoryWithGivenStorage("git", "", VALID_PROJECT_PATH);
return new Object[][]{
{adv1},// invalid vcs
{adv2},// invalid vcsurl
Expand All @@ -183,13 +193,14 @@ public void shouldThrowFactoryUrlExceptionIfProjectNameInvalid(String projectNam
@Test(dataProvider = "validProjectNamesProvider")
public void shouldBeAbleToValidateValidProjectName(String projectName) throws Exception {
// given
prepareFactoryWithGivenStorage("git", VALID_REPOSITORY_URL);
prepareFactoryWithGivenStorage("git", VALID_REPOSITORY_URL, VALID_PROJECT_PATH);
factory.withWorkspace(newDto(WorkspaceConfigDto.class).withProjects(
Collections.singletonList(newDto(ProjectConfigDto.class).withType("type")
.withName(projectName)
.withSource(newDto(SourceStorageDto.class)
.withType("git")
.withLocation(VALID_REPOSITORY_URL)))));
.withLocation(VALID_REPOSITORY_URL))
.withPath(VALID_PROJECT_PATH))));
// when, then
validator.validateProjects(factory);
}
Expand Down Expand Up @@ -376,7 +387,7 @@ public void shouldNotValidateIfOpenfileActionInsufficientParams() throws Excepti
//when
validator.validateProjectActions(factoryWithAccountId);
}

@Test(expectedExceptions = BadRequestException.class)
public void shouldNotValidateIfrunCommandActionInsufficientParams() throws Exception {
//given
Expand Down Expand Up @@ -505,12 +516,13 @@ public Object[][] trackedFactoryParameterWithoutValidAccountId() throws URISynta
};
}

private Factory prepareFactoryWithGivenStorage(String type, String location) {
private Factory prepareFactoryWithGivenStorage(String type, String location, String path) {
return factory.withWorkspace(newDto(WorkspaceConfigDto.class)
.withProjects(Collections.singletonList(newDto(ProjectConfigDto.class)
.withSource(newDto(SourceStorageDto.class)
.withType(type)
.withLocation(
location)))));
location))
.withPath(path))));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public interface ProjectConfigDto extends ProjectConfig {
ProjectConfigDto withAttributes(Map<String, List<String>> attributes);

@Override
@FactoryParameter(obligation = MANDATORY)
@FactoryParameter(obligation = OPTIONAL)
SourceStorageDto getSource();

void setSource(SourceStorageDto source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@
import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIONAL;

/**
* TODO Type and location are optional in case it is a subproject, that has an empty source.
*
* @author Alexander Garagatyi
*/
@DTO
public interface SourceStorageDto extends SourceStorage {
@Override
@FactoryParameter(obligation = MANDATORY)
@FactoryParameter(obligation = OPTIONAL)
String getType();

void setType(String type);

SourceStorageDto withType(String type);

@Override
@FactoryParameter(obligation = MANDATORY)
@FactoryParameter(obligation = OPTIONAL)
String getLocation();

void setLocation(String location);
Expand Down

0 comments on commit e94589e

Please sign in to comment.