diff --git a/README.md b/README.md index 518b2c72..1377a1df 100644 --- a/README.md +++ b/README.md @@ -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" } ``` diff --git a/gradle.properties b/gradle.properties index 9b256aac..7be50585 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,3 @@ package=co.com.bancolombia -systemProp.version=1.6.5 +systemProp.version=1.6.6 + diff --git a/src/functionalTest/java/co/com/bancolombia/PluginCleanFunctionalTest.java b/src/functionalTest/java/co/com/bancolombia/PluginCleanFunctionalTest.java index 63a97ec9..e2fe11e7 100644 --- a/src/functionalTest/java/co/com/bancolombia/PluginCleanFunctionalTest.java +++ b/src/functionalTest/java/co/com/bancolombia/PluginCleanFunctionalTest.java @@ -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() { @@ -214,7 +233,9 @@ public void canRunTaskGeneratePipelineAzureDevOpsTest() { @Test public void canRunTaskvalidateStructureWithOutParameters() { - canRunTaskGenerateStructureWithOutParameters(); + canRunTaskGenerateStructureWithOutParametersValidator(); + + String task = "validateStructure"; runner.withArguments(task); diff --git a/src/main/java/co/com/bancolombia/Constants.java b/src/main/java/co/com/bancolombia/Constants.java index 19917775..6bc544eb 100644 --- a/src/main/java/co/com/bancolombia/Constants.java +++ b/src/main/java/co/com/bancolombia/Constants.java @@ -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 diff --git a/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java b/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java index 5623ebf1..e0577c5b 100644 --- a/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java +++ b/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java @@ -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 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 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 stream = FileUtils.readFile(getProject(), DOMAIN.concat("/").concat(MODEL).concat("/").concat(BUILD_GRADLE)); + private boolean validateInfrastructureLayer() { + List modulesExcludes = Arrays.asList(MODEL_MODULE, "app-service", USE_CASE_MODULE); + AtomicBoolean valid = new AtomicBoolean(true); + Set> 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 = () -> { - 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 dependency) { + Configuration configuration = getConfiguration(dependency.getKey()); + if (configuration + .getDependencies().stream().anyMatch(filterDependenciesInfrastructure())) { + valid.set(false); + } + } + private Predicate filterDependenciesInfrastructure() { + return dependency -> "app-service" + .contains(dependency.getName()) && !Arrays.asList(MODEL_MODULE, USE_CASE_MODULE) + .contains(dependency.getName()); + } + + + private Set> getModules() { + return getProject().getChildProjects().entrySet(); + } +} diff --git a/src/test/java/co/com/bancolombia/task/ValidateStructureTaskTest.java b/src/test/java/co/com/bancolombia/task/ValidateStructureTaskTest.java index 10e0d4f3..b15ef83c 100644 --- a/src/test/java/co/com/bancolombia/task/ValidateStructureTaskTest.java +++ b/src/test/java/co/com/bancolombia/task/ValidateStructureTaskTest.java @@ -1,54 +1,151 @@ package co.com.bancolombia.task; import co.com.bancolombia.exceptions.CleanException; -import co.com.bancolombia.task.ValidateStructureTask; +import co.com.bancolombia.factory.adapters.ModuleFactoryDrivenAdapter; import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.JavaPlugin; import org.gradle.testfixtures.ProjectBuilder; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; - +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; +import static org.junit.Assert.*; +@RunWith(MockitoJUnitRunner.class) public class ValidateStructureTaskTest { ValidateStructureTask task; - @Before - public void init() throws IOException, CleanException { - File projectDir = new File("build/unitTest"); - Files.createDirectories(projectDir.toPath()); - writeString(new File(projectDir, "settings.gradle"), ""); - writeString(new File(projectDir, "build.gradle"), - "plugins {" + - " id('co.com.bancolombia.cleanArchitecture')" + - "}"); + public void setupException() throws IOException, CleanException { + Project project = ProjectBuilder.builder() + .withName("cleanArchitecture") + + .withProjectDir(new File("build/unitTest")) + .build(); + + project.getPluginManager().apply(JavaPlugin.class); + + project.getTasks().create("ca", GenerateStructureTask.class); + GenerateStructureTask generateStructureTask = (GenerateStructureTask) project.getTasks().getByName("ca"); + generateStructureTask.generateStructureTask(); + + ProjectBuilder.builder() + .withName("app-service") + .withProjectDir(new File("build/unitTest/applications/app-service")) + .withParent(project) + .build(); + + + project.getTasks().create("guc", GenerateUseCaseTask.class); + GenerateUseCaseTask generateUseCase = (GenerateUseCaseTask) project.getTasks().getByName("guc"); + generateUseCase.setName("business"); + generateUseCase.generateUseCaseTask(); + + Project useCaseProject = ProjectBuilder.builder() + .withName("usecase") + .withProjectDir(new File("build/unitTest/domain/usecase")) + .withParent(project) + .build(); + useCaseProject.getPluginManager().apply(JavaPlugin.class); + + + Project modelProject = ProjectBuilder.builder() + .withName("model") + .withProjectDir(new File("build/unitTest/domain/model")) + .withParent(project) + .build(); - Project project = ProjectBuilder.builder().withProjectDir(new File("build/unitTest")).build(); - project.getTasks().create("testStructure", GenerateStructureTask.class); + modelProject.getPluginManager().apply(JavaPlugin.class); + Task task2 = modelProject.getTasks().getByName("clean"); + task2.getActions().get(0).execute(task2); - GenerateStructureTask taskStructure = (GenerateStructureTask) project.getTasks().getByName("testStructure"); - taskStructure.generateStructureTask(); - project.getTasks().create("test", ValidateStructureTask.class); - task = (ValidateStructureTask) project.getTasks().getByName("test"); + assertTrue(new File("build/unitTest/infrastructure/driven-adapters/mongo-repository/build.gradle").exists()); + + project.getTasks().create("validate", ValidateStructureTask.class); + task = (ValidateStructureTask) project.getTasks().getByName("validate"); } - @Test - public void validateStructure() throws IOException, CleanException { + + @Test(expected = CleanException.class) + public void validateStructureException() throws IOException, CleanException { // Act + this.setupException(); task.validateStructureTask(); // Assert } + private void prepare() throws IOException, CleanException{ + Project project = ProjectBuilder.builder() + .withName("cleanArchitecture") + + .withProjectDir(new File("build/unitTest")) + .build(); + + project.getPluginManager().apply(JavaPlugin.class); + + project.getTasks().create("ca", GenerateStructureTask.class); + GenerateStructureTask generateStructureTask = (GenerateStructureTask) project.getTasks().getByName("ca"); + generateStructureTask.generateStructureTask(); + + ProjectBuilder.builder() + .withName("app-service") + .withProjectDir(new File("build/unitTest/applications/app-service")) + .withParent(project) + .build(); + + project.getTasks().create("gda", GenerateDrivenAdapterTask.class); + GenerateDrivenAdapterTask generateDriven = (GenerateDrivenAdapterTask) project.getTasks().getByName("gda"); + generateDriven.setType(ModuleFactoryDrivenAdapter.DrivenAdapterType.MONGODB); + generateDriven.generateDrivenAdapterTask(); + + project.getTasks().create("guc", GenerateUseCaseTask.class); + GenerateUseCaseTask generateUseCase = (GenerateUseCaseTask) project.getTasks().getByName("guc"); + generateUseCase.setName("business"); + generateUseCase.generateUseCaseTask(); - private void writeString(File file, String string) throws IOException { - try (Writer writer = new FileWriter(file)) { - writer.write(string); - } + + + Project mongoProject = ProjectBuilder.builder() + .withName("mongo-repository") + .withProjectDir(new File("build/unitTest/infrastructure/driven-adapters/mongo-repository")) + .withParent(project) + .build(); + + Project modelProject = ProjectBuilder.builder() + .withName("model") + .withProjectDir(new File("build/unitTest/domain/model")) + .withParent(project) + .build(); + mongoProject.getConfigurations().create("capsule").defaultDependencies(dependencySet -> { + dependencySet.add(project.getDependencies().create("co.paralleluniverse:capsule:1.0.3")); + }); + mongoProject.getPluginManager().apply(JavaPlugin.class); + + modelProject.getPluginManager().apply(JavaPlugin.class); + Task task2 = modelProject.getTasks().getByName("clean"); + task2.getActions().get(0).execute(task2); + + + assertTrue(new File("build/unitTest/infrastructure/driven-adapters/mongo-repository/build.gradle").exists()); + + project.getTasks().create("validate", ValidateStructureTask.class); + task = (ValidateStructureTask) project.getTasks().getByName("validate"); + } + + @Test + public void validateStructure() throws IOException, CleanException { + // Act + this.prepare(); + task.validateStructureTask(); + // Assert } + + + + + }