diff --git a/detekt-report-html/src/main/kotlin/io/github/detekt/report/html/HtmlOutputReport.kt b/detekt-report-html/src/main/kotlin/io/github/detekt/report/html/HtmlOutputReport.kt index bbbf1ebb08e..91c82f955e9 100644 --- a/detekt-report-html/src/main/kotlin/io/github/detekt/report/html/HtmlOutputReport.kt +++ b/detekt-report-html/src/main/kotlin/io/github/detekt/report/html/HtmlOutputReport.kt @@ -7,7 +7,9 @@ import io.gitlab.arturbosch.detekt.api.Issue import io.gitlab.arturbosch.detekt.api.OutputReport import io.gitlab.arturbosch.detekt.api.ProjectMetric import io.gitlab.arturbosch.detekt.api.RuleSet +import io.gitlab.arturbosch.detekt.api.SetupContext import io.gitlab.arturbosch.detekt.api.TextLocation +import io.gitlab.arturbosch.detekt.api.getOrNull import io.gitlab.arturbosch.detekt.api.internal.BuiltInOutputReport import io.gitlab.arturbosch.detekt.api.internal.whichDetekt import kotlinx.html.CommonAttributeGroupFacadeFlowInteractiveContent @@ -27,11 +29,14 @@ import kotlinx.html.span import kotlinx.html.stream.createHTML import kotlinx.html.ul import kotlinx.html.visit +import java.nio.file.Path import java.time.OffsetDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter import java.util.Locale +import kotlin.io.path.absolute import kotlin.io.path.invariantSeparatorsPathString +import kotlin.io.path.relativeTo private const val DEFAULT_TEMPLATE = "default-html-report-template.html" private const val PLACEHOLDER_METRICS = "@@@metrics@@@" @@ -51,6 +56,12 @@ class HtmlOutputReport : BuiltInOutputReport, OutputReport() { override val id: String = "HtmlOutputReport" override val ending = "html" + var basePath: Path? = null + + override fun init(context: SetupContext) { + basePath = context.getOrNull(DETEKT_OUTPUT_REPORT_BASE_PATH_KEY)?.absolute() + } + override fun render(detektion: Detektion) = javaClass.getResource("/$DEFAULT_TEMPLATE")!! .openSafeStream() @@ -146,7 +157,8 @@ class HtmlOutputReport : BuiltInOutputReport, OutputReport() { } private fun FlowContent.renderIssue(issue: Issue) { - val filePath = issue.location.filePath.relativePath ?: issue.location.filePath.absolutePath + val filePath = basePath?.let { issue.location.filePath.absolutePath.relativeTo(it) } + ?: issue.location.filePath.absolutePath val pathString = filePath.invariantSeparatorsPathString span("location") { text( diff --git a/detekt-report-html/src/test/kotlin/io/github/detekt/report/html/HtmlOutputReportSpec.kt b/detekt-report-html/src/test/kotlin/io/github/detekt/report/html/HtmlOutputReportSpec.kt index 5d526779b3d..3189e08c88a 100644 --- a/detekt-report-html/src/test/kotlin/io/github/detekt/report/html/HtmlOutputReportSpec.kt +++ b/detekt-report-html/src/test/kotlin/io/github/detekt/report/html/HtmlOutputReportSpec.kt @@ -82,6 +82,9 @@ class HtmlOutputReportSpec { @Test fun `renders the right file locations for relative paths`() { + val htmlReport = HtmlOutputReport() + htmlReport.basePath = Path("Users/tester/detekt/").absolute() + val result = htmlReport.render(createTestDetektionFromRelativePath()) assertThat(result).contains("src/main/com/sample/Sample1.kt:11:1") @@ -208,10 +211,11 @@ private fun createTestDetektionWithMultipleSmells(): Detektion { } private fun createTestDetektionFromRelativePath(): Detektion { + val basePath = "${System.getProperty("user.dir")}/Users/tester/detekt/" val entity1 = createEntity( location = createLocation( path = "src/main/com/sample/Sample1.kt", - basePath = "Users/tester/detekt/", + basePath = basePath, position = 11 to 1, text = 10..14, ), @@ -220,14 +224,14 @@ private fun createTestDetektionFromRelativePath(): Detektion { val entity2 = createEntity( location = createLocation( path = "src/main/com/sample/Sample2.kt", - basePath = "Users/tester/detekt/", + basePath = basePath, position = 22 to 2, ) ) val entity3 = createEntity( location = createLocation( path = "src/main/com/sample/Sample3.kt", - basePath = "Users/tester/detekt/", + basePath = basePath, position = 33 to 3, ) ) diff --git a/detekt-report-md/src/main/kotlin/io/github/detekt/report/md/MdOutputReport.kt b/detekt-report-md/src/main/kotlin/io/github/detekt/report/md/MdOutputReport.kt index 71f4ef27f87..028036b1536 100644 --- a/detekt-report-md/src/main/kotlin/io/github/detekt/report/md/MdOutputReport.kt +++ b/detekt-report-md/src/main/kotlin/io/github/detekt/report/md/MdOutputReport.kt @@ -15,14 +15,19 @@ import io.gitlab.arturbosch.detekt.api.Detektion import io.gitlab.arturbosch.detekt.api.Issue import io.gitlab.arturbosch.detekt.api.OutputReport import io.gitlab.arturbosch.detekt.api.ProjectMetric +import io.gitlab.arturbosch.detekt.api.SetupContext import io.gitlab.arturbosch.detekt.api.SourceLocation +import io.gitlab.arturbosch.detekt.api.getOrNull import io.gitlab.arturbosch.detekt.api.internal.BuiltInOutputReport import io.gitlab.arturbosch.detekt.api.internal.whichDetekt +import java.nio.file.Path import java.time.OffsetDateTime import java.time.ZoneOffset import java.time.format.DateTimeFormatter import java.util.Locale +import kotlin.io.path.absolute import kotlin.io.path.invariantSeparatorsPathString +import kotlin.io.path.relativeTo import kotlin.math.max import kotlin.math.min @@ -39,6 +44,12 @@ class MdOutputReport : BuiltInOutputReport, OutputReport() { override val id: String = "MdOutputReport" override val ending: String = "md" + var basePath: Path? = null + + override fun init(context: SetupContext) { + basePath = context.getOrNull(DETEKT_OUTPUT_REPORT_BASE_PATH_KEY)?.absolute() + } + override fun render(detektion: Detektion) = markdown { h1 { "detekt" } @@ -48,7 +59,7 @@ class MdOutputReport : BuiltInOutputReport, OutputReport() { h2 { "Complexity Report" } renderComplexity(getComplexityMetrics(detektion)) - renderIssues(detektion.issues) + renderIssues(detektion.issues, basePath) emptyLine() paragraph { @@ -81,17 +92,17 @@ private fun MarkdownContent.renderComplexity(complexityReport: List) { } } -private fun MarkdownContent.renderGroup(issues: List) { +private fun MarkdownContent.renderGroup(issues: List, basePath: Path?) { issues .groupBy { it.ruleInfo } .toList() .sortedBy { (ruleInfo, _) -> ruleInfo.id.value } .forEach { (ruleInfo, ruleIssues) -> - renderRule(ruleInfo, ruleIssues) + renderRule(ruleInfo, ruleIssues, basePath) } } -private fun MarkdownContent.renderRule(ruleInfo: Issue.RuleInfo, issues: List) { +private fun MarkdownContent.renderRule(ruleInfo: Issue.RuleInfo, issues: List, basePath: Path?) { val ruleId = ruleInfo.id.value val ruleSetId = ruleInfo.ruleSetId.value h3 { "$ruleSetId, $ruleId (%,d)".format(Locale.ROOT, issues.size) } @@ -114,12 +125,12 @@ private fun MarkdownContent.renderRule(ruleInfo: Issue.RuleInfo, issues: List) { +private fun MarkdownContent.renderIssues(issues: List, basePath: Path?) { val total = issues.count() h2 { "Issues (%,d)".format(Locale.ROOT, total) } @@ -129,12 +140,13 @@ private fun MarkdownContent.renderIssues(issues: List) { .toList() .sortedBy { (group, _) -> group.value } .forEach { (_, groupIssues) -> - renderGroup(groupIssues) + renderGroup(groupIssues, basePath) } } -private fun MarkdownContent.renderIssue(issue: Issue): String { - val filePath = issue.location.filePath.relativePath ?: issue.location.filePath.absolutePath +private fun MarkdownContent.renderIssue(issue: Issue, basePath: Path?): String { + val filePath = basePath?.let { issue.location.filePath.absolutePath.relativeTo(it) } + ?: issue.location.filePath.absolutePath val location = "${filePath.invariantSeparatorsPathString}:${issue.location.source.line}:${issue.location.source.column}" diff --git a/detekt-report-xml/src/main/kotlin/io/github/detekt/report/xml/XmlOutputReport.kt b/detekt-report-xml/src/main/kotlin/io/github/detekt/report/xml/XmlOutputReport.kt index 8a4c00ba1b7..831b939f99e 100644 --- a/detekt-report-xml/src/main/kotlin/io/github/detekt/report/xml/XmlOutputReport.kt +++ b/detekt-report-xml/src/main/kotlin/io/github/detekt/report/xml/XmlOutputReport.kt @@ -3,9 +3,14 @@ package io.github.detekt.report.xml import io.gitlab.arturbosch.detekt.api.Detektion import io.gitlab.arturbosch.detekt.api.Issue import io.gitlab.arturbosch.detekt.api.OutputReport +import io.gitlab.arturbosch.detekt.api.SetupContext +import io.gitlab.arturbosch.detekt.api.getOrNull import io.gitlab.arturbosch.detekt.api.internal.BuiltInOutputReport +import java.nio.file.Path import java.util.Locale +import kotlin.io.path.absolute import kotlin.io.path.invariantSeparatorsPathString +import kotlin.io.path.relativeTo /** * Contains rule violations in an XML format. The report follows the structure of a Checkstyle report. @@ -19,13 +24,22 @@ class XmlOutputReport : BuiltInOutputReport, OutputReport() { private val Issue.severityLabel: String get() = severity.name.lowercase(Locale.US) + var basePath: Path? = null + + override fun init(context: SetupContext) { + basePath = context.getOrNull(DETEKT_OUTPUT_REPORT_BASE_PATH_KEY)?.absolute() + } + override fun render(detektion: Detektion): String { val lines = ArrayList() lines += "" lines += "" detektion.issues - .groupBy { it.location.filePath.relativePath ?: it.location.filePath.absolutePath } + .groupBy { + basePath?.let { path -> it.location.filePath.absolutePath.relativeTo(path) } + ?: it.location.filePath.absolutePath + } .forEach { (filePath, issues) -> lines += "" issues.forEach { diff --git a/detekt-report-xml/src/test/kotlin/io/github/detekt/report/xml/XmlOutputFormatSpec.kt b/detekt-report-xml/src/test/kotlin/io/github/detekt/report/xml/XmlOutputFormatSpec.kt index e305ff9334a..64037bba763 100644 --- a/detekt-report-xml/src/test/kotlin/io/github/detekt/report/xml/XmlOutputFormatSpec.kt +++ b/detekt-report-xml/src/test/kotlin/io/github/detekt/report/xml/XmlOutputFormatSpec.kt @@ -13,6 +13,8 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.EnumSource import java.util.Locale +import kotlin.io.path.Path +import kotlin.io.path.absolute import kotlin.io.path.invariantSeparatorsPathString private const val TAB = "\t" @@ -114,13 +116,18 @@ class XmlOutputFormatSpec { fun `renders issues with relative path`() { val issueA = createIssueForRelativePath( ruleInfo = createRuleInfo("id_a"), + basePath = "${System.getProperty("user.dir")}/Users/tester/detekt/", relativePath = "Sample1.kt" ) val issueB = createIssueForRelativePath( ruleInfo = createRuleInfo("id_b"), + basePath = "${System.getProperty("user.dir")}/Users/tester/detekt/", relativePath = "Sample2.kt" ) + val outputFormat = XmlOutputReport() + outputFormat.basePath = Path("Users/tester/detekt/").absolute() + val result = outputFormat.render(TestDetektion(issueA, issueB)) assertThat(result).isEqualTo(