Skip to content

Commit

Permalink
Use OutputReport project base path to handle relative path output
Browse files Browse the repository at this point in the history
  • Loading branch information
3flex committed Apr 27, 2024
1 parent 86b5741 commit 323d8ff
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 14 deletions.
Expand Up @@ -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
Expand All @@ -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@@@"
Expand All @@ -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<Path>(DETEKT_OUTPUT_REPORT_BASE_PATH_KEY)?.absolute()
}

override fun render(detektion: Detektion) =
javaClass.getResource("/$DEFAULT_TEMPLATE")!!
.openSafeStream()
Expand Down Expand Up @@ -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(
Expand Down
Expand Up @@ -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("<span class=\"location\">src/main/com/sample/Sample1.kt:11:1</span>")
Expand Down Expand Up @@ -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,
),
Expand All @@ -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,
)
)
Expand Down
Expand Up @@ -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

Expand All @@ -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<Path>(DETEKT_OUTPUT_REPORT_BASE_PATH_KEY)?.absolute()
}

override fun render(detektion: Detektion) = markdown {
h1 { "detekt" }

Expand All @@ -48,7 +59,7 @@ class MdOutputReport : BuiltInOutputReport, OutputReport() {
h2 { "Complexity Report" }
renderComplexity(getComplexityMetrics(detektion))

renderIssues(detektion.issues)
renderIssues(detektion.issues, basePath)
emptyLine()

paragraph {
Expand Down Expand Up @@ -81,17 +92,17 @@ private fun MarkdownContent.renderComplexity(complexityReport: List<String>) {
}
}

private fun MarkdownContent.renderGroup(issues: List<Issue>) {
private fun MarkdownContent.renderGroup(issues: List<Issue>, 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<Issue>) {
private fun MarkdownContent.renderRule(ruleInfo: Issue.RuleInfo, issues: List<Issue>, basePath: Path?) {
val ruleId = ruleInfo.id.value
val ruleSetId = ruleInfo.ruleSetId.value
h3 { "$ruleSetId, $ruleId (%,d)".format(Locale.ROOT, issues.size) }
Expand All @@ -114,12 +125,12 @@ private fun MarkdownContent.renderRule(ruleInfo: Issue.RuleInfo, issues: List<Is
)
)
.forEach {
item { renderIssue(it) }
item { renderIssue(it, basePath) }
}
}
}

private fun MarkdownContent.renderIssues(issues: List<Issue>) {
private fun MarkdownContent.renderIssues(issues: List<Issue>, basePath: Path?) {
val total = issues.count()

h2 { "Issues (%,d)".format(Locale.ROOT, total) }
Expand All @@ -129,12 +140,13 @@ private fun MarkdownContent.renderIssues(issues: List<Issue>) {
.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}"

Expand Down
Expand Up @@ -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.
Expand All @@ -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<Path>(DETEKT_OUTPUT_REPORT_BASE_PATH_KEY)?.absolute()
}

override fun render(detektion: Detektion): String {
val lines = ArrayList<String>()
lines += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
lines += "<checkstyle version=\"4.3\">"

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 += "<file name=\"${filePath.invariantSeparatorsPathString.toXmlString()}\">"
issues.forEach {
Expand Down
Expand Up @@ -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"
Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit 323d8ff

Please sign in to comment.