From 8f430d7df0e80e6231c2e1bc9e14fd61da7dc003 Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Date: Sat, 15 Jun 2024 06:51:38 -0500 Subject: [PATCH 1/2] fix(ca validation): moved dep search into gradle task to avoid ConcurentModificationExceptions --- .../architecture/ArchitectureValidation.java | 13 ------------- .../bancolombia/task/ValidateStructureTask.java | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/co/com/bancolombia/factory/validations/architecture/ArchitectureValidation.java b/src/main/java/co/com/bancolombia/factory/validations/architecture/ArchitectureValidation.java index 473e4c79..8b82b639 100644 --- a/src/main/java/co/com/bancolombia/factory/validations/architecture/ArchitectureValidation.java +++ b/src/main/java/co/com/bancolombia/factory/validations/architecture/ArchitectureValidation.java @@ -9,7 +9,6 @@ import lombok.NoArgsConstructor; import lombok.SneakyThrows; import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class ArchitectureValidation { @@ -37,21 +36,9 @@ private static String toOSPath(String os, File projectDir) { return projectDir.toString(); } - private static void prepareParams(Project project, Project appService, ModuleBuilder builder) { - boolean hasSpringWeb = - appService.getConfigurations().stream() - .map(Configuration::getIncoming) - .flatMap(d -> d.getDependencies().stream()) - .map(d -> d.getGroup() + ":" + d.getName()) - .anyMatch(dep -> dep.equals("org.springframework:spring-web")); - project.getLogger().debug("hasSpringWeb: {}", hasSpringWeb); - builder.addParam("hasSpringWeb", hasSpringWeb); - } - @SneakyThrows private static void generateArchUnitFiles( Project project, Project appService, ModuleBuilder builder) { - prepareParams(project, appService, builder); project .getLogger() .lifecycle("Injecting ArchitectureTest in module {}", appService.getProjectDir().getName()); diff --git a/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java b/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java index 3e274f45..ed756fdd 100644 --- a/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java +++ b/src/main/java/co/com/bancolombia/task/ValidateStructureTask.java @@ -19,6 +19,7 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.DependencySet; +import org.gradle.api.artifacts.UnknownConfigurationException; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; @@ -47,7 +48,7 @@ public void execute() throws IOException, CleanException { logger.lifecycle("Clean Architecture plugin version: {}", Utils.getVersionPlugin()); getModules().forEach(d -> logger.lifecycle("Submodules: " + d.getKey())); logger.lifecycle("Project Package: {}", packageName); - + checkForSpringWebDependency(); ArchitectureValidation.inject(getProject(), builder); if (!validateModelLayer()) { @@ -62,6 +63,20 @@ public void execute() throws IOException, CleanException { logger.lifecycle("The project is valid"); } + private void checkForSpringWebDependency() { + boolean hasSpringWeb = false; + try { + hasSpringWeb = + getProject().getChildProjects().get(APP_SERVICE).getConfigurations() + .getByName("testImplementation").getDependencies().stream() + .anyMatch(d -> d.getName().equals("spring-web")); + } catch (UnknownConfigurationException e) { + logger.warn("configuration testImplementation not present"); + } + logger.lifecycle("has spring-web dependency to run validations: {}", hasSpringWeb); + builder.addParam("hasSpringWeb", hasSpringWeb); + } + private boolean validateModelLayer() { if (validateExistingModule(MODEL_MODULE)) { logger.lifecycle("Validating Model Module"); From 66b34b4c574f9932e4ab5c5f9b66b3b225ce5745 Mon Sep 17 00:00:00 2001 From: Gabriel Martinez Date: Sat, 15 Jun 2024 07:03:17 -0500 Subject: [PATCH 2/2] feature(mutation testing): added support for pitest mutation test plugin --- README.md | 32 ++++++++++--------- .../java/co/com/bancolombia/Constants.java | 1 + .../bancolombia/factory/ModuleBuilder.java | 4 +++ .../task/GenerateStructureTask.java | 10 ++++++ .../structure/root/build.gradle.mustache | 6 ++++ .../structure/root/main.gradle.mustache | 28 ++++++++++++++++ 6 files changed, 66 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index ea932252..f8b7b39b 100644 --- a/README.md +++ b/README.md @@ -49,28 +49,30 @@ The Scaffolding Clean Architecture plugin will allow you run 8 tasks: ## Generate Project -The **`cleanArchitecture | ca`** task will generate a clean architecture structure in your project, this task has four optional parameters; `package` , `type`, `name` and `coverage`. -If you run this task on an existing project it will override the `main.gradle`, `build.gradle` and `gradle.properties` files. +The **`cleanArchitecture | ca`** task will generate a clean architecture structure in your project. - - **`package`** `= `: You can specify the main or default package of your project. `Default Value = co.com.bancolombia` +**Caution**: If you run this task on an existing project it will override the `main.gradle`, `build.gradle` and `gradle.properties` files. - - **`type`** `= `: With this parameter the task will generate a POO project. `Default Value = reactive` - - **`name`** `= NameProject`: This parameter is going to specify the name of the project. `Default Value = cleanArchitecture` +| Parameter | Description | Usage | Default Value | +|-------------|--------------------------------------------------------------------------|----------------------------------------------|----------------------| +| package | You can specify the main or default package of your project | `--package=` | `co.com.bancolombia` | +| type | Define if project shoud be created around reactive or imperative aproach | `--type=` | `reactive` | +| name | Sets projects name | `--name=` | `cleanArchitecture` | +| lombok | Specify if you want to use this plugin | `--lombok=` | `true` | +| metrics | Specify if you want to enable this feature with micrometer | `--metrics=` | `true` | +| mutation | Specify if you want to enable mutation testing framework on this project | `--mutation=` | `true` | +| javaVersion | Sets Java version | `--javaVersion= ` | `VERSION_17` | - - - **`lombok`** `= `: Specify if you want to use this plugin . `Default Value = true` +Examples: - - **`metrics`** `= `: Specify if you want to enable this feature with micrometer . `Default Value = true` +```shell +gradle cleanArchitecture --package=co.com.bancolombia --type=reactive --name=NameProject --lombok=true +gradle ca --package=co.com.bancolombia --type=reactive --name=NameProject --lombok=true +``` - - **`javaVersion`** `= `: Java version . `Default Value = VERSION_17` - - ```shell - gradle cleanArchitecture --package=co.com.bancolombia --type=reactive --name=NameProject --lombok=true - gradle ca --package=co.com.bancolombia --type=reactive --name=NameProject --lombok=true - ``` - **_The structure will look like this for java:_** +**_The generated structure will look like this for java:_** ```bash 📦NameProject diff --git a/src/main/java/co/com/bancolombia/Constants.java b/src/main/java/co/com/bancolombia/Constants.java index d941146d..16257258 100644 --- a/src/main/java/co/com/bancolombia/Constants.java +++ b/src/main/java/co/com/bancolombia/Constants.java @@ -30,6 +30,7 @@ public final class Constants { public static final String COBERTURA_VERSION = "4.0.0"; public static final String PLUGIN_VERSION = "3.17.8"; public static final String DEPENDENCY_CHECK_VERSION = "9.2.0"; + public static final String PITEST_VERSION = "1.15.0"; // custom public static final String GRADLE_WRAPPER_VERSION = "8.8"; diff --git a/src/main/java/co/com/bancolombia/factory/ModuleBuilder.java b/src/main/java/co/com/bancolombia/factory/ModuleBuilder.java index 731c6fcb..94a22898 100644 --- a/src/main/java/co/com/bancolombia/factory/ModuleBuilder.java +++ b/src/main/java/co/com/bancolombia/factory/ModuleBuilder.java @@ -328,6 +328,10 @@ public boolean withMetrics() { return getABooleanProperty("metrics", true); } + public boolean withMutation() { + return getABooleanProperty("mutation", false); + } + @SafeVarargs public final void runValidations(Class... validations) throws ValidationException { diff --git a/src/main/java/co/com/bancolombia/task/GenerateStructureTask.java b/src/main/java/co/com/bancolombia/task/GenerateStructureTask.java index 4166ae1b..17443c7f 100644 --- a/src/main/java/co/com/bancolombia/task/GenerateStructureTask.java +++ b/src/main/java/co/com/bancolombia/task/GenerateStructureTask.java @@ -24,6 +24,7 @@ public class GenerateStructureTask extends AbstractCleanArchitectureDefaultTask private String name = "cleanArchitecture"; private BooleanOption lombok = BooleanOption.TRUE; private BooleanOption metrics = BooleanOption.TRUE; + private BooleanOption mutation = BooleanOption.TRUE; private BooleanOption force = BooleanOption.FALSE; private BooleanOption withExample = BooleanOption.FALSE; private JavaVersion javaVersion = JavaVersion.VERSION_17; @@ -53,6 +54,13 @@ public void setMetrics(BooleanOption metrics) { this.metrics = metrics; } + @Option( + option = "mutation", + description = "Set if this project should include mutation tests configuration") + public void setMutation(BooleanOption mutation) { + this.mutation = mutation; + } + @Option(option = "javaVersion", description = "Set Java version") public void setJavaVersion(JavaVersion javaVersion) { this.javaVersion = javaVersion; @@ -106,6 +114,7 @@ public void execute() throws IOException, CleanException { builder.addParam("lombok", lombok == BooleanOption.TRUE); builder.addParam("metrics", metrics == BooleanOption.TRUE); builder.addParam("example", withExample == BooleanOption.TRUE); + builder.addParam("mutation", mutation == BooleanOption.TRUE); builder.addParam("javaVersion", javaVersion); builder.addParam("java17", javaVersion == JavaVersion.VERSION_17); builder.addParam("java21", javaVersion == JavaVersion.VERSION_21); @@ -119,6 +128,7 @@ public void execute() throws IOException, CleanException { builder.addParam(REACTIVE, builder.isReactive()); builder.addParam("lombok", builder.isEnableLombok()); builder.addParam("metrics", builder.withMetrics()); + builder.addParam("mutation", builder.withMutation()); if (builder.isEnableLombok()) { builder.setupFromTemplate("structure/restructure"); } else { diff --git a/src/main/resources/structure/root/build.gradle.mustache b/src/main/resources/structure/root/build.gradle.mustache index c7f1f6e7..3a92f290 100644 --- a/src/main/resources/structure/root/build.gradle.mustache +++ b/src/main/resources/structure/root/build.gradle.mustache @@ -4,6 +4,9 @@ buildscript { springBootVersion = '{{SPRING_BOOT_VERSION}}' sonarVersion = '{{SONAR_VERSION}}' jacocoVersion = '{{JACOCO_VERSION}}' + {{#mutation}} + pitestVersion = '{{PITEST_VERSION}}' + {{/mutation}} {{#lombok}} lombokVersion = '{{LOMBOK_VERSION}}' {{/lombok}} @@ -29,6 +32,9 @@ plugins { id "org.owasp.dependencycheck" version "{{DEPENDENCY_CHECK_VERSION}}" apply false {{/example}} id 'org.springframework.boot' version "${springBootVersion}" apply false + {{#mutation}} + id 'info.solidsoft.pitest' version "${pitestVersion}" apply false + {{/mutation}} id 'org.sonarqube' version "${sonarVersion}" id 'jacoco' } diff --git a/src/main/resources/structure/root/main.gradle.mustache b/src/main/resources/structure/root/main.gradle.mustache index c8d0b84b..f70c0160 100644 --- a/src/main/resources/structure/root/main.gradle.mustache +++ b/src/main/resources/structure/root/main.gradle.mustache @@ -1,3 +1,7 @@ +{{#mutation}} +apply plugin: 'info.solidsoft.pitest.aggregator' +{{/mutation}} + allprojects { repositories { mavenCentral() @@ -10,10 +14,17 @@ subprojects { apply plugin: 'java' apply plugin: 'jacoco' apply plugin: 'io.spring.dependency-management' + {{#mutation}} + apply plugin: 'info.solidsoft.pitest' + {{/mutation}} compileJava.dependsOn validateStructure sourceCompatibility = JavaVersion.{{javaVersion}} + {{#mutation}} + //build.dependsOn 'pitest' + {{/mutation}} + test { useJUnitPlatform() } @@ -50,6 +61,23 @@ subprojects { test.finalizedBy(project.tasks.jacocoTestReport) + {{#mutation}} + pitest { + targetClasses = ['{{package}}.*'] + excludedClasses = [] + excludedTestClasses = [] + verbose = true + outputFormats = ['XML', 'HTML'] + threads = 8 + exportLineCoverage = true + timestampedReports = false + fileExtensionsToFilter.addAll('xml', 'orbit') + junit5PluginVersion = '1.2.1' + failWhenNoMutations = false + jvmArgs = ["-XX:+AllowRedefinitionToAddDeleteMethods"] + } + {{/mutation}} + jacocoTestReport { dependsOn test reports {