Michael Hoennig
2022-10-25 d7eed084202ed16b1c8a2514dae0ca94018a1c74
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
d7eed0 101 // Configure tests
6c33bb 102 tasks.named('test') {
MH 103     useJUnitPlatform()
d7eed0 104     jvmArgs '-Duser.language=en'
MH 105     jvmArgs '-Duser.country=US'
6c33bb 106 }
a2f2fd 107
a66ed8 108 // OpenAPI Source Code Generation
eeab68 109 openapiProcessor {
cd9be1 110     springRoot {
MH 111         processorName 'spring'
67e850 112         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
eeab68 113         apiPath "$projectDir/src/main/resources/api-definition.yaml"
MH 114         mapping "$projectDir/src/main/resources/api-mappings.yaml"
cd9be1 115         targetDir "$projectDir/build/generated/sources/openapi"
MH 116         showWarnings true
117         openApiNullable true
118     }
119     springRbac {
120         processorName 'spring'
67e850 121         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
cd9be1 122         apiPath "$projectDir/src/main/resources/api-definition/rbac/rbac.yaml"
MH 123         mapping "$projectDir/src/main/resources/api-definition/rbac/api-mappings.yaml"
124         targetDir "$projectDir/build/generated/sources/openapi"
125         showWarnings true
126         openApiNullable true
127     }
128     springTest {
129         processorName 'spring'
67e850 130         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
cd9be1 131         apiPath "$projectDir/src/main/resources/api-definition/test/test.yaml"
MH 132         mapping "$projectDir/src/main/resources/api-definition/test/api-mappings.yaml"
133         targetDir "$projectDir/build/generated/sources/openapi"
eeab68 134         showWarnings true
0e4602 135         openApiNullable true
eeab68 136     }
af90fe 137     springHs {
MH 138         processorName 'spring'
67e850 139         processor 'io.openapiprocessor:openapi-processor-spring:2022.5'
4e90f5 140         apiPath "$projectDir/src/main/resources/api-definition/hs-office/hs-office.yaml"
MH 141         mapping "$projectDir/src/main/resources/api-definition/hs-office/api-mappings.yaml"
af90fe 142         targetDir "$projectDir/build/generated/sources/openapi"
MH 143         showWarnings true
144         openApiNullable true
145     }
eeab68 146 }
MH 147 sourceSets.main.java.srcDir 'build/generated/sources/openapi'
af90fe 148 abstract class ProcessSpring extends DefaultTask {}
MH 149 tasks.register('processSpring', ProcessSpring)
150 ['processSpringRoot', 'processSpringRbac', 'processSpringTest', 'processSpringHs'].each {
151     project.tasks.processSpring.dependsOn it
cd9be1 152 }
af90fe 153 project.tasks.processResources.dependsOn processSpring
MH 154 project.tasks.compileJava.dependsOn processSpring
eeab68 155
a66ed8 156 // Spotless Code Formatting
a2f2fd 157 spotless {
MH 158     java {
0e4602 159         // removeUnusedImports() TODO: reactivate once it can deal with multi-line-strings
MH 160         indentWithSpaces(4)
a2f2fd 161         endWithNewline()
MH 162         toggleOffOn()
eeab68 163
0e4602 164         target fileTree(rootDir) {
eeab68 165             include '**/*.java'
MH 166             exclude '**/generated/**/*.java'
167         }
a2f2fd 168     }
MH 169 }
80b1e0 170 project.tasks.check.dependsOn(spotlessCheck)
MH 171
a66ed8 172 // OWASP Dependency Security Test
80b1e0 173 dependencyCheck {
MH 174     cveValidForHours=4
175     format = 'ALL'
176     suppressionFile = 'etc/owasp-dependency-check-suppression.xml'
177     failOnError = true
178     failBuildOnCVSS = 7
179 }
180 project.tasks.check.dependsOn(dependencyCheckAnalyze)
4ec261 181 project.tasks.dependencyCheckAnalyze.doFirst { // Why not doLast? See README.md!
fd96bf 182     println "OWASP Dependency Security Report: file:///${project.rootDir}/build/reports/dependency-check-report.html"
MH 183 }
184
c4531c 185
a66ed8 186 // License Check
c4531c 187 licenseReport {
MH 188     excludeBoms = true
189     allowedLicensesFile = new File("$projectDir/etc/allowed-licenses.json")
190 }
191 project.tasks.check.dependsOn(checkLicense)
a66ed8 192
MH 193 // JaCoCo Test Code Coverage
194 jacoco {
195     toolVersion = "0.8.8"
196 }
197 test {
198     finalizedBy jacocoTestReport // generate report after tests
199     excludes = [
cd9be1 200             'net.hostsharing.hsadminng.**.generated.**',
a66ed8 201     ]
MH 202 }
203 jacocoTestReport {
204     dependsOn test
205     afterEvaluate {
206         classDirectories.setFrom(files(classDirectories.files.collect {
207             fileTree(dir: it, exclude: [
cd9be1 208                     "net/hostsharing/hsadminng/**/generated/**/*.class",
4e90f5 209                     "net/hostsharing/hsadminng/hs/HsadminNgApplication.class"
a66ed8 210             ])
MH 211         }))
212     }
4ec261 213     doFirst { // Why not doLast? See README.md!
a66ed8 214         println "HTML Jacoco Test Code Coverage Report: file://${reports.html.outputLocation.get()}/index.html"
MH 215     }
216 }
217 project.tasks.check.dependsOn(jacocoTestCoverageVerification)
218 jacocoTestCoverageVerification {
219     violationRules {
220         rule {
221             limit {
894150 222                 minimum = 0.92
a66ed8 223             }
MH 224         }
225
226         // element: PACKAGE, BUNDLE, CLASS, SOURCEFILE or METHOD
227         // counter:  INSTRUCTION, BRANCH, LINE, COMPLEXITY, METHOD, or CLASS
228         // value: TOTALCOUNT, COVEREDCOUNT, MISSEDCOUNT, COVEREDRATIO or MISSEDRATIO
229
230         rule {
231             element = 'CLASS'
232             excludes = [
cd9be1 233                     'net.hostsharing.hsadminng.**.generated.**',
a66ed8 234                     'net.hostsharing.hsadminng.HsadminNgApplication',
5ada0d 235                     'net.hostsharing.hsadminng.ping.PingController',
MH 236                     'net.hostsharing.hsadminng.mapper.Mapper'
a66ed8 237             ]
MH 238
239             limit {
240                 counter = 'LINE'
241                 value = 'COVEREDRATIO'
6ec4c8 242                 minimum = 0.98
a66ed8 243             }
MH 244         }
245         rule {
246             element = 'METHOD'
247             excludes = [
cd9be1 248                     'net.hostsharing.hsadminng.**.generated.**',
2124d4 249                     'net.hostsharing.hsadminng.HsadminNgApplication.main',
5ada0d 250                     'net.hostsharing.hsadminng.ping.PingController.*'
4aa8b8 251             ]
a66ed8 252
MH 253             limit {
254                 counter = 'BRANCH'
255                 value = 'COVEREDRATIO'
6ec4c8 256                 minimum = 1.00
a66ed8 257             }
MH 258         }
259     }
260 }
261
9fb661 262 // pitest mutation testing
MH 263 pitest {
264     targetClasses = ['net.hostsharing.hsadminng.**']
265     excludedClasses = [
266             'net.hostsharing.hsadminng.config.**',
af90fe 267             'net.hostsharing.hsadminng.**.*Controller',
cd9be1 268             'net.hostsharing.hsadminng.**.generated.**'
9fb661 269     ]
MH 270
271     targetTests = ['net.hostsharing.hsadminng.**.*UnitTest', 'net.hostsharing.hsadminng.**.*RestTest']
272     excludedTestClasses = ['**AcceptanceTest*', '**IntegrationTest*']
273
274     pitestVersion = '1.9.0'
275     junit5PluginVersion = '1.0.0'
276
277     threads = 4
278
279     // As Java unit tests are pretty pointless in our case, this maybe makes not much sense.
af90fe 280     mutationThreshold = 71
MH 281     coverageThreshold = 57
d3312c 282     testStrengthThreshold = 87
9fb661 283
MH 284     outputFormats = ['XML', 'HTML']
285     timestampedReports = false
286 }
287 project.tasks.check.dependsOn(project.tasks.pitest)
4ec261 288 project.tasks.pitest.doFirst { // Why not doLast? See README.md!
9fb661 289     println "PiTest Mutation Report: file:///${project.rootDir}/build/reports/pitest/index.html"
MH 290 }
291
292
8b4e78 293 // Dependency Versions Upgrade
MH 294 useLatestVersions {
295     finalizedBy check
296 }
810c39 297
MH 298 def isNonStable = { String version ->
299     def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) }
300     def regex = /^[0-9,.v-]+(-r)?$/
301     return !stableKeyword && !(version ==~ regex)
302 }
303
304 tasks.named("dependencyUpdates").configure {
305     rejectVersionIf {
306         isNonStable(it.candidate.version)
307     }
308 }