diff --git a/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt b/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt index efb1ea8..45e089a 100644 --- a/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt +++ b/gradle/plugins/src/main/java/static_analysis/linters/DetektLinter.kt @@ -2,15 +2,23 @@ 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()) @@ -50,11 +58,29 @@ class DetektLinter : Linter { } } - source = getSources(extension.excludes) + 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") diff --git a/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt index 7b7b4ee..d2e5cb9 100644 --- a/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt +++ b/gradle/plugins/src/main/java/static_analysis/plugins/StaticAnalysisAndroidPlugin.kt @@ -27,6 +27,16 @@ class StaticAnalysisAndroidPlugin : StaticAnalysisPlugin() { buildVariant = applicationVariants.first { it.name.contains("Debug") }.name ) } + + project.tasks.register("detektAnalysis") { + val detektLinter = linters.find { it is DetektLinter } + ?: throw IllegalStateException("DetektLinter not found") + + setupStaticAnalysisTask( + linters = listOf(detektLinter), + buildVariant = applicationVariants.first { it.name.contains("Debug") }.name + ) + } } } } diff --git a/gradle/plugins/src/main/java/static_analysis/utils/String.kt b/gradle/plugins/src/main/java/static_analysis/utils/String.kt new file mode 100644 index 0000000..a2077ba --- /dev/null +++ b/gradle/plugins/src/main/java/static_analysis/utils/String.kt @@ -0,0 +1,25 @@ +package static_analysis.utils + +import java.io.File +import java.io.IOException +import java.util.concurrent.TimeUnit + +fun String.runCommand( + directoryToExecute: File? = null, + timeoutSec: Long = 30, +): String? { + return try { + val parts = this.split("\\s".toRegex()) + val process = ProcessBuilder(*parts.toTypedArray()) + .directory(directoryToExecute) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + + process.waitFor(timeoutSec, TimeUnit.SECONDS) + process.inputStream.bufferedReader().readText() + } catch(e: IOException) { + e.printStackTrace() + null + } +}