plugins { id 'java' id 'org.springframework.boot' version '2.7.3' id 'io.openapiprocessor.openapi-processor' version '2022.2' id 'io.spring.dependency-management' version '1.0.13.RELEASE' id 'com.github.jk1.dependency-license-report' version '2.1' id "org.owasp.dependencycheck" version "7.1.2" id "com.diffplug.spotless" version "6.10.0" id 'jacoco' id 'info.solidsoft.pitest' version '1.9.0' id 'se.patrikerdes.use-latest-versions' version '0.2.18' id 'com.github.ben-manes.versions' version '0.42.0' } group = 'net.hostsharing' version = '0.0.1-SNAPSHOT' wrapper { distributionType = Wrapper.DistributionType.BIN gradleVersion = '7.5' } configurations { compileOnly { extendsFrom annotationProcessor } testCompile { // Only JUNit 5 (Jupiter) should be used at compile time. // For runtime it's still needed by testcontainers, though. exclude group: 'junit', module: 'junit' exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' } } repositories { mavenCentral() } java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } ext { set('testcontainersVersion', "1.17.3") } // wrapper dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-rest' implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springdoc:springdoc-openapi-ui:1.6.11' implementation 'org.liquibase:liquibase-core' implementation 'com.vladmihalcea:hibernate-types-55:2.18.0' implementation 'org.openapitools:jackson-databind-nullable:0.2.3' implementation 'org.modelmapper:modelmapper:3.1.0' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'org.postgresql:postgresql' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.testcontainers:testcontainers' testImplementation 'org.testcontainers:junit-jupiter' testImplementation 'org.testcontainers:postgresql' testImplementation 'com.tngtech.archunit:archunit-junit5:1.0.0-rc1' testImplementation 'io.rest-assured:spring-mock-mvc' testImplementation 'org.hamcrest:hamcrest-core:2.2' testImplementation 'org.pitest:pitest-junit5-plugin:1.0.0' } dependencyManagement { imports { mavenBom "org.testcontainers:testcontainers-bom:${testcontainersVersion}" } } // Java Compiler Options tasks.withType(JavaCompile) { options.compilerArgs += [ "-parameters" // keep parameter names => no need for @Param for SpringData ] } // Use JUnit Jupiter tasks.named('test') { useJUnitPlatform() } // OpenAPI Source Code Generation openapiProcessor { springRoot { processorName 'spring' processor 'io.openapiprocessor:openapi-processor-spring:2022.4' apiPath "$projectDir/src/main/resources/api-definition.yaml" mapping "$projectDir/src/main/resources/api-mappings.yaml" targetDir "$projectDir/build/generated/sources/openapi" showWarnings true openApiNullable true } springRbac { processorName 'spring' processor 'io.openapiprocessor:openapi-processor-spring:2022.4' apiPath "$projectDir/src/main/resources/api-definition/rbac/rbac.yaml" mapping "$projectDir/src/main/resources/api-definition/rbac/api-mappings.yaml" targetDir "$projectDir/build/generated/sources/openapi" showWarnings true openApiNullable true } springTest { processorName 'spring' processor 'io.openapiprocessor:openapi-processor-spring:2022.4' apiPath "$projectDir/src/main/resources/api-definition/test/test.yaml" mapping "$projectDir/src/main/resources/api-definition/test/api-mappings.yaml" targetDir "$projectDir/build/generated/sources/openapi" showWarnings true openApiNullable true } } sourceSets.main.java.srcDir 'build/generated/sources/openapi' ['processSpringRoot', 'processSpringRbac', 'processSpringTest'].each { project.tasks.processResources.dependsOn it project.tasks.compileJava.dependsOn it } // Spotless Code Formatting spotless { java { // removeUnusedImports() TODO: reactivate once it can deal with multi-line-strings indentWithSpaces(4) endWithNewline() toggleOffOn() target fileTree(rootDir) { include '**/*.java' exclude '**/generated/**/*.java' } } } project.tasks.check.dependsOn(spotlessCheck) // OWASP Dependency Security Test dependencyCheck { cveValidForHours=4 format = 'ALL' suppressionFile = 'etc/owasp-dependency-check-suppression.xml' failOnError = true failBuildOnCVSS = 7 } project.tasks.check.dependsOn(dependencyCheckAnalyze) project.tasks.dependencyCheckAnalyze.doFirst { // doLast is not executed on exception, thus when we need it println "OWASP Dependency Security Report: file:///${project.rootDir}/build/reports/dependency-check-report.html" } // License Check licenseReport { excludeBoms = true allowedLicensesFile = new File("$projectDir/etc/allowed-licenses.json") } project.tasks.check.dependsOn(checkLicense) // JaCoCo Test Code Coverage jacoco { toolVersion = "0.8.8" } test { finalizedBy jacocoTestReport // generate report after tests excludes = [ 'net.hostsharing.hsadminng.**.generated.**', ] } jacocoTestReport { dependsOn test afterEvaluate { classDirectories.setFrom(files(classDirectories.files.collect { fileTree(dir: it, exclude: [ "net/hostsharing/hsadminng/**/generated/**/*.class", "net/hostsharing/hsadminng/PingController.class", "net/hostsharing/hsadminng/hs/hscustomer/HsadminNgApplication.class" ]) })) } doLast { println "HTML Jacoco Test Code Coverage Report: file://${reports.html.outputLocation.get()}/index.html" } } project.tasks.check.dependsOn(jacocoTestCoverageVerification) jacocoTestCoverageVerification { violationRules { rule { limit { minimum = 0.90 } } // element: PACKAGE, BUNDLE, CLASS, SOURCEFILE or METHOD // counter: INSTRUCTION, BRANCH, LINE, COMPLEXITY, METHOD, or CLASS // value: TOTALCOUNT, COVEREDCOUNT, MISSEDCOUNT, COVEREDRATIO or MISSEDRATIO rule { element = 'CLASS' excludes = [ 'net.hostsharing.hsadminng.**.generated.**', 'net.hostsharing.hsadminng.HsadminNgApplication', 'net.hostsharing.hsadminng.PingController', 'net.hostsharing.hsadminng.Mapper' ] limit { counter = 'LINE' value = 'COVEREDRATIO' minimum = 0.95 } } rule { element = 'METHOD' excludes = [ 'net.hostsharing.hsadminng.**.generated.**', 'net.hostsharing.hsadminng.HsadminNgApplication.main', 'net.hostsharing.hsadminng.PingController.*' ] limit { counter = 'BRANCH' value = 'COVEREDRATIO' minimum = 0.95 } } } } // pitest mutation testing pitest { targetClasses = ['net.hostsharing.hsadminng.**'] excludedClasses = [ 'net.hostsharing.hsadminng.config.**', 'net.hostsharing.hsadminng.**.generated.**' ] targetTests = ['net.hostsharing.hsadminng.**.*UnitTest', 'net.hostsharing.hsadminng.**.*RestTest'] excludedTestClasses = ['**AcceptanceTest*', '**IntegrationTest*'] pitestVersion = '1.9.0' junit5PluginVersion = '1.0.0' threads = 4 // As Java unit tests are pretty pointless in our case, this maybe makes not much sense. mutationThreshold = 31 coverageThreshold = 44 testStrengthThreshold = 76 outputFormats = ['XML', 'HTML'] timestampedReports = false } project.tasks.check.dependsOn(project.tasks.pitest) project.tasks.pitest.doLast { println "PiTest Mutation Report: file:///${project.rootDir}/build/reports/pitest/index.html" } // Dependency Versions Upgrade useLatestVersions { finalizedBy check }