mirror of
https://github.com/jlengrand/detekt.git
synced 2026-03-10 08:11:23 +00:00
Extract xml and html reports to own modules (#2750)
* Move xml report to own module * Extract common complexity report logic to metrics module This allows to share complexity report logic between the console report and a report-html module. * Move whichXXX functions from DebugUtils to api module for now More modules use the detekt version at runtime and it is nice to have it in plugins as the IntelliJ or Sonar plugin. We should later move this helpers to the tooling-api. * Extract html report to own module * Merge all service files when packaging cli fatJar * Write the detekt version to all jar manifest files This allows to retrieve the detekt version from any jar at runtime. * Extract txt report to own module
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
dependencies {
|
||||
api(project(":detekt-api"))
|
||||
testImplementation(project(":detekt-test-utils"))
|
||||
testImplementation(project(":detekt-test"))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.github.detekt.metrics
|
||||
|
||||
import io.github.detekt.metrics.processors.commentLinesKey
|
||||
import io.github.detekt.metrics.processors.complexityKey
|
||||
import io.github.detekt.metrics.processors.linesKey
|
||||
import io.github.detekt.metrics.processors.logicalLinesKey
|
||||
import io.github.detekt.metrics.processors.sourceLinesKey
|
||||
import io.gitlab.arturbosch.detekt.api.Detektion
|
||||
|
||||
class ComplexityMetric(detektion: Detektion) {
|
||||
|
||||
val mcc = detektion.getData(complexityKey)
|
||||
val cognitiveComplexity = detektion.getData(CognitiveComplexity.KEY)
|
||||
val loc = detektion.getData(linesKey)
|
||||
val sloc = detektion.getData(sourceLinesKey)
|
||||
val lloc = detektion.getData(logicalLinesKey)
|
||||
val cloc = detektion.getData(commentLinesKey)
|
||||
val findings = detektion.findings.entries
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package io.github.detekt.metrics
|
||||
|
||||
import io.gitlab.arturbosch.detekt.api.Detektion
|
||||
import java.util.Locale
|
||||
|
||||
class ComplexityReportGenerator(private val complexityMetric: ComplexityMetric) {
|
||||
|
||||
private var numberOfSmells = 0
|
||||
private var smellPerThousandLines = 0
|
||||
private var mccPerThousandLines = 0
|
||||
private var commentSourceRatio = 0
|
||||
|
||||
companion object Factory {
|
||||
fun create(detektion: Detektion): ComplexityReportGenerator =
|
||||
ComplexityReportGenerator(ComplexityMetric(detektion))
|
||||
}
|
||||
|
||||
fun generate(): List<String>? {
|
||||
if (cannotGenerate()) return null
|
||||
return listOf(
|
||||
"%,d lines of code (loc)".format(Locale.US, complexityMetric.loc),
|
||||
"%,d source lines of code (sloc)".format(Locale.US, complexityMetric.sloc),
|
||||
"%,d logical lines of code (lloc)".format(Locale.US, complexityMetric.lloc),
|
||||
"%,d comment lines of code (cloc)".format(Locale.US, complexityMetric.cloc),
|
||||
"%,d cyclomatic complexity (mcc)".format(Locale.US, complexityMetric.mcc),
|
||||
"%,d cognitive complexity".format(Locale.US, complexityMetric.cognitiveComplexity),
|
||||
"%,d number of total code smells".format(Locale.US, numberOfSmells),
|
||||
"%,d%% comment source ratio".format(Locale.US, commentSourceRatio),
|
||||
"%,d mcc per 1,000 lloc".format(Locale.US, mccPerThousandLines),
|
||||
"%,d code smells per 1,000 lloc".format(Locale.US, smellPerThousandLines)
|
||||
)
|
||||
}
|
||||
|
||||
private fun cannotGenerate(): Boolean {
|
||||
return when {
|
||||
null in setOf(
|
||||
complexityMetric.mcc,
|
||||
complexityMetric.cloc,
|
||||
complexityMetric.cognitiveComplexity
|
||||
) -> true
|
||||
complexityMetric.lloc == null || complexityMetric.lloc == 0 -> true
|
||||
complexityMetric.sloc == null || complexityMetric.sloc == 0 -> true
|
||||
else -> {
|
||||
numberOfSmells = complexityMetric.findings.sumBy { it.value.size }
|
||||
smellPerThousandLines = numberOfSmells * 1000 / complexityMetric.lloc
|
||||
mccPerThousandLines = complexityMetric.mcc!! * 1000 / complexityMetric.lloc
|
||||
commentSourceRatio = complexityMetric.cloc!! * 100 / complexityMetric.sloc
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package io.github.detekt.metrics
|
||||
|
||||
import io.github.detekt.metrics.processors.commentLinesKey
|
||||
import io.github.detekt.metrics.processors.complexityKey
|
||||
import io.github.detekt.metrics.processors.linesKey
|
||||
import io.github.detekt.metrics.processors.logicalLinesKey
|
||||
import io.github.detekt.metrics.processors.sourceLinesKey
|
||||
import io.gitlab.arturbosch.detekt.api.Detektion
|
||||
import io.gitlab.arturbosch.detekt.api.Finding
|
||||
import io.gitlab.arturbosch.detekt.test.TestDetektion
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.spekframework.spek2.Spek
|
||||
import org.spekframework.spek2.style.specification.describe
|
||||
|
||||
internal class ComplexityReportGeneratorSpec : Spek({
|
||||
|
||||
describe("complexity report generator") {
|
||||
|
||||
lateinit var detektion: TestDetektion
|
||||
|
||||
beforeEachTest {
|
||||
val finding = mockk<Finding>()
|
||||
every { finding.id }.returns("test")
|
||||
detektion = TestDetektion(finding)
|
||||
addData(detektion)
|
||||
}
|
||||
|
||||
context("several complexity metrics") {
|
||||
|
||||
it("successfully generates a complexity report") {
|
||||
val expectedContent = listOf(
|
||||
"1,000 lines of code (loc)",
|
||||
"6 source lines of code (sloc)",
|
||||
"5 logical lines of code (lloc)",
|
||||
"4 comment lines of code (cloc)",
|
||||
"2 cyclomatic complexity (mcc)",
|
||||
"2 cognitive complexity",
|
||||
"1 number of total code smells",
|
||||
"66% comment source ratio",
|
||||
"400 mcc per 1,000 lloc",
|
||||
"200 code smells per 1,000 lloc"
|
||||
)
|
||||
|
||||
assertThat(generateComplexityReport(detektion)).isEqualTo(expectedContent)
|
||||
}
|
||||
}
|
||||
|
||||
context("several invalid complexity metrics") {
|
||||
|
||||
it("returns null for missing mcc") {
|
||||
detektion.removeData(complexityKey)
|
||||
assertThat(generateComplexityReport(detektion)).isNull()
|
||||
}
|
||||
|
||||
it("returns null for missing lloc") {
|
||||
detektion.removeData(logicalLinesKey)
|
||||
assertThat(generateComplexityReport(detektion)).isNull()
|
||||
|
||||
detektion.addData(logicalLinesKey, 0)
|
||||
assertThat(generateComplexityReport(detektion)).isNull()
|
||||
}
|
||||
|
||||
it("returns null for missing sloc") {
|
||||
detektion.removeData(sourceLinesKey)
|
||||
assertThat(generateComplexityReport(detektion)).isNull()
|
||||
|
||||
detektion.addData(sourceLinesKey, 0)
|
||||
assertThat(generateComplexityReport(detektion)).isNull()
|
||||
}
|
||||
|
||||
it("returns null for missing cloc") {
|
||||
detektion.removeData(complexityKey)
|
||||
assertThat(generateComplexityReport(detektion)).isNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
private fun addData(detektion: Detektion) {
|
||||
detektion.addData(complexityKey, 2)
|
||||
detektion.addData(CognitiveComplexity.KEY, 2)
|
||||
detektion.addData(linesKey, 1000)
|
||||
detektion.addData(sourceLinesKey, 6)
|
||||
detektion.addData(logicalLinesKey, 5)
|
||||
detektion.addData(commentLinesKey, 4)
|
||||
}
|
||||
|
||||
private fun generateComplexityReport(detektion: Detektion): List<String>? {
|
||||
val complexityMetric = ComplexityMetric(detektion)
|
||||
val generator = ComplexityReportGenerator(complexityMetric)
|
||||
return generator.generate()
|
||||
}
|
||||
Reference in New Issue
Block a user