From a8947ce318f7ae2b5cf9911f1b35b427ec0d1cc7 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:06:28 -0500 Subject: [PATCH 01/18] =?UTF-8?q?=E2=9E=95=20Add=20JGit=20dependency=20to?= =?UTF-8?q?=20techdebt=20plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated `build.gradle.kts` to include JGit as a new dependency for version control operations. --- gradle/libs.versions.toml | 2 ++ techdebt-gradle-plugin/build.gradle.kts | 1 + 2 files changed, 3 insertions(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3165dbe..cb71cba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,6 +9,7 @@ junit-platform = "1.10.1" ksp = "2.3.4" android-gradle-plugin = "8.13.2" maven-publish = "0.35.0" +jgit = "7.5.0.202512021534-r" detekt = "1.23.4" ktfmt = "0.16.0" @@ -23,6 +24,7 @@ kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit" } junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit" } junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version.ref = "junit-platform" } +jgit = { group = "org.eclipse.jgit", name = "org.eclipse.jgit", version.ref = "jgit" } [plugins] kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } diff --git a/techdebt-gradle-plugin/build.gradle.kts b/techdebt-gradle-plugin/build.gradle.kts index 36fec68..c36a296 100644 --- a/techdebt-gradle-plugin/build.gradle.kts +++ b/techdebt-gradle-plugin/build.gradle.kts @@ -24,6 +24,7 @@ dependencies { implementation(libs.kotlin.gradle.plugin) implementation(libs.ksp.gradle.plugin) implementation(libs.android.gradle.plugin) + implementation(libs.jgit) testImplementation(libs.junit.jupiter.api) testRuntimeOnly(libs.junit.jupiter.engine) From 0333c056437b7c5a7dc86441c04f5ac021e347da Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:07:01 -0500 Subject: [PATCH 02/18] =?UTF-8?q?=F0=9F=AA=9B=20Add=20`lastModified`=20and?= =?UTF-8?q?=20`author`=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced two new optional fields, `lastModified` and `author`, in `TechDebtItem` for tracking technical debt metadata. Enhanced source location management by adding the `getSourceLocation` utility function to resolve more precise locations. Refactored processors to leverage this updated logic. --- .../gradle/GenerateTechDebtReportTask.kt | 22 ++-- .../techdebt/gradle/TechDebtExtension.kt | 3 + .../escodro/techdebt/gradle/TechDebtPlugin.kt | 2 + .../techdebt/gradle/model/TechDebtItem.kt | 4 +- .../gradle/parser/GeneratedTechDebtParser.kt | 31 +++-- .../techdebt/gradle/parser/GitParser.kt | 109 ++++++++++++++++++ .../gradle/parser/SourceFileResolver.kt | 45 ++++++++ .../techdebt/gradle/report/CardGenerator.kt | 18 ++- .../extension/KSAnnotationExtensions.kt | 19 +++ .../processor/SuppressSymbolProcessor.kt | 9 +- .../processor/TechDebtSymbolProcessor.kt | 9 +- .../escodro/techdebt/report/TechDebtItem.kt | 4 +- 12 files changed, 248 insertions(+), 27 deletions(-) create mode 100644 techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt create mode 100644 techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt index 4a587a9..660459b 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt @@ -3,6 +3,7 @@ package com.escodro.techdebt.gradle import com.escodro.techdebt.gradle.model.TechDebtItem import com.escodro.techdebt.gradle.parser.CommentParser import com.escodro.techdebt.gradle.parser.GeneratedTechDebtParser +import com.escodro.techdebt.gradle.parser.GitParser import com.escodro.techdebt.gradle.report.HtmlReportGenerator import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection @@ -24,6 +25,9 @@ abstract class GenerateTechDebtReportTask : DefaultTask() { /** Whether to collect TODO/FIXME comments. Defaults to `false`. */ @get:Input abstract val collectComments: Property + /** Whether to enable Git metadata (e.g. last modified date). Defaults to `false`. */ + @get:Input abstract val enableGitMetadata: Property + /** * Map of project directory to project path. Used to resolve the module name for TODO comments * without accessing the Project object at execution time. @@ -43,25 +47,29 @@ abstract class GenerateTechDebtReportTask : DefaultTask() { private val jsonParser: GeneratedTechDebtParser = GeneratedTechDebtParser() - private val commentParser: CommentParser = CommentParser() - @TaskAction fun generate() { val allItems = mutableListOf() allItems += jsonParser.parse(jsonFiles) + val rootProjectDir = project.rootProject.projectDir if (collectComments.get()) { allItems += - commentParser.parse( - sourceFiles = sourceFiles, - projectPaths = projectPathByDirectory.get() - ) + CommentParser() + .parse(sourceFiles = sourceFiles, projectPaths = projectPathByDirectory.get()) } val aggregatedItems = aggregateItems(allItems) + val itemsWithMetadata = + if (enableGitMetadata.get()) { + GitParser(rootProjectDir).parse(aggregatedItems) + } else { + aggregatedItems + } + val sortedItems = - aggregatedItems.sortedWith(compareBy({ it.moduleName }, { it.priorityOrder })) + itemsWithMetadata.sortedWith(compareBy({ it.moduleName }, { it.priorityOrder })) writeReport(sortedItems) } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtExtension.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtExtension.kt index 207e5c8..f3fd7ae 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtExtension.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtExtension.kt @@ -18,6 +18,9 @@ abstract class TechDebtExtension { /** Whether to collect TODO/FIXME comments. Defaults to `false`. */ abstract val collectComments: Property + /** Whether to enable Git metadata (e.g. last modified date). Defaults to `false`. */ + abstract val enableGitMetadata: Property + /** * The base URL for the tickets. If set, the ticket property in the HTML report will be a link. */ diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt index 9a9394a..e2fd8b7 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt @@ -16,6 +16,7 @@ class TechDebtPlugin : Plugin { project.extensions.create("techDebtReport", TechDebtExtension::class.java) extension.collectSuppress.convention(false) extension.collectComments.convention(false) + extension.enableGitMetadata.convention(false) val reportTask: TaskProvider = project.tasks.register( @@ -23,6 +24,7 @@ class TechDebtPlugin : Plugin { GenerateTechDebtReportTask::class.java ) { task -> task.collectComments.set(extension.collectComments) + task.enableGitMetadata.set(extension.enableGitMetadata) task.baseTicketUrl.set(extension.baseTicketUrl) task.projectPathByDirectory.set( project.allprojects.associate { it.projectDir.absolutePath to it.path } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt index de570e2..08b500e 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt @@ -21,7 +21,9 @@ data class TechDebtItem( val ticket: String, val priority: String, val sourceSet: String, - val type: TechDebtItemType = TechDebtItemType.TECH_DEBT + val type: TechDebtItemType = TechDebtItemType.TECH_DEBT, + val lastModified: String? = null, + val author: String? = null, ) { /** * Returns the priority order for the tech debt item. diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt index 5dd92a4..cddf07f 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt @@ -19,11 +19,13 @@ internal class GeneratedTechDebtParser { if (file.exists()) { val items = Json.decodeFromString>(file.readText()) val updatedItems = - if (items.any { it.sourceSet == "unknown" }) { - val sourceSet = resolveSourceSet(file.absolutePath) - items.map { it.copy(sourceSet = sourceSet) } - } else { - items + items.map { item -> + if (shouldResolveSourceSet(item.sourceSet)) { + val sourceSet = resolveSourceSet(file.absolutePath) + item.copy(sourceSet = sourceSet) + } else { + item + } } allItems.addAll(updatedItems) } @@ -31,13 +33,24 @@ internal class GeneratedTechDebtParser { return allItems } + private fun shouldResolveSourceSet(sourceSet: String): Boolean { + if (sourceSet == SOURCE_SET_UNKNOWN || sourceSet == SOURCE_SET_MAIN) return true + return !sourceSet.contains("/") && !sourceSet.contains("\\") && !sourceSet.contains(":") + } + private fun resolveSourceSet(path: String): String { val parts = path.split("/") val kspIndex = parts.indexOf("ksp") - return if (kspIndex != -1 && kspIndex + 1 < parts.size) { - parts[kspIndex + 1] - } else { - "unknown" + if (kspIndex != -1 && kspIndex + 1 < parts.size) { + val sourceSetName = parts[kspIndex + 1] + return sourceSetName } + return SOURCE_SET_UNKNOWN + } + + private companion object { + + private const val SOURCE_SET_MAIN = "main" + private const val SOURCE_SET_UNKNOWN = "unknown" } } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt new file mode 100644 index 0000000..428ff2a --- /dev/null +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -0,0 +1,109 @@ +package com.escodro.techdebt.gradle.parser + +import com.escodro.techdebt.gradle.model.TechDebtItem +import java.io.File +import java.io.IOException +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import org.apache.log4j.Logger +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.blame.BlameResult +import org.eclipse.jgit.lib.Repository +import org.eclipse.jgit.storage.file.FileRepositoryBuilder + +/** + * Metadata processor responsible for enriching [TechDebtItem] with Git information, such as the + * last modified date. + * + * @param rootProjectDirectory the root directory of the project + */ +internal class GitParser(private val rootProjectDirectory: File) { + + private val logger = Logger.getLogger(GitParser::class.java) + + private val sourceFileResolver = SourceFileResolver(rootProjectDirectory) + + private val blameCache = mutableMapOf() + + /** + * Enriches the given [TechDebtItem]s with Git information. + * + * @param items the list of tech debt items to be enriched + * @return the list of enriched tech debt items + */ + fun parse(items: List): List { + val repository = findRepository(rootProjectDirectory) ?: return items + + return repository.use { repo -> + val git = Git(repo) + items.map { item -> + val gitInfo = getGitInfo(git, item) + item.copy(lastModified = gitInfo?.lastModified, author = gitInfo?.author) + } + } + } + + private fun getGitInfo(git: Git, item: TechDebtItem): GitInfo? { + val sourceFile = sourceFileResolver.resolve(item.sourceSet, item.moduleName) + if (sourceFile == null || !sourceFile.exists()) { + return null + } + + val relativePath = sourceFile.relativeTo(rootProjectDirectory).path + val lineNumber = getLineNumber(item.sourceSet) + + return try { + val blame = + blameCache.getOrPut(relativePath) { + git.blame().setFilePath(relativePath).setFollowFileRenames(true).call() + } + extractGitInfo(blame, lineNumber) + } catch (e: IOException) { + logger.error("Failed to get Git info for file: $relativePath at line: $lineNumber", e) + null + } + } + + private fun extractGitInfo(blame: BlameResult?, lineNumber: Int): GitInfo? { + val commit = blame?.getSourceCommit(lineNumber - 1) ?: return null + val authorIdent = commit.authorIdent + val date = authorIdent.whenAsInstant + return GitInfo( + lastModified = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) + .format(date), + author = authorIdent.name, + ) + } + + private fun findRepository(directory: File): Repository? = + try { + val gitDir = FileRepositoryBuilder().readEnvironment().findGitDir(directory).gitDir + if (gitDir == null) { + null + } else { + FileRepositoryBuilder().setGitDir(gitDir).build() + } + } catch (e: IOException) { + logger.error("Failed to find Git repository in directory: ${directory.absolutePath}", e) + null + } catch (e: IllegalArgumentException) { + logger.error("Invalid Git repository in directory: ${directory.absolutePath}", e) + null + } + + private fun getLineNumber(sourceSet: String): Int = + sourceSet.substringAfterLast(":").toIntOrNull() ?: 1 +} + +/** + * Data class representing Git metadata information. + * + * @param lastModified the last modified date of the file + * @param author the author of the last modification + */ +private data class GitInfo( + val lastModified: String?, + val author: String?, +) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt new file mode 100644 index 0000000..a58df66 --- /dev/null +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt @@ -0,0 +1,45 @@ +package com.escodro.techdebt.gradle.parser + +import java.io.File + +/** + * Resolver responsible for mapping a source set string (path:line) to a physical [File] on disk. + */ +internal class SourceFileResolver(private val rootProjectDirectory: File) { + + /** + * Resolves the source file for the given source set and module name. + * + * @param sourceSet the source set string (e.g., "src/main/kotlin/MyFile.kt:10" or "main") + * @param moduleName the name of the module (e.g., ":app") + * @return the resolved [File], or `null` if it couldn't be found + */ + fun resolve(sourceSet: String, moduleName: String): File? { + if (sourceSet == "unknown") return null + + val path = sourceSet.substringBeforeLast(":") + val file = File(path) + val resolvedFile = + when { + file.isAbsolute && file.exists() -> file + File(rootProjectDirectory, path).exists() -> File(rootProjectDirectory, path) + else -> resolveInModule(moduleName, path) ?: fallbackSearch(path) + } + return resolvedFile + } + + private fun resolveInModule(moduleName: String, path: String): File? { + val moduleRelativePath = moduleName.removePrefix(":").replace(":", "/") + val moduleDir = File(rootProjectDirectory, moduleRelativePath) + + return if (moduleDir.exists() && moduleDir.isDirectory) { + val fileInModule = File(moduleDir, path) + if (fileInModule.exists()) fileInModule else null + } else { + null + } + } + + private fun fallbackSearch(path: String): File? = + rootProjectDirectory.walkTopDown().firstOrNull { it.isFile && it.endsWith(path) } +} diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt index ab00b34..3731e5b 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt @@ -64,6 +64,12 @@ internal class CardGenerator { if (item.type == TechDebtItemType.SUPPRESS) { infoGroup("Symbol") { +item.name } } + if (item.lastModified != null) { + infoGroup("Last Modified") { +item.lastModified } + } + if (item.author != null) { + infoGroup("Author") { +item.author } + } } } } @@ -72,7 +78,17 @@ internal class CardGenerator { private fun FlowContent.infoGroup(label: String, block: FlowContent.() -> Unit) { div(classes = "info-group") { span(classes = "info-label") { +label } - span(classes = "info-value") { block() } + div(classes = "info-value") { + attributes["style"] = + """ + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; + """ + .trimIndent() + block() + } } } diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt index 5c8f851..17e911e 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt @@ -1,5 +1,6 @@ package com.escodro.techdebt.extension +import com.google.devtools.ksp.symbol.FileLocation import com.google.devtools.ksp.symbol.KSAnnotated import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSFile @@ -16,3 +17,21 @@ fun getSymbolName(symbol: KSAnnotated): String = is KSFile -> symbol.fileName else -> "unknown" } + +/** + * Returns the source location of the given symbol. + * + * @param symbol the symbol to get the source location + * @param sourceSet the source set name + * @return the source location + */ +fun getSourceLocation(symbol: KSAnnotated, sourceSet: String): String { + val location = symbol.location + val sourceLocation = + if (location is FileLocation) { + "${location.filePath}:${location.lineNumber}" + } else { + sourceSet + } + return sourceLocation +} diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt index ecd1f83..750bca2 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt @@ -1,5 +1,6 @@ package com.escodro.techdebt.processor +import com.escodro.techdebt.extension.getSourceLocation import com.escodro.techdebt.extension.getSymbolName import com.escodro.techdebt.report.TechDebtItem import com.escodro.techdebt.report.TechDebtItemType @@ -31,9 +32,6 @@ internal class SuppressSymbolProcessor { resolver.getSymbolsWithAnnotation(Suppress::class.qualifiedName!!).forEach { symbol -> if (!symbol.validate()) return@forEach - val ksFile = symbol as? KSFile ?: (symbol as? KSDeclaration)?.containingFile - ksFile?.let { allOriginatingFiles.add(it) } - val suppressAnnotations = symbol.annotations .filter { @@ -54,6 +52,9 @@ internal class SuppressSymbolProcessor { } val name = getSymbolName(symbol) + val sourceLocation = getSourceLocation(symbol = symbol, sourceSet = sourceSet) + val ksFile = symbol as? KSFile ?: (symbol as? KSDeclaration)?.containingFile + ksFile?.let { allOriginatingFiles.add(it) } ruleNames.forEach { rule -> allItems.add( @@ -63,7 +64,7 @@ internal class SuppressSymbolProcessor { description = rule, ticket = "", priority = "", - sourceSet = sourceSet, + sourceSet = sourceLocation, type = TechDebtItemType.SUPPRESS ) ) diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt index aca5ace..fe902ea 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt @@ -1,6 +1,7 @@ package com.escodro.techdebt.processor import com.escodro.techdebt.TechDebt +import com.escodro.techdebt.extension.getSourceLocation import com.escodro.techdebt.extension.getSymbolName import com.escodro.techdebt.report.TechDebtItem import com.google.devtools.ksp.processing.Resolver @@ -40,9 +41,6 @@ internal class TechDebtSymbolProcessor { return@forEach } - val ksFile = symbol as? KSFile ?: (symbol as? KSDeclaration)?.containingFile - ksFile?.let { allOriginatingFiles.add(it) } - val annotation = symbol.annotations.firstOrNull { it.annotationType.resolve().declaration.qualifiedName?.asString() == @@ -59,6 +57,9 @@ internal class TechDebtSymbolProcessor { } val name = getSymbolName(symbol) + val sourceLocation = getSourceLocation(symbol = symbol, sourceSet = sourceSet) + val ksFile = symbol as? KSFile ?: (symbol as? KSDeclaration)?.containingFile + ksFile?.let { allOriginatingFiles.add(it) } allItems.add( TechDebtItem( @@ -67,7 +68,7 @@ internal class TechDebtSymbolProcessor { description = args["description"]?.toString().orEmpty(), ticket = args["ticket"]?.toString().orEmpty(), priority = priority, - sourceSet = sourceSet + sourceSet = sourceLocation ) ) } diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt index 0b1dcf8..422fb39 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt @@ -21,7 +21,9 @@ data class TechDebtItem( val ticket: String, val priority: String, val sourceSet: String, - val type: TechDebtItemType = TechDebtItemType.TECH_DEBT + val type: TechDebtItemType = TechDebtItemType.TECH_DEBT, + val lastModified: String? = null, + val author: String? = null, ) /** Represents the type of technical debt item. */ From e798b267f45c2da8b24acd60d74406715500f5b8 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:07:47 -0500 Subject: [PATCH 03/18] =?UTF-8?q?=E2=9C=85=20Add=20unit=20tests=20for=20ne?= =?UTF-8?q?w=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added comprehensive unit tests for `SourceFileResolver` and `GitParser` to ensure file resolution and parsing behaviors work as expected. Refactored `CommentParserTest` to include setup logic for `CommentParser`. --- .../gradle/parser/CommentParserTest.kt | 8 +- .../techdebt/gradle/parser/GitParserTest.kt | 124 ++++++++++++++++++ .../gradle/parser/SourceFileResolverTest.kt | 85 ++++++++++++ 3 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt create mode 100644 techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolverTest.kt diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt index d6587c4..ccd4567 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt @@ -5,6 +5,7 @@ import java.io.File import org.gradle.testfixtures.ProjectBuilder import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir @@ -12,7 +13,12 @@ internal class CommentParserTest { @TempDir lateinit var tempDir: File - private val parser = CommentParser() + private lateinit var parser: CommentParser + + @BeforeEach + fun setup() { + parser = CommentParser() + } @Test fun `test parser collects TODOs from source files`() { diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt new file mode 100644 index 0000000..0b55fd9 --- /dev/null +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt @@ -0,0 +1,124 @@ +package com.escodro.techdebt.gradle.parser + +import com.escodro.techdebt.gradle.model.TechDebtItem +import java.io.File +import org.eclipse.jgit.api.Git +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +internal class GitParserTest { + + @TempDir lateinit var tempDir: File + + @Test + fun `test git parser extracts information correctly`() { + // Initialize a git repository in the temp directory + val git = Git.init().setDirectory(tempDir).call() + val file = File(tempDir, "TestFile.kt") + file.writeText("content") + git.add().addFilepattern("TestFile.kt").call() + val commit = + git.commit().setMessage("Initial commit").setAuthor("Junie", "junie@example.com").call() + + val parser = GitParser(tempDir) + val item = + TechDebtItem( + moduleName = ":app", + name = "Test", + description = "Test description", + ticket = "T-123", + priority = "HIGH", + sourceSet = "TestFile.kt:1" + ) + + val results = parser.parse(listOf(item)) + + assertEquals(1, results.size) + val result = results.first() + assertEquals("Junie", result.author) + assertNotNull(result.lastModified) + } + + @Test + fun `test git parser returns original items if no repository found`() { + val parser = GitParser(tempDir) + val item = + TechDebtItem( + moduleName = ":app", + name = "Test", + description = "Test description", + ticket = "T-123", + priority = "HIGH", + sourceSet = "TestFile.kt:1" + ) + + val results = parser.parse(listOf(item)) + + assertEquals(1, results.size) + assertNull(results.first().author) + assertNull(results.first().lastModified) + } + + @Test + fun `test git parser uses cache for multiple items in same file`() { + val git = Git.init().setDirectory(tempDir).call() + val file = File(tempDir, "TestFile.kt") + file.writeText("line 1\nline 2") + git.add().addFilepattern("TestFile.kt").call() + git.commit().setMessage("Initial commit").setAuthor("Junie", "junie@example.com").call() + + val parser = GitParser(tempDir) + val item1 = + TechDebtItem( + moduleName = ":app", + name = "Test 1", + description = "Desc 1", + ticket = "T-1", + priority = "HIGH", + sourceSet = "TestFile.kt:1" + ) + val item2 = + TechDebtItem( + moduleName = ":app", + name = "Test 2", + description = "Desc 2", + ticket = "T-2", + priority = "LOW", + sourceSet = "TestFile.kt:2" + ) + + val results = parser.parse(listOf(item1, item2)) + + assertEquals(2, results.size) + assertEquals("Junie", results[0].author) + assertEquals("Junie", results[1].author) + } + + @Test + fun `test git parser does not skip main source set`() { + val git = Git.init().setDirectory(tempDir).call() + val file = File(tempDir, "MainFile.kt") + file.writeText("content") + git.add().addFilepattern("MainFile.kt").call() + git.commit().setMessage("Initial commit").setAuthor("Junie", "junie@example.com").call() + + val parser = GitParser(tempDir) + val item = + TechDebtItem( + moduleName = ":app", + name = "Test", + description = "Test description", + ticket = "T-123", + priority = "HIGH", + sourceSet = "MainFile.kt" // Simulating when KSP returns just a filename + ) + + val results = parser.parse(listOf(item)) + + assertEquals(1, results.size) + assertEquals("Junie", results.first().author) + } +} diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolverTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolverTest.kt new file mode 100644 index 0000000..3b753f8 --- /dev/null +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolverTest.kt @@ -0,0 +1,85 @@ +package com.escodro.techdebt.gradle.parser + +import java.io.File +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir + +internal class SourceFileResolverTest { + + @TempDir lateinit var tempDir: File + + @Test + fun `test resolver finds file by absolute path`() { + val file = File(tempDir, "MyFile.kt").apply { writeText("content") } + val resolver = SourceFileResolver(tempDir) + + val resolved = resolver.resolve(file.absolutePath + ":10", ":app") + + assertNotNull(resolved) + assertEquals(file.absolutePath, resolved?.absolutePath) + } + + @Test + fun `test resolver finds file by relative path from root`() { + val subDir = File(tempDir, "src/main/kotlin").apply { mkdirs() } + val file = File(subDir, "MyFile.kt").apply { writeText("content") } + val resolver = SourceFileResolver(tempDir) + + val resolved = resolver.resolve("src/main/kotlin/MyFile.kt:10", ":app") + + assertNotNull(resolved) + assertEquals(file.absolutePath, resolved?.absolutePath) + } + + @Test + fun `test resolver finds file in module directory`() { + val moduleDir = File(tempDir, "app/src/main/kotlin").apply { mkdirs() } + val file = File(moduleDir, "MyFile.kt").apply { writeText("content") } + val resolver = SourceFileResolver(tempDir) + + // The path in sourceSet might be relative to the module + val resolved = resolver.resolve("src/main/kotlin/MyFile.kt:10", ":app") + + assertNotNull(resolved) + assertEquals(file.absolutePath, resolved?.absolutePath) + } + + @Test + fun `test resolver falls back to walkTopDown`() { + val deepDir = File(tempDir, "some/very/deep/path").apply { mkdirs() } + val file = File(deepDir, "DeepFile.kt").apply { writeText("content") } + val resolver = SourceFileResolver(tempDir) + + val resolved = resolver.resolve("DeepFile.kt:10", ":any") + + assertNotNull(resolved) + assertEquals(file.absolutePath, resolved?.absolutePath) + } + + @Test + fun `test resolver returns null for unknown sourceSet`() { + val resolver = SourceFileResolver(tempDir) + val resolved = resolver.resolve("unknown", ":app") + assertNull(resolved) + } + + @Test + fun `test resolver handles main sourceSet by falling back to search`() { + val subDir = File(tempDir, "src/main/kotlin").apply { mkdirs() } + val file = File(subDir, "MainFile.kt").apply { writeText("content") } + val resolver = SourceFileResolver(tempDir) + + // When KSP says "main", we hope to find the file by searching for the module name or + // something + // In this case, "main" as sourceSet won't match any file name unless we have a file named + // "main" + // But if we pass a real file name that KSP sometimes fails to give full path for: + val resolved = resolver.resolve("MainFile.kt", ":app") + + assertNotNull(resolved) + assertEquals(file.absolutePath, resolved?.absolutePath) + } +} From 94450dfeae57abb9d8ab3a6d7dab2cd03c80addf Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:08:27 -0500 Subject: [PATCH 04/18] =?UTF-8?q?=F0=9F=A5=9D=20Update=20HTML=20sample=20r?= =?UTF-8?q?eport?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sample report was updated after the new git metadata feature. --- samples/sample-jvm/assets/report.html | 253 ++++++++++++++++++++++++-- samples/sample-jvm/build.gradle.kts | 1 + 2 files changed, 235 insertions(+), 19 deletions(-) diff --git a/samples/sample-jvm/assets/report.html b/samples/sample-jvm/assets/report.html index 803c0c5..d43d979 100644 --- a/samples/sample-jvm/assets/report.html +++ b/samples/sample-jvm/assets/report.html @@ -239,8 +239,30 @@

Annotated Tech Debt

-
PriorityHIGH
-
Source Setmain
+
Priority +
HIGH
+
+
Source Set +
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:1
+
+
Last Modified +
2026-01-18 11:39:12
+
+
Author +
Igor Escodro
+
@@ -255,9 +277,36 @@

Annotated Tech Debt

-
Ticket26
-
PriorityHIGH
-
Source Setmain
+
Ticket + +
+
Priority +
HIGH
+
+
Source Set +
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:19
+
+
Last Modified +
2026-01-10 19:56:05
+
+
Author +
Igor Escodro
+
@@ -272,9 +321,36 @@

Annotated Tech Debt

-
Ticket23
-
PriorityMEDIUM
-
Source Setmain
+
Ticket + +
+
Priority +
MEDIUM
+
+
Source Set +
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:16
+
+
Last Modified +
2026-01-10 19:56:05
+
+
Author +
Igor Escodro
+
@@ -289,9 +365,36 @@

Annotated Tech Debt

-
Ticket20
-
PriorityLOW
-
Source Setmain
+
Ticket + +
+
Priority +
LOW
+
+
Source Set +
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:9
+
+
Last Modified +
2026-01-10 19:56:05
+
+
Author +
Igor Escodro
+
@@ -306,8 +409,30 @@

Annotated Tech Debt

-
PriorityNONE
-
Source Setmain
+
Priority +
NONE
+
+
Source Set +
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:25
+
+
Last Modified +
2026-01-10 19:56:05
+
+
Author +
Igor Escodro
+
@@ -322,7 +447,24 @@

Comments

-
Locationsrc/main/kotlin/com/escodro/sample/Sample.kt:20
+
Location +
src/main/kotlin/com/escodro/sample/Sample.kt:20
+
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -336,7 +478,24 @@

Comments

-
Locationsrc/main/kotlin/com/escodro/sample/Sample.kt:27
+
Location +
src/main/kotlin/com/escodro/sample/Sample.kt:27
+
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -350,7 +509,24 @@

Comments

-
Locationsrc/main/kotlin/com/escodro/sample/Sample.kt:35
+
Location +
src/main/kotlin/com/escodro/sample/Sample.kt:35
+
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -364,7 +540,24 @@

Comments

-
Locationsrc/main/kotlin/com/escodro/sample/Sample.kt:39
+
Location +
src/main/kotlin/com/escodro/sample/Sample.kt:39
+
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -380,8 +573,30 @@

Suppressed Rules

-
Source Setmain
-
Symbolcom.escodro.sample.Sample.suppressedFunction
+
Source Set +
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:31
+
+
Symbol +
com.escodro.sample.Sample.suppressedFunction
+
+
Last Modified +
2026-01-25 09:17:04
+
+
Author +
Igor Escodro
+
diff --git a/samples/sample-jvm/build.gradle.kts b/samples/sample-jvm/build.gradle.kts index 3cdbb5c..7ca82d2 100644 --- a/samples/sample-jvm/build.gradle.kts +++ b/samples/sample-jvm/build.gradle.kts @@ -16,5 +16,6 @@ techDebtReport { outputFile.set(layout.projectDirectory.file("assets/report.html")) collectSuppress.set(true) collectComments.set(true) + enableGitMetadata.set(true) baseTicketUrl.set("https://github.com/igorescodro/tech-debt/issues/") } From 0769f5305cf62e2513fe58d0b1c370789205fd1f Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:08:45 -0500 Subject: [PATCH 05/18] =?UTF-8?q?=F0=9F=AA=9C=20Add=20Git=20metadata=20sup?= =?UTF-8?q?port=20to=20README?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated the README to document the new `enableGitMetadata` option and the ability to collect and visualize Git information like author and last modified date. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index a642b66..63c3ead 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,9 @@ techDebtReport { // Set a base URL for tickets to automatically generate links (Optional) baseTicketUrl.set("https://jira.myproject.com/tickets/") + + // Enable Git metadata like last modified date and author (Optional, default is false) + enableGitMetadata.set(true) } ``` @@ -99,6 +102,7 @@ techDebtReport { - **Consolidated HTML Report**: A clean, easy-to-read summary of all technical debt from all modules in your project. - **Suppress Support**: Optionally collect and visualize suppressed rules (e.g., `@Suppress("MagicNumber")`) in the report. - **TODO/FIXME Comments Support**: Optionally collect and visualize `TODO` and `FIXME` comments from your source code. +- **Git Metadata Support**: Optionally collect and visualize Git information (Author and Last Modified date) for each tech debt item. - **Priority Levels**: Support for `LOW`, `MEDIUM`, and `HIGH` priority levels (and `NONE`). - **Ticket Linking**: Keep track of related tickets in your issue tracking system. If `baseTicketUrl` is configured, tickets will automatically become clickable links in the report. From 266a300ac9acf41e77341497433db601bcf94d01 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:22:34 -0500 Subject: [PATCH 06/18] =?UTF-8?q?=F0=9F=90=93=20Add=20root=20project=20dir?= =?UTF-8?q?ectory=20property=20to=20task?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced `rootProjectDirectory` as a new internal property in `GenerateTechDebtReportTask` to resolve Git metadata. Updated task instantiation logic in `TechDebtPlugin` to set this property. --- .../escodro/techdebt/gradle/GenerateTechDebtReportTask.kt | 7 ++++++- .../kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt index 660459b..72b2052 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/GenerateTechDebtReportTask.kt @@ -7,11 +7,13 @@ import com.escodro.techdebt.gradle.parser.GitParser import com.escodro.techdebt.gradle.report.HtmlReportGenerator import org.gradle.api.DefaultTask import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Optional import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction @@ -34,6 +36,9 @@ abstract class GenerateTechDebtReportTask : DefaultTask() { */ @get:Input abstract val projectPathByDirectory: MapProperty + /** The root directory of the project. Used to resolve Git metadata. */ + @get:Internal abstract val rootProjectDirectory: DirectoryProperty + /** The source files to scan for TODO comments. */ @get:InputFiles @get:Optional abstract val sourceFiles: ConfigurableFileCollection @@ -52,7 +57,7 @@ abstract class GenerateTechDebtReportTask : DefaultTask() { val allItems = mutableListOf() allItems += jsonParser.parse(jsonFiles) - val rootProjectDir = project.rootProject.projectDir + val rootProjectDir = rootProjectDirectory.get().asFile if (collectComments.get()) { allItems += CommentParser() diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt index e2fd8b7..fcf7ce1 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/TechDebtPlugin.kt @@ -29,6 +29,7 @@ class TechDebtPlugin : Plugin { task.projectPathByDirectory.set( project.allprojects.associate { it.projectDir.absolutePath to it.path } ) + task.rootProjectDirectory.set(project.rootProject.layout.projectDirectory) task.outputFile.set( extension.outputFile.convention( project.layout.buildDirectory.file( From 44d8a61e8bc90282b94ce1b760dd291543171d12 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:23:51 -0500 Subject: [PATCH 07/18] =?UTF-8?q?=F0=9F=A7=AA=20Add=20unit=20test=20for=20?= =?UTF-8?q?bare=20filename=20sourceSet=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a new test in `GeneratedTechDebtParserTest` to verify proper handling of bare filenames as source sets. Simplified source set resolution logic in `GeneratedTechDebtParser`. --- .../gradle/parser/GeneratedTechDebtParser.kt | 3 +- .../parser/GeneratedTechDebtParserTest.kt | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt index cddf07f..8c55970 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParser.kt @@ -34,8 +34,7 @@ internal class GeneratedTechDebtParser { } private fun shouldResolveSourceSet(sourceSet: String): Boolean { - if (sourceSet == SOURCE_SET_UNKNOWN || sourceSet == SOURCE_SET_MAIN) return true - return !sourceSet.contains("/") && !sourceSet.contains("\\") && !sourceSet.contains(":") + return sourceSet == SOURCE_SET_UNKNOWN || sourceSet == SOURCE_SET_MAIN } private fun resolveSourceSet(path: String): String { diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParserTest.kt index ecd95c3..41f6c29 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GeneratedTechDebtParserTest.kt @@ -79,4 +79,35 @@ internal class GeneratedTechDebtParserTest { assertEquals(1, items.size) assertEquals("customSourceSet", items.first().sourceSet) } + + @Test + fun `test parser does not resolve sourceSet when it is a bare filename`() { + val project = ProjectBuilder.builder().withProjectDir(tempDir).build() + val kspDir = File(tempDir, "build/generated/ksp/main/resources/techdebt") + kspDir.mkdirs() + val jsonFile = + File(kspDir, "report.json").apply { + writeText( + """ + [ + { + "moduleName": ":app", + "name": "com.example.MyClass", + "description": "Test debt", + "ticket": "JIRA-123", + "priority": "HIGH", + "sourceSet": "MyFile.kt" + } + ] + """ + .trimIndent() + ) + } + + val jsonFiles = project.files(jsonFile) + val items = parser.parse(jsonFiles) + + assertEquals(1, items.size) + assertEquals("MyFile.kt", items.first().sourceSet) + } } From 0716177a1e921177c1b446d4658af6ce71371d77 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:34:24 -0500 Subject: [PATCH 08/18] =?UTF-8?q?=F0=9F=A9=B9=20Handle=20`GitAPIException`?= =?UTF-8?q?=20in=20`GitParser`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added error handling for `GitAPIException` in the `GitParser` to gracefully handle scenarios where Git blame operations fail. --- .../kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt index 428ff2a..b52801d 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -7,6 +7,7 @@ import java.time.ZoneId import java.time.format.DateTimeFormatter import org.apache.log4j.Logger import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.errors.GitAPIException import org.eclipse.jgit.blame.BlameResult import org.eclipse.jgit.lib.Repository import org.eclipse.jgit.storage.file.FileRepositoryBuilder @@ -61,6 +62,9 @@ internal class GitParser(private val rootProjectDirectory: File) { } catch (e: IOException) { logger.error("Failed to get Git info for file: $relativePath at line: $lineNumber", e) null + }catch (e: GitAPIException) { + logger.error("Failed to get Git blame for file: $relativePath at line: $lineNumber", e) + null } } From d41be2c423b6e411bf5a4a3e0dd596d4744f79a5 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:36:51 -0500 Subject: [PATCH 09/18] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Remove=20styles=20fr?= =?UTF-8?q?om=20`.info-value`=20elements=20and=20move=20to=20stylesheet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidated duplicate inline styles for `.info-value` elements into the stylesheet for maintainability. --- .../com/escodro/techdebt/gradle/report/CardGenerator.kt | 8 -------- .../com/escodro/techdebt/gradle/report/ReportStyle.kt | 4 ++++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt index 3731e5b..926340a 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt @@ -79,14 +79,6 @@ internal class CardGenerator { div(classes = "info-group") { span(classes = "info-label") { +label } div(classes = "info-value") { - attributes["style"] = - """ - min-width: 0; - white-space: normal; - overflow-wrap: anywhere; - word-break: break-word; - """ - .trimIndent() block() } } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/ReportStyle.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/ReportStyle.kt index e17575b..00393fe 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/ReportStyle.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/ReportStyle.kt @@ -236,6 +236,10 @@ internal class ReportStyle { .info-value { font-size: 14px; color: #333; + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; } .ticket { From 24ac59371841fdce56de00d92beebcf101f6abdc Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:50:46 -0500 Subject: [PATCH 10/18] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20Add=20`location`?= =?UTF-8?q?=20field=20for=20enhanced=20source=20mapping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced a new `location` field in `TechDebtItem` to provide precise source mapping. Updated `GitParser`, `CommentParser`, and processors to leverage the new field for consistent handling. Removed redundant inline styles in sample HTML report for maintainability. --- samples/sample-jvm/assets/report.html | 199 ++++-------------- .../techdebt/gradle/model/TechDebtItem.kt | 1 + .../techdebt/gradle/parser/CommentParser.kt | 4 +- .../techdebt/gradle/parser/GitParser.kt | 2 +- .../gradle/parser/SourceFileResolver.kt | 7 +- .../processor/SuppressSymbolProcessor.kt | 3 +- .../processor/TechDebtSymbolProcessor.kt | 3 +- .../escodro/techdebt/report/TechDebtItem.kt | 1 + 8 files changed, 57 insertions(+), 163 deletions(-) diff --git a/samples/sample-jvm/assets/report.html b/samples/sample-jvm/assets/report.html index d43d979..82942a3 100644 --- a/samples/sample-jvm/assets/report.html +++ b/samples/sample-jvm/assets/report.html @@ -168,6 +168,10 @@ .info-value { font-size: 14px; color: #333; + min-width: 0; + white-space: normal; + overflow-wrap: anywhere; + word-break: break-word; } .ticket { @@ -240,28 +244,16 @@

Annotated Tech Debt

Priority -
HIGH
+
HIGH
Source Set -
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:1
+
main
Last Modified -
2026-01-18 11:39:12
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -278,34 +270,19 @@

Annotated Tech Debt

Ticket - +
Priority -
HIGH
+
HIGH
Source Set -
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:19
+
main
Last Modified -
2026-01-10 19:56:05
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -322,34 +299,19 @@

Annotated Tech Debt

Ticket - +
Priority -
MEDIUM
+
MEDIUM
Source Set -
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:16
+
main
Last Modified -
2026-01-10 19:56:05
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -366,34 +328,19 @@

Annotated Tech Debt

Ticket - +
Priority -
LOW
+
LOW
Source Set -
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:9
+
main
Last Modified -
2026-01-10 19:56:05
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -410,28 +357,16 @@

Annotated Tech Debt

Priority -
NONE
+
NONE
Source Set -
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:25
+
main
Last Modified -
2026-01-10 19:56:05
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -448,22 +383,13 @@

Comments

Location -
src/main/kotlin/com/escodro/sample/Sample.kt:20
+
src/main/kotlin/com/escodro/sample/Sample.kt
Last Modified -
2026-01-31 09:38:49
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -479,22 +405,13 @@

Comments

Location -
src/main/kotlin/com/escodro/sample/Sample.kt:27
+
src/main/kotlin/com/escodro/sample/Sample.kt
Last Modified -
2026-01-31 09:38:49
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -510,22 +427,13 @@

Comments

Location -
src/main/kotlin/com/escodro/sample/Sample.kt:35
+
src/main/kotlin/com/escodro/sample/Sample.kt
Last Modified -
2026-01-31 09:38:49
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -541,22 +449,13 @@

Comments

Location -
src/main/kotlin/com/escodro/sample/Sample.kt:39
+
src/main/kotlin/com/escodro/sample/Sample.kt
Last Modified -
2026-01-31 09:38:49
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
@@ -574,28 +473,16 @@

Suppressed Rules

Source Set -
/Users/igorescodro/StudioProjects/TechDebt/samples/sample-jvm/src/main/kotlin/com/escodro/sample/Sample.kt:31
+
main
Symbol -
com.escodro.sample.Sample.suppressedFunction
+
com.escodro.sample.Sample.suppressedFunction
Last Modified -
2026-01-25 09:17:04
+
2026-01-18 11:39:12
Author -
Igor Escodro
+
Igor Escodro
diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt index 08b500e..8a947ab 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt @@ -23,6 +23,7 @@ data class TechDebtItem( val sourceSet: String, val type: TechDebtItemType = TechDebtItemType.TECH_DEBT, val lastModified: String? = null, + val location: String? = null, val author: String? = null, ) { /** diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/CommentParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/CommentParser.kt index 8e25170..a8b0ffb 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/CommentParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/CommentParser.kt @@ -38,14 +38,16 @@ internal class CommentParser { val description = if (content.isEmpty()) type else "$type: $content" val relativePath = file.relativeTo(File(projectDir)).invariantSeparatorsPath + val location = "$relativePath:${index + 1}" items += TechDebtItem( moduleName = projectPath, - sourceSet = "$relativePath:${index + 1}", + sourceSet = relativePath, name = "", description = description, ticket = "", priority = "", + location = location, type = TechDebtItemType.COMMENT ) } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt index b52801d..d82d795 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -45,7 +45,7 @@ internal class GitParser(private val rootProjectDirectory: File) { } private fun getGitInfo(git: Git, item: TechDebtItem): GitInfo? { - val sourceFile = sourceFileResolver.resolve(item.sourceSet, item.moduleName) + val sourceFile = sourceFileResolver.resolve(item.location, item.moduleName) if (sourceFile == null || !sourceFile.exists()) { return null } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt index a58df66..d4ae32d 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt @@ -14,10 +14,11 @@ internal class SourceFileResolver(private val rootProjectDirectory: File) { * @param moduleName the name of the module (e.g., ":app") * @return the resolved [File], or `null` if it couldn't be found */ - fun resolve(sourceSet: String, moduleName: String): File? { - if (sourceSet == "unknown") return null + fun resolve(sourceSet: String?, moduleName: String): File? { + val path = sourceSet?.substringBeforeLast(":") + + if (sourceSet == "unknown" || path == null) return null - val path = sourceSet.substringBeforeLast(":") val file = File(path) val resolvedFile = when { diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt index 750bca2..da284e3 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt @@ -64,7 +64,8 @@ internal class SuppressSymbolProcessor { description = rule, ticket = "", priority = "", - sourceSet = sourceLocation, + sourceSet = sourceSet, + location = sourceLocation, type = TechDebtItemType.SUPPRESS ) ) diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt index fe902ea..ad75be6 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt @@ -68,7 +68,8 @@ internal class TechDebtSymbolProcessor { description = args["description"]?.toString().orEmpty(), ticket = args["ticket"]?.toString().orEmpty(), priority = priority, - sourceSet = sourceLocation + sourceSet = sourceSet, + location = sourceLocation, ) ) } diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt index 422fb39..0c8d31d 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt @@ -23,6 +23,7 @@ data class TechDebtItem( val sourceSet: String, val type: TechDebtItemType = TechDebtItemType.TECH_DEBT, val lastModified: String? = null, + val location: String? = null, val author: String? = null, ) From befda44d3aa6447b20c9fd7f73543aac9bb804de Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:52:11 -0500 Subject: [PATCH 11/18] =?UTF-8?q?=F0=9F=90=90=20Update=20TechItem=20model?= =?UTF-8?q?=20KDoc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt | 3 +++ .../main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt index 8a947ab..ade3f8b 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/model/TechDebtItem.kt @@ -12,6 +12,9 @@ import kotlinx.serialization.Serializable * @property priority the priority of the tech debt * @property sourceSet the source set where the tech debt is located * @property type the type of the tech debt item + * @property lastModified the last time the tech debt was modified + * @property location the location of the tech debt in the source code + * @property author the author of the tech debt */ @Serializable data class TechDebtItem( diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt index 0c8d31d..bdae6cb 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/report/TechDebtItem.kt @@ -12,6 +12,9 @@ import kotlinx.serialization.Serializable * @property priority the priority of the tech debt * @property sourceSet the source set where the tech debt is located * @property type the type of the tech debt item + * @property lastModified the last time the tech debt was modified + * @property location the location of the tech debt in the source code + * @property author the author of the tech debt */ @Serializable data class TechDebtItem( From 86a7366946bfec8ae4209c4e4271e39855c974e4 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:52:42 -0500 Subject: [PATCH 12/18] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20code=20style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrected spacing for exception handling in `GitParser` and simplified lambda usage in `CardGenerator` for better readability and maintainability. --- .../kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt | 2 +- .../com/escodro/techdebt/gradle/report/CardGenerator.kt | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt index d82d795..2405130 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -62,7 +62,7 @@ internal class GitParser(private val rootProjectDirectory: File) { } catch (e: IOException) { logger.error("Failed to get Git info for file: $relativePath at line: $lineNumber", e) null - }catch (e: GitAPIException) { + } catch (e: GitAPIException) { logger.error("Failed to get Git blame for file: $relativePath at line: $lineNumber", e) null } diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt index 926340a..6c12b30 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt @@ -78,9 +78,7 @@ internal class CardGenerator { private fun FlowContent.infoGroup(label: String, block: FlowContent.() -> Unit) { div(classes = "info-group") { span(classes = "info-label") { +label } - div(classes = "info-value") { - block() - } + div(classes = "info-value") { block() } } } From 500542d01969826f93a14bff5a6f84fea382ceca Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:57:32 -0500 Subject: [PATCH 13/18] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20Remove=20suppress?= =?UTF-8?q?ed=20symbol=20display=20from=20report?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the "Symbol" section for suppressed items in `CardGenerator` and updated the sample HTML report to reflect the change, simplifying the output. --- samples/sample-jvm/assets/report.html | 3 --- .../kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt | 3 --- 2 files changed, 6 deletions(-) diff --git a/samples/sample-jvm/assets/report.html b/samples/sample-jvm/assets/report.html index 82942a3..3903d09 100644 --- a/samples/sample-jvm/assets/report.html +++ b/samples/sample-jvm/assets/report.html @@ -475,9 +475,6 @@

Suppressed Rules

Source Set
main
-
Symbol -
com.escodro.sample.Sample.suppressedFunction
-
Last Modified
2026-01-18 11:39:12
diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt index 6c12b30..7d8720c 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/report/CardGenerator.kt @@ -61,9 +61,6 @@ internal class CardGenerator { ) { +item.sourceSet } - if (item.type == TechDebtItemType.SUPPRESS) { - infoGroup("Symbol") { +item.name } - } if (item.lastModified != null) { infoGroup("Last Modified") { +item.lastModified } } From e8e53f33fec35b6e82a4c244caf15254793c8a74 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 10:59:18 -0500 Subject: [PATCH 14/18] =?UTF-8?q?=F0=9F=90=9E=20Fix=20fallbackSearch=20pat?= =?UTF-8?q?h=20matching=20in=20SourceFileResolver?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated `fallbackSearch` to use `it.path.endsWith(path)` for accurate path matching. --- .../com/escodro/techdebt/gradle/parser/SourceFileResolver.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt index d4ae32d..5281f4b 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/SourceFileResolver.kt @@ -42,5 +42,5 @@ internal class SourceFileResolver(private val rootProjectDirectory: File) { } private fun fallbackSearch(path: String): File? = - rootProjectDirectory.walkTopDown().firstOrNull { it.isFile && it.endsWith(path) } + rootProjectDirectory.walkTopDown().firstOrNull { it.isFile && it.path.endsWith(path) } } From 11bb02fd77ba78aaf3382fac2c4b82c6f1cc0d00 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 11:06:26 -0500 Subject: [PATCH 15/18] =?UTF-8?q?=F0=9F=A7=AA=20Update=20tests=20to=20incl?= =?UTF-8?q?ude=20`location`=20field=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhanced `GitParserTest` and `CommentParserTest` to validate the `location` field, ensuring accurate source mapping is tested consistently. --- .../techdebt/gradle/parser/CommentParserTest.kt | 3 ++- .../techdebt/gradle/parser/GitParserTest.kt | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt index ccd4567..f77a8a0 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/CommentParserTest.kt @@ -49,7 +49,8 @@ internal class CommentParserTest { val item = items.first() assertEquals(":project", item.moduleName) assertEquals("TODO: My task", item.description) - assertEquals("src/main/kotlin/com/example/MyClass.kt:3", item.sourceSet) + assertEquals("src/main/kotlin/com/example/MyClass.kt", item.sourceSet) + assertEquals("src/main/kotlin/com/example/MyClass.kt:3", item.location) assertEquals(TechDebtItemType.COMMENT, item.type) } diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt index 0b55fd9..cde94d5 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt @@ -31,7 +31,8 @@ internal class GitParserTest { description = "Test description", ticket = "T-123", priority = "HIGH", - sourceSet = "TestFile.kt:1" + sourceSet = "TestFile.kt:1", + location = file.absolutePath + ":1" ) val results = parser.parse(listOf(item)) @@ -45,6 +46,8 @@ internal class GitParserTest { @Test fun `test git parser returns original items if no repository found`() { val parser = GitParser(tempDir) + val file = File(tempDir, "TestFile.kt") + file.writeText("content") val item = TechDebtItem( moduleName = ":app", @@ -52,7 +55,8 @@ internal class GitParserTest { description = "Test description", ticket = "T-123", priority = "HIGH", - sourceSet = "TestFile.kt:1" + sourceSet = "TestFile.kt:1", + location = file.absolutePath + ":1" ) val results = parser.parse(listOf(item)) @@ -78,7 +82,8 @@ internal class GitParserTest { description = "Desc 1", ticket = "T-1", priority = "HIGH", - sourceSet = "TestFile.kt:1" + sourceSet = "TestFile.kt:1", + location = file.absolutePath + ":1" ) val item2 = TechDebtItem( @@ -87,7 +92,8 @@ internal class GitParserTest { description = "Desc 2", ticket = "T-2", priority = "LOW", - sourceSet = "TestFile.kt:2" + sourceSet = "TestFile.kt:2", + location = file.absolutePath + ":2" ) val results = parser.parse(listOf(item1, item2)) @@ -113,7 +119,8 @@ internal class GitParserTest { description = "Test description", ticket = "T-123", priority = "HIGH", - sourceSet = "MainFile.kt" // Simulating when KSP returns just a filename + sourceSet = "MainFile.kt", // Simulating when KSP returns just a filename + location = file.absolutePath + ":1" ) val results = parser.parse(listOf(item)) From b481fe0c6bcb0652dca72a06c217d7dd814d3a54 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 11:07:42 -0500 Subject: [PATCH 16/18] =?UTF-8?q?=F0=9F=90=9E=20Normalize=20file=20paths?= =?UTF-8?q?=20in=20`GitParser`=20to=20handle=20OS-specific=20separators?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced path separators with forward slashes in `GitParser` to ensure consistent path handling. Added unit test to validate this behavior across environments. --- .../techdebt/gradle/parser/GitParser.kt | 2 +- .../techdebt/gradle/parser/GitParserTest.kt | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt index 2405130..a6d4330 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -50,7 +50,7 @@ internal class GitParser(private val rootProjectDirectory: File) { return null } - val relativePath = sourceFile.relativeTo(rootProjectDirectory).path + val relativePath = sourceFile.relativeTo(rootProjectDirectory).path.replace(File.separatorChar, '/') val lineNumber = getLineNumber(item.sourceSet) return try { diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt index cde94d5..84bfe2a 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt @@ -128,4 +128,33 @@ internal class GitParserTest { assertEquals(1, results.size) assertEquals("Junie", results.first().author) } + + @Test + fun `test git parser handles OS-specific paths`() { + // Initialize a git repository + val git = Git.init().setDirectory(tempDir).call() + + // Create a file in a subdirectory to have a relative path + val subDir = File(tempDir, "subdir").apply { mkdir() } + val file = File(subDir, "TestFile.kt") + file.writeText("content") + + // In Git, the path must be forward-slash separated + git.add().addFilepattern("subdir/TestFile.kt").call() + git.commit().setMessage("Initial commit").setAuthor("Junie", "junie@example.com").call() + + val parser = GitParser(tempDir) + val item = TechDebtItem( + moduleName = ":app", + name = "Test", + description = "Test description", + ticket = "T-123", + priority = "HIGH", + sourceSet = "TestFile.kt:1", + location = file.absolutePath + ":1" + ) + + val results = parser.parse(listOf(item)) + assertEquals("Junie", results.first().author) + } } From 8bcda9d6642dc28a82b9f81334c7a3e99672e3cd Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 18:59:43 -0500 Subject: [PATCH 17/18] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20`GitParse?= =?UTF-8?q?r`=20to=20validate=20line=20numbers=20and=20update=20test=20cov?= =?UTF-8?q?erage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improved `GitParser` to ensure line numbers are validated before processing and adjusted affected test cases to handle scenarios where line numbers are missing. Simplified handling of `sourceSet` parsing. Removed unused sections from the sample HTML report for clarity. --- samples/sample-jvm/assets/report.html | 60 ------------------- .../techdebt/gradle/parser/GitParser.kt | 11 ++-- .../techdebt/gradle/parser/GitParserTest.kt | 23 +++---- 3 files changed, 18 insertions(+), 76 deletions(-) diff --git a/samples/sample-jvm/assets/report.html b/samples/sample-jvm/assets/report.html index 3903d09..4abfca2 100644 --- a/samples/sample-jvm/assets/report.html +++ b/samples/sample-jvm/assets/report.html @@ -249,12 +249,6 @@

Annotated Tech Debt

Source Set
main
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -278,12 +272,6 @@

Annotated Tech Debt

Source Set
main
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -307,12 +295,6 @@

Annotated Tech Debt

Source Set
main
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -336,12 +318,6 @@

Annotated Tech Debt

Source Set
main
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -362,12 +338,6 @@

Annotated Tech Debt

Source Set
main
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -385,12 +355,6 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -407,12 +371,6 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -429,12 +387,6 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -451,12 +403,6 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
@@ -475,12 +421,6 @@

Suppressed Rules

Source Set
main
-
Last Modified -
2026-01-18 11:39:12
-
-
Author -
Igor Escodro
-
diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt index a6d4330..fc615c9 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -46,12 +46,13 @@ internal class GitParser(private val rootProjectDirectory: File) { private fun getGitInfo(git: Git, item: TechDebtItem): GitInfo? { val sourceFile = sourceFileResolver.resolve(item.location, item.moduleName) - if (sourceFile == null || !sourceFile.exists()) { + val lineNumber = getLineNumber(item.sourceSet) + if (sourceFile == null || !sourceFile.exists() || lineNumber == null) { return null } - val relativePath = sourceFile.relativeTo(rootProjectDirectory).path.replace(File.separatorChar, '/') - val lineNumber = getLineNumber(item.sourceSet) + val relativePath = + sourceFile.relativeTo(rootProjectDirectory).path.replace(File.separatorChar, '/') return try { val blame = @@ -97,8 +98,8 @@ internal class GitParser(private val rootProjectDirectory: File) { null } - private fun getLineNumber(sourceSet: String): Int = - sourceSet.substringAfterLast(":").toIntOrNull() ?: 1 + private fun getLineNumber(sourceSet: String): Int? = + sourceSet.substringAfterLast(":").toIntOrNull() } /** diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt index 84bfe2a..cc028a1 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt @@ -104,7 +104,7 @@ internal class GitParserTest { } @Test - fun `test git parser does not skip main source set`() { + fun `test git parser returns null if line number is missing`() { val git = Git.init().setDirectory(tempDir).call() val file = File(tempDir, "MainFile.kt") file.writeText("content") @@ -126,7 +126,7 @@ internal class GitParserTest { val results = parser.parse(listOf(item)) assertEquals(1, results.size) - assertEquals("Junie", results.first().author) + assertNull(results.first().author) } @Test @@ -144,15 +144,16 @@ internal class GitParserTest { git.commit().setMessage("Initial commit").setAuthor("Junie", "junie@example.com").call() val parser = GitParser(tempDir) - val item = TechDebtItem( - moduleName = ":app", - name = "Test", - description = "Test description", - ticket = "T-123", - priority = "HIGH", - sourceSet = "TestFile.kt:1", - location = file.absolutePath + ":1" - ) + val item = + TechDebtItem( + moduleName = ":app", + name = "Test", + description = "Test description", + ticket = "T-123", + priority = "HIGH", + sourceSet = "TestFile.kt:1", + location = file.absolutePath + ":1" + ) val results = parser.parse(listOf(item)) assertEquals("Junie", results.first().author) From 66436c9161b8cd8d46388ea7960cc6fd774b17f7 Mon Sep 17 00:00:00 2001 From: Igor Escodro Date: Sat, 7 Feb 2026 19:18:16 -0500 Subject: [PATCH 18/18] =?UTF-8?q?=F0=9F=A7=83=EF=B8=8F=20Refactor=20`GitPa?= =?UTF-8?q?rser`=20and=20processors=20for=20improved=20location=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated `GitParser` to validate `location` instead of `sourceSet` for line number parsing, adjusted test cases to reflect changes, and enhanced processors to use `getAnnotationLocation`. --- samples/sample-jvm/assets/report.html | 54 +++++++++++++++++++ .../techdebt/gradle/parser/GitParser.kt | 8 +-- .../techdebt/gradle/parser/GitParserTest.kt | 36 +++++++++++-- .../extension/KSAnnotationExtensions.kt | 12 +++-- .../processor/SuppressSymbolProcessor.kt | 8 ++- .../processor/TechDebtSymbolProcessor.kt | 5 +- 6 files changed, 109 insertions(+), 14 deletions(-) diff --git a/samples/sample-jvm/assets/report.html b/samples/sample-jvm/assets/report.html index 4abfca2..8affdf1 100644 --- a/samples/sample-jvm/assets/report.html +++ b/samples/sample-jvm/assets/report.html @@ -249,6 +249,12 @@

Annotated Tech Debt

Source Set
main
+
Last Modified +
2026-01-18 11:39:12
+
+
Author +
Igor Escodro
+
@@ -272,6 +278,12 @@

Annotated Tech Debt

Source Set
main
+
Last Modified +
2026-01-31 17:34:25
+
+
Author +
Igor Escodro
+
@@ -318,6 +330,12 @@

Annotated Tech Debt

Source Set
main
+
Last Modified +
2026-01-31 17:34:25
+
+
Author +
Igor Escodro
+
@@ -338,6 +356,12 @@

Annotated Tech Debt

Source Set
main
+
Last Modified +
2026-01-10 19:56:05
+
+
Author +
Igor Escodro
+
@@ -355,6 +379,12 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -371,6 +401,12 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -387,6 +423,12 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -403,6 +445,12 @@

Comments

Location
src/main/kotlin/com/escodro/sample/Sample.kt
+
Last Modified +
2026-01-31 09:38:49
+
+
Author +
Igor Escodro
+
@@ -421,6 +469,12 @@

Suppressed Rules

Source Set
main
+
Last Modified +
2026-01-25 09:17:04
+
+
Author +
Igor Escodro
+
diff --git a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt index fc615c9..552cb91 100644 --- a/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt +++ b/techdebt-gradle-plugin/src/main/kotlin/com/escodro/techdebt/gradle/parser/GitParser.kt @@ -46,7 +46,7 @@ internal class GitParser(private val rootProjectDirectory: File) { private fun getGitInfo(git: Git, item: TechDebtItem): GitInfo? { val sourceFile = sourceFileResolver.resolve(item.location, item.moduleName) - val lineNumber = getLineNumber(item.sourceSet) + val lineNumber = getLineNumber(item.location) if (sourceFile == null || !sourceFile.exists() || lineNumber == null) { return null } @@ -98,8 +98,10 @@ internal class GitParser(private val rootProjectDirectory: File) { null } - private fun getLineNumber(sourceSet: String): Int? = - sourceSet.substringAfterLast(":").toIntOrNull() + private fun getLineNumber(location: String?): Int? { + if (location == null || !location.contains(":")) return null + return location.substringAfterLast(":").toIntOrNull() + } } /** diff --git a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt index cc028a1..c380eff 100644 --- a/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt +++ b/techdebt-gradle-plugin/src/test/kotlin/com/escodro/techdebt/gradle/parser/GitParserTest.kt @@ -31,7 +31,7 @@ internal class GitParserTest { description = "Test description", ticket = "T-123", priority = "HIGH", - sourceSet = "TestFile.kt:1", + sourceSet = "main", // Realistic sourceSet name location = file.absolutePath + ":1" ) @@ -119,8 +119,8 @@ internal class GitParserTest { description = "Test description", ticket = "T-123", priority = "HIGH", - sourceSet = "MainFile.kt", // Simulating when KSP returns just a filename - location = file.absolutePath + ":1" + sourceSet = "main", + location = file.absolutePath // No line number here ) val results = parser.parse(listOf(item)) @@ -158,4 +158,34 @@ internal class GitParserTest { val results = parser.parse(listOf(item)) assertEquals("Junie", results.first().author) } + + @Test + fun `test git parser does not return info for uncommitted changes`() { + val git = Git.init().setDirectory(tempDir).call() + val file = File(tempDir, "TestFile.kt") + file.writeText("committed content\n") + git.add().addFilepattern("TestFile.kt").call() + git.commit().setMessage("Initial commit").setAuthor("Junie", "junie@example.com").call() + + // Add a new line that is NOT committed + file.appendText("uncommitted content") + + val parser = GitParser(tempDir) + val item = + TechDebtItem( + moduleName = ":app", + name = "Test", + description = "Test description", + ticket = "T-123", + priority = "HIGH", + sourceSet = "main", + location = file.absolutePath + ":2" + ) + + val results = parser.parse(listOf(item)) + + assertEquals(1, results.size) + assertNull(results.first().author) + assertNull(results.first().lastModified) + } } diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt index 17e911e..985c702 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/extension/KSAnnotationExtensions.kt @@ -2,8 +2,10 @@ package com.escodro.techdebt.extension import com.google.devtools.ksp.symbol.FileLocation import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSAnnotation import com.google.devtools.ksp.symbol.KSDeclaration import com.google.devtools.ksp.symbol.KSFile +import com.google.devtools.ksp.symbol.Location /** * Returns the name of the given symbol, which can be a declaration or a file. @@ -19,14 +21,16 @@ fun getSymbolName(symbol: KSAnnotated): String = } /** - * Returns the source location of the given symbol. + * Returns the source location of the given annotation. * - * @param symbol the symbol to get the source location + * @param annotation the annotation to get the source location * @param sourceSet the source set name * @return the source location */ -fun getSourceLocation(symbol: KSAnnotated, sourceSet: String): String { - val location = symbol.location +fun getAnnotationLocation(annotation: KSAnnotation, sourceSet: String): String = + getLocation(annotation.location, sourceSet) + +private fun getLocation(location: Location, sourceSet: String): String { val sourceLocation = if (location is FileLocation) { "${location.filePath}:${location.lineNumber}" diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt index da284e3..a2187ee 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/SuppressSymbolProcessor.kt @@ -1,6 +1,6 @@ package com.escodro.techdebt.processor -import com.escodro.techdebt.extension.getSourceLocation +import com.escodro.techdebt.extension.getAnnotationLocation import com.escodro.techdebt.extension.getSymbolName import com.escodro.techdebt.report.TechDebtItem import com.escodro.techdebt.report.TechDebtItemType @@ -52,7 +52,11 @@ internal class SuppressSymbolProcessor { } val name = getSymbolName(symbol) - val sourceLocation = getSourceLocation(symbol = symbol, sourceSet = sourceSet) + val sourceLocation = + getAnnotationLocation( + annotation = suppressAnnotations.first(), + sourceSet = sourceSet + ) val ksFile = symbol as? KSFile ?: (symbol as? KSDeclaration)?.containingFile ksFile?.let { allOriginatingFiles.add(it) } diff --git a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt index ad75be6..4b6474a 100644 --- a/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt +++ b/techdebt-processor/src/main/kotlin/com/escodro/techdebt/processor/TechDebtSymbolProcessor.kt @@ -1,7 +1,7 @@ package com.escodro.techdebt.processor import com.escodro.techdebt.TechDebt -import com.escodro.techdebt.extension.getSourceLocation +import com.escodro.techdebt.extension.getAnnotationLocation import com.escodro.techdebt.extension.getSymbolName import com.escodro.techdebt.report.TechDebtItem import com.google.devtools.ksp.processing.Resolver @@ -57,7 +57,8 @@ internal class TechDebtSymbolProcessor { } val name = getSymbolName(symbol) - val sourceLocation = getSourceLocation(symbol = symbol, sourceSet = sourceSet) + val sourceLocation = + getAnnotationLocation(annotation = annotation, sourceSet = sourceSet) val ksFile = symbol as? KSFile ?: (symbol as? KSDeclaration)?.containingFile ksFile?.let { allOriginatingFiles.add(it) }