Michael Hoennig
2022-10-21 5ada0dae35f03103104d9d2998c25a26912f5baa
commit | author | age
6c33bb 1 plugins {
a2f2fd 2     id 'java'
810c39 3     id 'org.springframework.boot' version '2.7.5'
0e4602 4     id 'io.openapiprocessor.openapi-processor' version '2022.2'
810c39 5     id 'io.spring.dependency-management' version '1.1.0'
c4531c 6     id 'com.github.jk1.dependency-license-report' version '2.1'
810c39 7     id "org.owasp.dependencycheck" version "7.3.0"
398f15 8     id "com.diffplug.spotless" version "6.11.0"
a66ed8 9     id 'jacoco'
7d4815 10     id 'info.solidsoft.pitest' version '1.9.0'
8b4e78 11     id 'se.patrikerdes.use-latest-versions' version '0.2.18'
810c39 12     id 'com.github.ben-manes.versions' version '0.43.0'
6c33bb 13 }
MH 14
15 group = 'net.hostsharing'
16 version = '0.0.1-SNAPSHOT'
17
d9ee00 18 wrapper {
MH 19     distributionType = Wrapper.DistributionType.BIN
20     gradleVersion = '7.5'
21 }
22
6c33bb 23 configurations {
MH 24     compileOnly {
25         extendsFrom annotationProcessor
26     }
3de8b0 27     testCompile {
3eec8a 28         extendsFrom testAnnotationProcessor
MH 29
3de8b0 30         // Only JUNit 5 (Jupiter) should be used at compile time.
MH 31         // For runtime it's still needed by testcontainers, though.
32         exclude group: 'junit', module: 'junit'
33         exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
34     }
6c33bb 35 }
MH 36
37 repositories {
38     mavenCentral()
433d0e 39 }
MH 40
41 java {
42     toolchain {
43         languageVersion = JavaLanguageVersion.of(17)
44     }
6c33bb 45 }
MH 46
47 ext {
48     set('testcontainersVersion', "1.17.3")
49 }
a2f2fd 50
MH 51 // wrapper
6c33bb 52
MH 53 dependencies {
54     implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
55     implementation 'org.springframework.boot:spring-boot-starter-data-rest'
56     implementation 'org.springframework.boot:spring-boot-starter-jdbc'
57     implementation 'org.springframework.boot:spring-boot-starter-web'
67e850 58     implementation 'org.springframework.boot:spring-boot-starter-validation'
c6d92e 59     implementation 'com.github.gavlyukovskiy:datasource-proxy-spring-boot-starter:1.8.1'
810c39 60     implementation 'org.springdoc:springdoc-openapi-ui:1.6.12'
6c33bb 61     implementation 'org.liquibase:liquibase-core'
810c39 62     implementation 'com.vladmihalcea:hibernate-types-55:2.20.0'
4f22df 63     implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4'
0e4602 64     implementation 'org.openapitools:jackson-databind-nullable:0.2.3'
eeab68 65     implementation 'org.modelmapper:modelmapper:3.1.0'
d98b8f 66     implementation 'org.iban4j:iban4j:3.2.3-RELEASE'
6c33bb 67
MH 68     compileOnly 'org.projectlombok:lombok'
3eec8a 69     testCompileOnly 'org.projectlombok:lombok'
6c33bb 70
MH 71     developmentOnly 'org.springframework.boot:spring-boot-devtools'
72
73     runtimeOnly 'org.postgresql:postgresql'
74
75     annotationProcessor 'org.projectlombok:lombok'
3eec8a 76     testAnnotationProcessor 'org.projectlombok:lombok'
6c33bb 77
MH 78     testImplementation 'org.springframework.boot:spring-boot-starter-test'
79     testImplementation 'org.testcontainers:testcontainers'
80     testImplementation 'org.testcontainers:junit-jupiter'
81     testImplementation 'org.testcontainers:postgresql'
398f15 82     testImplementation 'com.tngtech.archunit:archunit-junit5:1.0.0'
0e4602 83     testImplementation 'io.rest-assured:spring-mock-mvc'
9fb661 84     testImplementation 'org.hamcrest:hamcrest-core:2.2'
398f15 85     testImplementation 'org.pitest:pitest-junit5-plugin:1.1.0'
6c33bb 86 }
MH 87
88 dependencyManagement {
89     imports {
90         mavenBom "org.testcontainers:testcontainers-bom:${testcontainersVersion}"
91     }
92 }
93
a66ed8 94 // Java Compiler Options
433d0e 95 tasks.withType(JavaCompile) {
a66ed8 96     options.compilerArgs += [
MH 97             "-parameters" // keep parameter names => no need for @Param for SpringData
98     ]
433d0e 99 }
MH 100
a66ed8 101 // Use JUnit Jupiter
6c33bb 102 tasks.named('test') {
MH 103     useJUnitPlatform()
104 }
a2f2fd 105
a66ed8 106 // OpenAPI Source Code Generation
eeab68 107 openapiProcessor {
cd9be1 108     springRoot {
MH 109         processorName 'spring'
67e850 110         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
eeab68 111         apiPath "$projectDir/src/main/resources/api-definition.yaml"
MH 112         mapping "$projectDir/src/main/resources/api-mappings.yaml"
cd9be1 113         targetDir "$projectDir/build/generated/sources/openapi"
MH 114         showWarnings true
115         openApiNullable true
116     }
117     springRbac {
118         processorName 'spring'
67e850 119         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
cd9be1 120         apiPath "$projectDir/src/main/resources/api-definition/rbac/rbac.yaml"
MH 121         mapping "$projectDir/src/main/resources/api-definition/rbac/api-mappings.yaml"
122         targetDir "$projectDir/build/generated/sources/openapi"
123         showWarnings true
124         openApiNullable true
125     }
126     springTest {
127         processorName 'spring'
67e850 128         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
cd9be1 129         apiPath "$projectDir/src/main/resources/api-definition/test/test.yaml"
MH 130         mapping "$projectDir/src/main/resources/api-definition/test/api-mappings.yaml"
131         targetDir "$projectDir/build/generated/sources/openapi"
eeab68 132         showWarnings true
0e4602 133         openApiNullable true
eeab68 134     }
af90fe 135     springHs {
MH 136         processorName 'spring'
67e850 137         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
4e90f5 138         apiPath "$projectDir/src/main/resources/api-definition/hs-office/hs-office.yaml"
MH 139         mapping "$projectDir/src/main/resources/api-definition/hs-office/api-mappings.yaml"
af90fe 140         targetDir "$projectDir/build/generated/sources/openapi"
MH 141         showWarnings true
142         openApiNullable true
143     }
eeab68 144 }
MH 145 sourceSets.main.java.srcDir 'build/generated/sources/openapi'
af90fe 146 abstract class ProcessSpring extends DefaultTask {}
MH 147 tasks.register('processSpring', ProcessSpring)
148 ['processSpringRoot', 'processSpringRbac', 'processSpringTest', 'processSpringHs'].each {
149     project.tasks.processSpring.dependsOn it
cd9be1 150 }
af90fe 151 project.tasks.processResources.dependsOn processSpring
MH 152 project.tasks.compileJava.dependsOn processSpring
eeab68 153
a66ed8 154 // Spotless Code Formatting
a2f2fd 155 spotless {
MH 156     java {
0e4602 157         // removeUnusedImports() TODO: reactivate once it can deal with multi-line-strings
MH 158         indentWithSpaces(4)
a2f2fd 159         endWithNewline()
MH 160         toggleOffOn()
eeab68 161
0e4602 162         target fileTree(rootDir) {
eeab68 163             include '**/*.java'
MH 164             exclude '**/generated/**/*.java'
165         }
a2f2fd 166     }
MH 167 }
80b1e0 168 project.tasks.check.dependsOn(spotlessCheck)
MH 169
a66ed8 170 // OWASP Dependency Security Test
80b1e0 171 dependencyCheck {
MH 172     cveValidForHours=4
173     format = 'ALL'
174     suppressionFile = 'etc/owasp-dependency-check-suppression.xml'
175     failOnError = true
176     failBuildOnCVSS = 7
177 }
178 project.tasks.check.dependsOn(dependencyCheckAnalyze)
4ec261 179 project.tasks.dependencyCheckAnalyze.doFirst { // Why not doLast? See README.md!
fd96bf 180     println "OWASP Dependency Security Report: file:///${project.rootDir}/build/reports/dependency-check-report.html"
MH 181 }
182
c4531c 183
a66ed8 184 // License Check
c4531c 185 licenseReport {
MH 186     excludeBoms = true
187     allowedLicensesFile = new File("$projectDir/etc/allowed-licenses.json")
188 }
189 project.tasks.check.dependsOn(checkLicense)
a66ed8 190
MH 191 // JaCoCo Test Code Coverage
192 jacoco {
193     toolVersion = "0.8.8"
194 }
195 test {
196     finalizedBy jacocoTestReport // generate report after tests
197     excludes = [
cd9be1 198             'net.hostsharing.hsadminng.**.generated.**',
a66ed8 199     ]
MH 200 }
201 jacocoTestReport {
202     dependsOn test
203     afterEvaluate {
204         classDirectories.setFrom(files(classDirectories.files.collect {
205             fileTree(dir: it, exclude: [
cd9be1 206                     "net/hostsharing/hsadminng/**/generated/**/*.class",
4e90f5 207                     "net/hostsharing/hsadminng/hs/HsadminNgApplication.class"
a66ed8 208             ])
MH 209         }))
210     }
4ec261 211     doFirst { // Why not doLast? See README.md!
a66ed8 212         println "HTML Jacoco Test Code Coverage Report: file://${reports.html.outputLocation.get()}/index.html"
MH 213     }
214 }
215 project.tasks.check.dependsOn(jacocoTestCoverageVerification)
216 jacocoTestCoverageVerification {
217     violationRules {
218         rule {
219             limit {
894150 220                 minimum = 0.92
a66ed8 221             }
MH 222         }
223
224         // element: PACKAGE, BUNDLE, CLASS, SOURCEFILE or METHOD
225         // counter:  INSTRUCTION, BRANCH, LINE, COMPLEXITY, METHOD, or CLASS
226         // value: TOTALCOUNT, COVEREDCOUNT, MISSEDCOUNT, COVEREDRATIO or MISSEDRATIO
227
228         rule {
229             element = 'CLASS'
230             excludes = [
cd9be1 231                     'net.hostsharing.hsadminng.**.generated.**',
a66ed8 232                     'net.hostsharing.hsadminng.HsadminNgApplication',
5ada0d 233                     'net.hostsharing.hsadminng.ping.PingController',
MH 234                     'net.hostsharing.hsadminng.mapper.Mapper'
a66ed8 235             ]
MH 236
237             limit {
238                 counter = 'LINE'
239                 value = 'COVEREDRATIO'
6ec4c8 240                 minimum = 0.98
a66ed8 241             }
MH 242         }
243         rule {
244             element = 'METHOD'
245             excludes = [
cd9be1 246                     'net.hostsharing.hsadminng.**.generated.**',
2124d4 247                     'net.hostsharing.hsadminng.HsadminNgApplication.main',
5ada0d 248                     'net.hostsharing.hsadminng.ping.PingController.*'
4aa8b8 249             ]
a66ed8 250
MH 251             limit {
252                 counter = 'BRANCH'
253                 value = 'COVEREDRATIO'
6ec4c8 254                 minimum = 1.00
a66ed8 255             }
MH 256         }
257     }
258 }
259
9fb661 260 // pitest mutation testing
MH 261 pitest {
262     targetClasses = ['net.hostsharing.hsadminng.**']
263     excludedClasses = [
264             'net.hostsharing.hsadminng.config.**',
af90fe 265             'net.hostsharing.hsadminng.**.*Controller',
cd9be1 266             'net.hostsharing.hsadminng.**.generated.**'
9fb661 267     ]
MH 268
269     targetTests = ['net.hostsharing.hsadminng.**.*UnitTest', 'net.hostsharing.hsadminng.**.*RestTest']
270     excludedTestClasses = ['**AcceptanceTest*', '**IntegrationTest*']
271
272     pitestVersion = '1.9.0'
273     junit5PluginVersion = '1.0.0'
274
275     threads = 4
276
277     // As Java unit tests are pretty pointless in our case, this maybe makes not much sense.
af90fe 278     mutationThreshold = 71
MH 279     coverageThreshold = 57
d3312c 280     testStrengthThreshold = 87
9fb661 281
MH 282     outputFormats = ['XML', 'HTML']
283     timestampedReports = false
284 }
285 project.tasks.check.dependsOn(project.tasks.pitest)
4ec261 286 project.tasks.pitest.doFirst { // Why not doLast? See README.md!
9fb661 287     println "PiTest Mutation Report: file:///${project.rootDir}/build/reports/pitest/index.html"
MH 288 }
289
290
8b4e78 291 // Dependency Versions Upgrade
MH 292 useLatestVersions {
293     finalizedBy check
294 }
810c39 295
MH 296 def isNonStable = { String version ->
297     def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) }
298     def regex = /^[0-9,.v-]+(-r)?$/
299     return !stableKeyword && !(version ==~ regex)
300 }
301
302 tasks.named("dependencyUpdates").configure {
303     rejectVersionIf {
304         isNonStable(it.candidate.version)
305     }
306 }