Skip to content

Commit

Permalink
feat(pitest): Add UpgradeAction for pitest settings
Browse files Browse the repository at this point in the history
  • Loading branch information
juancgalvis committed Oct 18, 2024
1 parent 93698ac commit 7a822e2
Show file tree
Hide file tree
Showing 11 changed files with 520 additions and 2 deletions.
4 changes: 4 additions & 0 deletions sh_dependencies.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
{
"name": "DEPENDENCY_CHECK_VERSION",
"packageName": "org.owasp.dependencycheck:org.owasp.dependencycheck.gradle.plugin"
},
{
"name": "PITEST_VERSION",
"packageName": "info.solidsoft.pitest:info.solidsoft.pitest.gradle.plugin"
}
],
"custom": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ public static String insertAfterMatch(
return main.substring(0, start) + concatValue + main.substring(start);
}

public static String addToStartIfNotContains(
String main, String containsValue, String concatValue) {
if (main.contains(containsValue)) {
return main;
}
return concatValue + main;
}

public static String replace(String content, String previous, String next) {
return content.replace(previous, next);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package co.com.bancolombia.factory.upgrades.actions;

import static co.com.bancolombia.Constants.MainFiles.BUILD_GRADLE;
import static co.com.bancolombia.Constants.MainFiles.MAIN_GRADLE;

import co.com.bancolombia.Constants;
import co.com.bancolombia.factory.ModuleBuilder;
import co.com.bancolombia.factory.upgrades.UpdateUtils;
import co.com.bancolombia.factory.upgrades.UpgradeAction;
import lombok.SneakyThrows;

public class UpgradeY2024M10D17AddPitest implements UpgradeAction {
private final String pitestConfig =
"pitest {\n"
+ " targetClasses = ['{{package}}.*']\n"
+ " excludedClasses = []\n"
+ " excludedTestClasses = []\n"
+ " pitestVersion = '1.16.1'\n"
+ " verbose = true\n"
+ " outputFormats = ['XML', 'HTML']\n"
+ " threads = 8\n"
+ " exportLineCoverage = true\n"
+ " timestampedReports = false\n"
+ " //mutators = ['STRONGER', 'DEFAULTS']\n"
+ " fileExtensionsToFilter.addAll('xml', 'orbit')\n"
+ " junit5PluginVersion = '1.2.1'\n"
+ " failWhenNoMutations = false\n"
+ " jvmArgs = [\"-XX:+AllowRedefinitionToAddDeleteMethods\"]\n"
+ " }\n"
+ "\n"
+ " ";

private final String pitestMergedConfig =
"\npitestReportAggregate {\n"
+ " doLast {\n"
+ " def reportDir = layout.buildDirectory.dir(\"reports/pitest\").get().asFile\n"
+ " def consolidatedReport = new File(reportDir, 'mutations.xml')\n"
+ " consolidatedReport.withWriter { writer ->\n"
+ " writer.write(\"<mutations>\\n\")\n"
+ " subprojects.each { subproject ->\n"
+ " def xmlReport = subproject.layout.buildDirectory.file(\"reports/pitest/mutations.xml\").get().asFile\n"
+ " if (xmlReport.exists()) {\n"
+ " def xmlContent = xmlReport.text\n"
+ " xmlContent = xmlContent.replaceAll(\"<\\\\?xml[^>]*>\", \"\")\n"
+ " xmlContent = xmlContent.replaceAll(\"</?mutations( partial=\\\"true\\\")?>\", \"\")\n"
+ " writer.write(xmlContent.trim() + \"\\n\")\n"
+ " }\n"
+ " }\n"
+ " writer.write(\"</mutations>\")\n"
+ " }\n"
+ " }\n"
+ "}\n\n";

@Override
@SneakyThrows
public boolean up(ModuleBuilder builder) {
boolean appliedToBuildGradle =
builder.updateFile(
BUILD_GRADLE,
content -> {
String partial =
UpdateUtils.insertAfterMatch(
content,
"ext {",
"pitestVersion",
"\n pitestVersion = '" + Constants.PITEST_VERSION + "'");

partial =
UpdateUtils.insertAfterMatch(
partial,
"plugins {",
"info.solidsoft.pitest",
"\n id 'info.solidsoft.pitest' version \"${pitestVersion}\" apply false");

return UpdateUtils.insertAfterMatch(
partial,
"jacocoMergedReport.xml\"",
"sonar.pitest.reportPaths",
"\n property \"sonar.pitest.reportPaths\", \"build/reports/pitest/mutations.xml\"");
});
boolean appliedToMainGradle =
builder.updateFile(
MAIN_GRADLE,
content -> {
String partial =
UpdateUtils.addToStartIfNotContains(
content,
"info.solidsoft.pitest.aggregator",
"apply plugin: 'info.solidsoft.pitest.aggregator'\n\n");

partial =
UpdateUtils.insertAfterMatch(
partial,
"subprojects {",
"'info.solidsoft.pitest'",
"\n apply plugin: 'info.solidsoft.pitest'");

String packageLoaded = builder.getStringParam("package");
if (packageLoaded == null) {
packageLoaded = "your.package";
}
String pitest = pitestConfig.replace("{{package}}", packageLoaded);
partial =
UpdateUtils.insertBeforeMatch(
partial, "jacocoTestReport {", "pitestVersion", pitest);

partial =
UpdateUtils.insertAfterMatch(
partial,
"subprojects.jacocoTestReport",
"pitestReportAggregate",
", pitestReportAggregate");

partial =
UpdateUtils.insertAfterMatch(partial, "dependsOn test", "'pitest'", ", 'pitest'");

return UpdateUtils.insertBeforeMatch(
partial, "tasks.named('wrapper')", "pitestReportAggregate {", pitestMergedConfig);
});
return appliedToBuildGradle || appliedToMainGradle;
}

@Override
public String name() {
return "3.17.24->3.18";
}

@Override
public String description() {
return "Add skipCompile for sonar";
}
}
1 change: 1 addition & 0 deletions src/main/resources/structure/root/build.gradle.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ sonar {
property "sonar.junit.reportsPath", "{{sonar.junit.reportsPaths}}"
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacocoMergedReport/jacocoMergedReport.xml"
property "sonar.pitest.reportPaths", "build/reports/pitest/mutations.xml"
property "sonar.externalIssuesReportPaths", "build/issues.json"
}
}
Expand Down
26 changes: 24 additions & 2 deletions src/main/resources/structure/root/main.gradle.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,13 @@ subprojects {
targetClasses = ['{{package}}.*']
excludedClasses = []
excludedTestClasses = []
pitestVersion = '1.16.1'
verbose = true
outputFormats = ['XML', 'HTML']
threads = 8
exportLineCoverage = true
timestampedReports = false
//mutators = ['STRONGER', 'DEFAULTS']
fileExtensionsToFilter.addAll('xml', 'orbit')
junit5PluginVersion = '1.2.1'
failWhenNoMutations = false
Expand All @@ -79,7 +81,7 @@ subprojects {
{{/mutation}}

jacocoTestReport {
dependsOn test
dependsOn test, 'pitest'
reports {
xml.setRequired true
xml.setOutputLocation layout.buildDirectory.file("reports/jacoco.xml")
Expand All @@ -96,7 +98,7 @@ jacoco {
}

tasks.register('jacocoMergedReport', JacocoReport) {
dependsOn = [test, subprojects.jacocoTestReport]
dependsOn = [test, subprojects.jacocoTestReport, pitestReportAggregate]
additionalSourceDirs.setFrom files(subprojects.sourceSets.main.allSource.srcDirs)
sourceDirectories.setFrom files(subprojects.sourceSets.main.allSource.srcDirs)
classDirectories.setFrom files(subprojects.sourceSets.main.output)
Expand All @@ -114,6 +116,26 @@ tasks.withType(JavaCompile).configureEach {
]
}

pitestReportAggregate {
doLast {
def reportDir = layout.buildDirectory.dir("reports/pitest").get().asFile
def consolidatedReport = new File(reportDir, 'mutations.xml')
consolidatedReport.withWriter { writer ->
writer.write("<mutations>\n")
subprojects.each { subproject ->
def xmlReport = subproject.layout.buildDirectory.file("reports/pitest/mutations.xml").get().asFile
if (xmlReport.exists()) {
def xmlContent = xmlReport.text
xmlContent = xmlContent.replaceAll("<\\?xml[^>]*>", "")
xmlContent = xmlContent.replaceAll("</?mutations( partial=\"true\")?>", "")
writer.write(xmlContent.trim() + "\n")
}
}
writer.write("</mutations>")
}
}
}

tasks.named('wrapper') {
gradleVersion = '{{GRADLE_WRAPPER_VERSION}}'
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,20 @@ void shouldAppendValidate() {
assertEquals(expected, result);
}

@Test
void shouldAddToStartIfNotContains() {
// Arrange
String file = "apply plugin: 'info.solidsoft.pitest.aggregator'\n\n";
String check = "info.solidsoft.pitest.aggregator";
String currentContent = "allprojects {}\n";
builder.addFile(file, currentContent);
// Act
String expected = "apply plugin: 'info.solidsoft.pitest.aggregator'\n\nallprojects {}\n";
String result = UpdateUtils.addToStartIfNotContains(currentContent, check, file);
// Assert
assertEquals(expected, result);
}

@Test
void shouldThrowWhenNoMatch() {
// Arrange
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package co.com.bancolombia.factory.upgrades.actions;

import static co.com.bancolombia.Constants.MainFiles.BUILD_GRADLE;
import static co.com.bancolombia.Constants.MainFiles.MAIN_GRADLE;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import co.com.bancolombia.factory.ModuleBuilder;
import co.com.bancolombia.factory.upgrades.UpgradeAction;
import co.com.bancolombia.utils.FileUtils;
import com.github.mustachejava.resolver.DefaultResolver;
import java.io.IOException;
import java.nio.file.Files;
import org.gradle.api.Project;
import org.gradle.api.logging.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class UpgradeY2024M10D17AddPitestTest {

@Mock private Project project;
@Mock private Logger logger;

private ModuleBuilder builder;
private UpgradeAction updater;

@BeforeEach
public void setup() throws IOException {
when(project.getName()).thenReturn("UtilsTest");
when(project.getLogger()).thenReturn(logger);
when(project.getProjectDir()).thenReturn(Files.createTempDirectory("sample").toFile());

builder = spy(new ModuleBuilder(project));
updater = new UpgradeY2024M10D17AddPitest();

assertNotNull(updater.name());
assertNotNull(updater.description());
}

@Test
void shouldApplyUpdate() throws IOException {
DefaultResolver resolver = new DefaultResolver();
// Arrange
builder.addFile(
BUILD_GRADLE, FileUtils.getResourceAsString(resolver, "pitest/build-before.txt"));
builder.addFile(MAIN_GRADLE, FileUtils.getResourceAsString(resolver, "pitest/main-before.txt"));
// Act
boolean applied = updater.up(builder);
// Assert
assertTrue(applied);
verify(builder)
.addFile(BUILD_GRADLE, FileUtils.getResourceAsString(resolver, "pitest/build-after.txt"));
verify(builder)
.addFile(MAIN_GRADLE, FileUtils.getResourceAsString(resolver, "pitest/main-after.txt"));
}
}
37 changes: 37 additions & 0 deletions src/test/resources/pitest/build-after.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
buildscript {
ext {
pitestVersion = '1.15.0'
cleanArchitectureVersion = '3.17.26'
springBootVersion = '3.3.4'
sonarVersion = '5.1.0.4882'
jacocoVersion = '0.8.12'
lombokVersion = '1.18.34'
}
}

plugins {
id 'info.solidsoft.pitest' version "${pitestVersion}" apply false
id 'co.com.bancolombia.cleanArchitecture' version "${cleanArchitectureVersion}"
id 'org.springframework.boot' version "${springBootVersion}" apply false
id 'org.sonarqube' version "${sonarVersion}"
id 'jacoco'
}

sonar {
def modules = subprojects.projectDir.collect { "${it.toString().replace(project.projectDir.toString() + "/", "")}" }
properties {
property "sonar.sourceEncoding", "UTF-8"
property "sonar.modules", "${modules.join(',')}"
property "sonar.sources", "src,deployment,settings.gradle,main.gradle,build.gradle,${modules.collect { "${it}/build.gradle" }.join(',')}"
property "sonar.test", "src/test"
property "sonar.exclusions", ""
property "sonar.java.binaries", "build/classes"
property "sonar.junit.reportsPath", "build/test-reports"
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacocoMergedReport/jacocoMergedReport.xml"
property "sonar.pitest.reportPaths", "build/reports/pitest/mutations.xml"
property "sonar.externalIssuesReportPaths", "build/issues.json"
}
}

apply from: './main.gradle'
34 changes: 34 additions & 0 deletions src/test/resources/pitest/build-before.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
buildscript {
ext {
cleanArchitectureVersion = '3.17.26'
springBootVersion = '3.3.4'
sonarVersion = '5.1.0.4882'
jacocoVersion = '0.8.12'
lombokVersion = '1.18.34'
}
}

plugins {
id 'co.com.bancolombia.cleanArchitecture' version "${cleanArchitectureVersion}"
id 'org.springframework.boot' version "${springBootVersion}" apply false
id 'org.sonarqube' version "${sonarVersion}"
id 'jacoco'
}

sonar {
def modules = subprojects.projectDir.collect { "${it.toString().replace(project.projectDir.toString() + "/", "")}" }
properties {
property "sonar.sourceEncoding", "UTF-8"
property "sonar.modules", "${modules.join(',')}"
property "sonar.sources", "src,deployment,settings.gradle,main.gradle,build.gradle,${modules.collect { "${it}/build.gradle" }.join(',')}"
property "sonar.test", "src/test"
property "sonar.exclusions", ""
property "sonar.java.binaries", "build/classes"
property "sonar.junit.reportsPath", "build/test-reports"
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacocoMergedReport/jacocoMergedReport.xml"
property "sonar.externalIssuesReportPaths", "build/issues.json"
}
}

apply from: './main.gradle'
Loading

0 comments on commit 7a822e2

Please sign in to comment.