package static_analysis.linters import io.gitlab.arturbosch.detekt.Detekt import org.gradle.api.Project import org.gradle.api.file.FileTree import static_analysis.errors.DetektError import static_analysis.errors.StaticAnalysisError import static_analysis.plugins.StaticAnalysisExtension import static_analysis.utils.getSources import static_analysis.utils.runCommand import static_analysis.utils.typedChildren import static_analysis.utils.xmlParser import java.io.File class DetektLinter : Linter { private companion object { const val ONLY_DIFFS_FLAG = "only-diffs" const val GET_GIT_DIFFS_COMMAND = "git diff --name-only --ignore-submodules" } override val name: String = "Detekt" override fun getErrors(project: Project): List = xmlParser(project.getDetektReportFile()) .typedChildren() .filter { fileNode -> fileNode.name() == "file" } .map { fileNode -> fileNode .typedChildren() .filter { it.name() == "error" } .map { errorNode -> DetektError( filePath = fileNode.attribute("name") as String, fileLine = errorNode.attribute("line") as String, errorId = errorNode.attribute("source") as String, description = errorNode.attribute("message") as String ) } } .flatten() override fun setupForProject(project: Project, extension: StaticAnalysisExtension) { project.afterEvaluate { tasks.withType(Detekt::class.java) { exclude("**/test/**") exclude("resources/") exclude("build/") exclude("tmp/") jvmTarget = "1.8" config.setFrom(files("${extension.buildScriptDir!!}/static_analysis_configs/detekt-config.yml")) reports { txt.enabled = false html.enabled = false xml { enabled = true destination = getDetektReportFile() } } val isOnlyDiffs = properties["args"] == ONLY_DIFFS_FLAG // example: ./gradlew detektAnalysis -Pargs="only-diffs" source = getSources(extension.excludes, isOnlyDiffs, project) } } } private fun getSources(excludes: String, isOnlyDiffs: Boolean, project: Project): FileTree = when { isOnlyDiffs -> getGitDiffFiles(excludes, project) else -> project.getSources(excludes) } private fun getGitDiffFiles(excludes: String, project: Project): FileTree { val gitDiffs = GET_GIT_DIFFS_COMMAND.runCommand() ?: return project.files().asFileTree val diffFiles = gitDiffs.lines() .map { File(it) } .filter { (it.extension == "kt" || it.extension == "java") && !excludes.contains(it.path) } .toList() return project.files(diffFiles).asFileTree } override fun getTaskNames(project: Project, buildType: String?): List = listOf(":detekt") private fun Project.getDetektReportFile() = file("${rootProject.buildDir}/reports/detekt.xml") }