Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/validate structure #75

Merged
merged 9 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ To use the plugin you need Gradle version 5 or later, to start add the following

```groovy
plugins {
id "co.com.bancolombia.cleanArchitecture" version "1.6.5"
id "co.com.bancolombia.cleanArchitecture" version "1.6.6"
}
```

Expand Down
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
package=co.com.bancolombia
systemProp.version=1.6.5
systemProp.version=1.6.6

Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,25 @@ public void canRunTaskGenerateStructureWithOutParameters() {
assertEquals(result.task(":" + task).getOutcome(), TaskOutcome.SUCCESS);
}

public void canRunTaskGenerateStructureWithOutParametersValidator() {


runner.withArguments("ca");
runner.withProjectDir(projectDir);
runner.build();


runner.withArguments("generateDrivenAdapter", "--type=" + "jpa");
runner.withProjectDir(projectDir);
runner.build();

runner.withArguments("generateDrivenAdapter", "--type=" + "ASYNCEVENTBUS");
runner.withProjectDir(projectDir);
runner.build();

}



@Test
public void canRunTaskGenerateStructureWithParameters() {
Expand Down Expand Up @@ -214,7 +233,9 @@ public void canRunTaskGeneratePipelineAzureDevOpsTest() {

@Test
public void canRunTaskvalidateStructureWithOutParameters() {
canRunTaskGenerateStructureWithOutParameters();
canRunTaskGenerateStructureWithOutParametersValidator();


String task = "validateStructure";

runner.withArguments(task);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/co/com/bancolombia/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Constants {
public static final String SECRETS_VERSION = "2.1.0";
public static final String RCOMMONS_ASYNC_COMMONS_STARTER_VERSION = "0.4.7";
public static final String RCOMMONS_OBJECT_MAPPER_VERSION = "0.1.0";
public static final String PLUGIN_VERSION = "1.6.5";
public static final String PLUGIN_VERSION = "1.6.6";

public enum BooleanOption {
TRUE, FALSE
Expand Down
131 changes: 78 additions & 53 deletions src/main/java/co/com/bancolombia/task/ValidateStructureTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,93 +4,118 @@
import co.com.bancolombia.utils.FileUtils;
import co.com.bancolombia.utils.Utils;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.logging.Logger;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.TaskAction;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Stream;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;

public class ValidateStructureTask extends DefaultTask {
private static final String DOMAIN = "domain";
private static final String MODEL = "model";
private static final String USECASE_FOLDER = "usecase";
private static final String BUILD_GRADLE = "build.gradle";
private Logger logger = getProject().getLogger();
private static final String MODEL_MODULE = "model";
private static final String USE_CASE_MODULE = "usecase";


@TaskAction
public void validateStructureTask() throws IOException, CleanException {

String packageName = FileUtils.readProperties(getProject().getProjectDir().getPath(), "package");
logger.lifecycle("Clean Architecture plugin version: {}", Utils.getVersionPlugin());
getModules().forEach(d -> logger.lifecycle("Submodules: " + d.getKey()));
logger.lifecycle("Project Package: {}", packageName);

if (!validateModelLayer()) {
throw new CleanException("the model layer is invalid");
throw new CleanException("Model module is invalid");
}
if (!validateUseCaseLayer()) {
throw new CleanException("the use case layer is invalid");
throw new CleanException("Use case module is invalid");
}
if (!validateEntryPointLayer()) {
throw new CleanException("the entry point layer is invalid");
}
if (!validateDrivenAdapterLayer()) {
throw new CleanException("the driven adapter layer is invalid");
if (!validateInfrastructureLayer()) {
throw new CleanException("Infrastructure layer is invalid");
}
logger.lifecycle("The project is valid");

}

//TODO: Complete
public boolean validateEntryPointLayer() throws IOException {
List<File> files = FileUtils.finderSubProjects(getProject().getProjectDir().getAbsolutePath().concat("/infrastructure/entry-points"));
for (File file : files) {
logger.lifecycle(file.getCanonicalPath());
private boolean validateModelLayer() {

if (validateExistingModule(MODEL_MODULE)) {
logger.lifecycle("Validating Model Module");
Configuration configuration = getConfiguration(MODEL_MODULE);
return configuration.getAllDependencies().isEmpty();
}
logger.warn("Model module not found");
return true;

}

//TODO: Complete
private boolean validateDrivenAdapterLayer() throws IOException {
List<File> files = FileUtils.finderSubProjects(getProject().getProjectDir().getAbsolutePath().concat("/infrastructure/driven-adapters"));
for (File file : files) {
logger.lifecycle(file.getCanonicalPath());
private boolean validateUseCaseLayer() {
if (validateExistingModule(USE_CASE_MODULE)) {
logger.lifecycle("Validating Use Case Module");
Configuration configuration = getConfiguration(USE_CASE_MODULE);
return configuration.getAllDependencies().size() == 1
&& configuration.getAllDependencies().iterator().next().getName().contains((MODEL_MODULE));
}
logger.warn("Use case module not found");
return true;
}

private boolean validateModelLayer() throws IOException {
Stream<String> stream = FileUtils.readFile(getProject(), DOMAIN.concat("/").concat(MODEL).concat("/").concat(BUILD_GRADLE));
private boolean validateInfrastructureLayer() {
List<String> modulesExcludes = Arrays.asList(MODEL_MODULE, "app-service", USE_CASE_MODULE);
AtomicBoolean valid = new AtomicBoolean(true);
Set<Map.Entry<String, Project>> modules = getModules();

modules.stream().filter(module -> !modulesExcludes.contains(module.getKey()))
.forEach(moduleFiltered -> {
logger.lifecycle(String.format("Validating %s Module", moduleFiltered.getKey()));
validateDependencies(valid, moduleFiltered);
});

long countImplementationproject = stream
.map(line -> line.replaceAll("\\s", ""))
.filter(line -> !line.startsWith("//") && line.contains("implementationproject"))
.count();
return countImplementationproject == 0;
return valid.get();
}

private boolean validateExistingModule(String module) {
return (getProject().getChildProjects().containsKey(module));
}

private boolean validateUseCaseLayer() {
Supplier<Stream<String>> stream = () -> {
try {
return FileUtils.readFile(getProject(), DOMAIN.concat("/").concat(USECASE_FOLDER).concat("/").concat(BUILD_GRADLE));
} catch (IOException e) {
logger.error(e.getMessage());
return null;
}
};

String modelDependency1 = "implementationproject(':model')";
String modelDependency2 = "compileproject(':model')";
boolean isvalid = stream.get().filter(line -> !line.startsWith("//")).map(line -> line.replaceAll("\\s", ""))
.anyMatch(str -> str.equals(modelDependency1) || str.equals(modelDependency2));
long countImplementationproject = stream.get().map(line -> line.replaceAll("\\s", "")).filter(line -> !line.startsWith("//") && line.contains("implementationproject")).count();
long countCompileproject = stream.get().map(line -> line.replaceAll("\\s", "")).filter(line -> !line.startsWith("//") && line.contains("compileproject")).count();

return isvalid && ((countImplementationproject == 1 && countCompileproject == 0) || (countImplementationproject == 0 && countCompileproject == 1));
public Configuration getConfiguration(String moduleName) {
printDependenciesByModule(moduleName);

return getProject()
.getChildProjects()
.get(moduleName)
.getConfigurations()
.getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME);
}

}
private void printDependenciesByModule(String moduleName) {
getProject()
.getChildProjects()
.get(moduleName)
.getConfigurations().getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME).getDependencies().forEach(dependency -> logger.lifecycle("--- Dependency: " + dependency.getName()));
}

private void validateDependencies(AtomicBoolean valid, Map.Entry<String, Project> dependency) {
Configuration configuration = getConfiguration(dependency.getKey());
if (configuration
.getDependencies().stream().anyMatch(filterDependenciesInfrastructure())) {
valid.set(false);
}
}

private Predicate<Dependency> filterDependenciesInfrastructure() {
return dependency -> "app-service"
.contains(dependency.getName()) && !Arrays.asList(MODEL_MODULE, USE_CASE_MODULE)
.contains(dependency.getName());
}


private Set<Map.Entry<String, Project>> getModules() {
return getProject().getChildProjects().entrySet();
}
}
Loading