Repository: analysis-dev/diktat (kotlin)

Issue:
Fix diktat-gradle-plugin behavior in multiproject builds
By default, diktat should use `src/**/*.kt` as inputs, but for multiproject builds there is no root `src` dir. Diktat should either register tasks for all subprojects too, or automatically traverse the whole file tree.

Pull request:
### What's done:
* Changed logic
* Added tests

This pull request closes #572

Patch:
diff --git a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt
index c3af548a2a..6ab0cb31f0 100644
--- a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt
+++ b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt
@@ -31,6 +31,9 @@ open class DiktatJavaExecTaskBase @Inject constructor(
     @get:Internal
     internal val ignoreFailuresProp: Property<Boolean> = project.objects.property(Boolean::class.javaObjectType)
 
+    @get:Internal
+    internal var shouldRun = true
+
     init {
         group = "verification"
         if (isMainClassPropertySupported(gradleVersionString)) {
@@ -48,18 +51,36 @@ open class DiktatJavaExecTaskBase @Inject constructor(
             if (diktatExtension.debug) {
                 add("--debug")
             }
-            diktatExtension.inputs.files.forEach {
-                val pattern = project.trimRootDir(it.path)
-                add("\"$pattern\"")
-            }
+            diktatExtension.inputs
+                .also {
+                    if (it.isEmpty) {
+                        /*
+                         If ktlint receives empty patterns, it implicitly uses &#42;&#42;/*.kt, **/*.kts instead.
+                         This can lead to diktat analyzing gradle buildscripts and so on. We want to prevent it.
+                        */
+                        logger.warn("Inputs for $name do not exist, will not run diktat")
+                        shouldRun = false
+                    }
+                }
+                .files
+                .forEach {
+                    add("\"${it.path}\"")
+                }
             diktatExtension.excludes?.files?.forEach {
-                val pattern = project.trimRootDir(it.path)
-                add("\"!$pattern\"")
+                add("\"!${it.path}\"")
             }
         }
         logger.debug("Setting JavaExec args to $args")
     }
 
+    override fun exec() {
+        if (shouldRun) {
+            super.exec()
+        } else {
+            logger.info("Skipping diktat execution")
+        }
+    }
+
     /**
      * @param ignoreFailures whether failure in this plugin should be ignored by a build
      */
@@ -99,10 +120,3 @@ fun Project.registerDiktatFixTask(diktatExtension: DiktatExtension, diktatConfig
             DIKTAT_FIX_TASK, DiktatJavaExecTaskBase::class.java, gradle.gradleVersion,
             diktatExtension, diktatConfiguration, listOf("-F ")
         )
-
-private fun Project.trimRootDir(path: String) = if (path.startsWith(rootDir.absolutePath)) {
-    path.drop(rootDir.absolutePath.length)
-} else {
-    path
-}
-    .trim(File.separatorChar)


Test patch:
diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt
index d489d99dec..7587186137 100644
--- a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt
+++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginTest.kt
@@ -13,6 +13,9 @@ class DiktatGradlePluginTest {
     @BeforeEach
     fun setUp() {
         project = projectBuilder.build()
+        // mock kotlin sources
+        project.mkdir("src/main/kotlin")
+        project.file("src/main/kotlin/Test.kt").createNewFile()
         project.pluginManager.apply(DiktatGradlePlugin::class.java)
     }
 
@@ -27,5 +30,6 @@ class DiktatGradlePluginTest {
         val diktatExtension = project.extensions.getByName("diktat") as DiktatExtension
         Assertions.assertFalse(diktatExtension.debug)
         Assertions.assertIterableEquals(project.fileTree("src").files, diktatExtension.inputs.files)
+        Assertions.assertTrue(diktatExtension.inputs.files.isNotEmpty())
     }
 }
diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
index 9f99c6b51d..6c976f80b2 100644
--- a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
+++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
@@ -19,7 +19,7 @@ class DiktatJavaExecTaskTest {
     @Test
     fun `check command line for various inputs`() {
         assertCommandLineEquals(
-            listOf(null, "\"${listOf("src", "**", "*.kt").joinToString(File.separator)}\""),
+            listOf(null, "\"${combinePathParts("src", "**", "*.kt")}\""),
             DiktatExtension().apply {
                 inputs = project.files("src/**/*.kt")
             }
@@ -29,7 +29,7 @@ class DiktatJavaExecTaskTest {
     @Test
     fun `check command line in debug mode`() {
         assertCommandLineEquals(
-            listOf(null, "--debug", "\"${listOf("src", "**", "*.kt").joinToString(File.separator)}\""),
+            listOf(null, "--debug", "\"${combinePathParts("src", "**", "*.kt")}\""),
             DiktatExtension().apply {
                 inputs = project.files("src/**/*.kt")
                 debug = true
@@ -40,8 +40,8 @@ class DiktatJavaExecTaskTest {
     @Test
     fun `check command line with excludes`() {
         assertCommandLineEquals(
-            listOf(null, "\"${listOf("src", "**", "*.kt").joinToString(File.separator)}\"",
-                "\"!${listOf("src", "main", "kotlin", "generated").joinToString(File.separator)}\""
+            listOf(null, "\"${combinePathParts("src", "**", "*.kt")}\"",
+                "\"!${combinePathParts("src", "main", "kotlin", "generated")}\""
             ),
             DiktatExtension().apply {
                 inputs = project.files("src/**/*.kt")
@@ -50,8 +50,18 @@ class DiktatJavaExecTaskTest {
         )
     }
 
+    @Test
+    fun `check command line with non-existent inputs`() {
+        val task = registerDiktatTask(
+            DiktatExtension().apply {
+                inputs = project.files()
+            }
+        ).get()
+        Assertions.assertFalse(task.shouldRun)
+    }
+
     private fun registerDiktatTask(extension: DiktatExtension) = project.tasks.register(
-        "test", DiktatJavaExecTaskBase::class.java,
+        "diktatTask4Test", DiktatJavaExecTaskBase::class.java,
         "6.7", extension, project.configurations.create("diktat")
     )
 
@@ -59,4 +69,7 @@ class DiktatJavaExecTaskTest {
         val task = registerDiktatTask(extension).get()
         Assertions.assertIterableEquals(expected, task.commandLine)
     }
+
+    private fun combinePathParts(vararg parts: String) = project.projectDir.absolutePath +
+            parts.joinToString(File.separator, prefix = File.separator)
 }