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