Repository: analysis-dev/diktat (kotlin)

Issue:
ISE: "No runnable rules found. Please ensure that at least one is enabled" when running smoke tests during the release procedure
Whenever `DiktatSaveSmokeTest` is [run during the release process](https://github.com/saveourtool/diktat/runs/7525484968?check_suite_focus=true#step:8:3933), the following command is executed during each test:

```bash
java -jar ktlint -R diktat.jar --disabled_rules=standard -F /tmp/FixPlugin--899173061/src/main/kotlin/DefaultPackageTest.kt
```

The command fails with

```stacktrace
java.util.concurrent.ExecutionException: java.lang.IllegalStateException: No runnable rules found. Please ensure that at least one is enabled.
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
	at com.pinterest.ktlint.internal.KtlintCommandLine.parallel(KtlintCommandLine.kt:578)
	at com.pinterest.ktlint.internal.KtlintCommandLine.parallel$default(KtlintCommandLine.kt:536)
	at com.pinterest.ktlint.internal.KtlintCommandLine.lintFiles(KtlintCommandLine.kt:283)
	at com.pinterest.ktlint.internal.KtlintCommandLine.run(KtlintCommandLine.kt:235)
	at com.pinterest.ktlint.Main.main(Main.kt:31)
Caused by: java.lang.IllegalStateException: No runnable rules found. Please ensure that at least one is enabled.
	at com.pinterest.ktlint.core.internal.RuleSorter.applyRunAfterRuleToRuleExecutionOrder(RuleSorter.kt:184)
	at com.pinterest.ktlint.core.internal.RuleSorter.getSortedRules(RuleSorter.kt:40)
	at com.pinterest.ktlint.core.internal.VisitorProvider.<init>(VisitorProvider.kt:35)
	at com.pinterest.ktlint.core.internal.VisitorProvider.<init>(VisitorProvider.kt:17)
	at com.pinterest.ktlint.core.KtLint.format(KtLint.kt:239)
	at com.pinterest.ktlint.internal.FileUtilsKt.formatFile(FileUtils.kt:202)
	at com.pinterest.ktlint.internal.KtlintCommandLine.process(KtlintCommandLine.kt:355)
	at com.pinterest.ktlint.internal.KtlintCommandLine.access$process(KtlintCommandLine.kt:48)
	at com.pinterest.ktlint.internal.KtlintCommandLine$lintFiles$3.invoke$lambda-1(KtlintCommandLine.kt:274)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
```

The output from the regular workflow:

```console
[INFO] Running org.cqfn.diktat.ruleset.smoke.DiktatSaveSmokeTest
[WARN ] 2022-07-26 17:05:29 Make sure JAVA_HOME (/opt/hostedtoolcache/Java_Zulu_jdk/11.0.16-8/x64) points to a Java 8 or Java 11 home. Java 17 is not yet supported.
[INFO ] 2022-07-26 17:05:29 The base directory for the smoke test is /home/runner/work/diktat/diktat/diktat-rules/src/test/resources/test/smoke.
[INFO ] 2022-07-26 17:05:29 Downloading https://github.com/saveourtool/save-cli/releases/download/v0.3.2/save-0.3.2-linuxX64.kexe to save-0.3.2-linuxX64.kexe...
[INFO ] 2022-07-26 17:05:30 6016712 byte(s) copied in 235.426 ms.
[INFO ] 2022-07-26 17:05:30 Downloading https://github.com/pinterest/ktlint/releases/download/0.46.1/ktlint to ktlint...
[INFO ] 2022-07-26 17:05:32 63363704 byte(s) copied in 732.33 ms.
[INFO] Tests run: 15, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 86.137 s - in org.cqfn.diktat.ruleset.smoke.DiktatSaveSmokeTest
```

The output from the release workflow:

```console
[INFO] Running org.cqfn.diktat.ruleset.smoke.DiktatSaveSmokeTest
[WARN ] 2022-07-26 17:17:36 Make sure JAVA_HOME (/opt/hostedtoolcache/Java_Zulu_jdk/11.0.16-8/x64) points to a Java 8 or Java 11 home. Java 17 is not yet supported.
[INFO ] 2022-07-26 17:17:36 The base directory for the smoke test is /home/runner/work/diktat/diktat/diktat-rules/src/test/resources/test/smoke.
[INFO ] 2022-07-26 17:17:36 Downloading https://github.com/saveourtool/save-cli/releases/download/v0.3.2/save-0.3.2-linuxX64.kexe to save-0.3.2-linuxX64.kexe...
[INFO ] 2022-07-26 17:17:37 6016712 byte(s) copied in 230.523 ms.
[INFO ] 2022-07-26 17:17:37 Downloading https://github.com/pinterest/ktlint/releases/download/0.46.1/ktlint to ktlint...
[INFO ] 2022-07-26 17:17:40 63363704 byte(s) copied in 2780.787 ms.
Error:  Tests run: 15, Failures: 15, Errors: 0, Skipped: 0, Time elapsed: 31.537 s <<< FAILURE! - in org.cqfn.diktat.ruleset.smoke.DiktatSaveSmokeTest
```

## Environment information
* diktat version: `1.2.2-SNAPSHOT` at 812406d8b4c7c506864d779d600e118b61f1b597

Pull request:
### What's done:

 * Now it's possible to run `mvn clean install` w/o skipping tests.
 * Reverted ad66a04da79f66db5c452197ece937f666ed14c9 (was useless in the 1st
   place).
 * Reverted a67811df0a6dcb27e047fdd35f09ae4478fc0a41 (no longer necessary).
 * Partially reverted 54c8ccefc3009b8dd2a493c30590168318765b89 (no longer
   necessary).
 * See #1478.

Patch:
diff --git a/.github/workflows/metrics_for_master.yml b/.github/workflows/metrics_for_master.yml
index 155cb76d7c..f31fbeacab 100644
--- a/.github/workflows/metrics_for_master.yml
+++ b/.github/workflows/metrics_for_master.yml
@@ -28,11 +28,9 @@ jobs:
           key: maven-build-${{ hashFiles('**/pom.xml') }}
           restore-keys: |
             maven-build-
-      - name: Maven Install
-        # we need to run `install` goal here so that gradle will be able to resolve dependencies and run tests on diktat-gradle-plugin
-        run: mvn -B install -DskipPluginMarker -DskipTests
       - name: Run tests
-        run: mvn verify
+        # we need to run `install` goal here so that gradle will be able to resolve dependencies and run tests on diktat-gradle-plugin
+        run: mvn -B install -DskipPluginMarker
       - name: Generate code coverage report
         uses: codecov/codecov-action@v3
         with:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ccd63496ea..d8cd6b3c5f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -49,16 +49,10 @@ jobs:
               { "id": "gpg.passphrase", "passphrase": "${{ secrets.DIKTAT_GPG_PASS }}" },
               { "id": "kotlin-maven-plugin-tools", "username": "${{github.actor}}", "password": "${{ secrets.GITHUB_TOKEN }}" }
             ]
-        # Runs tests, incl. smoke tests (using a fat JAR built from the
-        # "diktat-ruleset" module). The fat JAR is also used later during the
-        # "upload-release-asset" step (see below).
-      - name: Run tests
-        run: mvn -B clean install
-        # "diktat-ruleset" is a module that creates a fat JAR, which is,
-        # obviously, never released. Since we *do need* this fat JAR in order to
-        # run smoke tests, we *skip tests entirely* in this step.
-      - name: Deploy artifacts (skipping the clean, test, and verify phases)
-        run: mvn -B deploy -Prelease --projects "!diktat-ruleset" -DskipTests=true
+      - name: Deploy artifacts
+        run: mvn -B clean deploy -Prelease --projects '!diktat-ruleset'
+      - name: Build diktat.jar
+        run: mvn -B package --projects diktat-ruleset
       - name: Create Github Release
         id: create_release
         uses: actions/create-release@v1
diff --git a/.gitignore b/.gitignore
index 37ac6a8ad3..e653b9107b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,11 @@
-target
-.gradle
-build
+target/
+.gradle/
+build/
 !ktlint/src/main/resources/config/.idea
-/.idea
+/.idea/
 *.iml
-out
+out/
 .DS_Store
+
+# Vim swap files
+*.swp
diff --git a/diktat-rules/pom.xml b/diktat-rules/pom.xml
index 40d0bd03a5..cdde4b934e 100644
--- a/diktat-rules/pom.xml
+++ b/diktat-rules/pom.xml
@@ -161,6 +161,73 @@
                     </arguments>
                 </configuration>
             </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <executions>
+                    <!-- Don't produce the JAR during the `package` phase. -->
+                    <execution>
+                        <id>default-jar</id>
+                        <phase>none</phase>
+                    </execution>
+                    <!-- Instead, create it immediately before the `test` phase
+                         so that the shade plug-in may use it. -->
+                    <execution>
+                        <id>fat-jar-for-smoke-tests</id>
+                        <phase>process-test-classes</phase>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- Create a fat JAR to be used in smoke tests, removing the
+                 circular dependency between `diktat-rules` and `diktat-ruleset`. -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <version>3.3.0</version>
+                <configuration>
+                    <!-- Suppress the generation of `dependency-reduced-pom.xml`,
+                         because it will also get installed under `~/.m2`,
+                         resulting in the `diktat-maven-plugin` build failure
+                         (the plug-in depends on `diktat-rules`). -->
+                    <createDependencyReducedPom>false</createDependencyReducedPom>
+                    <!-- Should be `false`: otherwise, the generated JAR, even
+                         with a custom classifier, will still be installed/deployed. -->
+                    <shadedArtifactAttached>false</shadedArtifactAttached>
+                    <!-- Necessary: otherwise, the artifact produced by the JAR
+                         plug-in will be overwritten by the fat JAR. -->
+                    <finalName>${project.name}-${project.version}-fat-jar-for-smoke-tests</finalName>
+                    <artifactSet>
+                        <excludes>
+                            <exclude>com.squareup:kotlinpoet</exclude>
+                            <exclude>net.java.dev.jna:jna</exclude>
+                            <exclude>org.jetbrains.intellij.deps:trove4j</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-compiler-embeddable</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-daemon-embeddable</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-reflect</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-script-runtime</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-stdlib-common</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-stdlib-jdk7</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-stdlib-jdk8</exclude>
+                            <exclude>org.jetbrains.kotlin:kotlin-stdlib</exclude>
+                            <exclude>org.jetbrains:annotations</exclude>
+                        </excludes>
+                    </artifactSet>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>fat-jar-for-smoke-tests</id>
+                        <phase>process-test-classes</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 


Test patch:
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 939765f846..3455e26247 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -24,9 +24,7 @@ jobs:
           restore-keys: |
             maven-build-
       - name: Maven Install
-        run: mvn -B clean install -DskipTests
-      - name: Maven run test
-        run: mvn verify
+        run: mvn -B clean install
       - name: Code coverage report
         uses: codecov/codecov-action@v3
         with:
@@ -152,25 +150,13 @@ jobs:
       - name: Maven Install
         if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
         run: |
-          mvn -B -T1C clean install -DskipTests
-        shell: bash
-
-      - name: Maven run test
-        if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
-        run: |
-          mvn verify
+          mvn -B -T1C clean install
         shell: bash
 
       - name: Maven Install on windows
         if: runner.os == 'Windows'
         run: |
-          mvn -B -T1C clean install -DskipTests
-        shell: cmd
-
-      - name: Maven run test
-        if: runner.os == 'Windows'
-        run: |
-          mvn verify
+          mvn -B -T1C clean install
         shell: cmd
 
         # This step needs a Git repository, so it's impossible to extract it
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt
index bbc4e0153e..638d35ee91 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/ruleset/smoke/DiktatSaveSmokeTest.kt
@@ -8,6 +8,7 @@ import org.cqfn.diktat.util.prependPath
 import org.cqfn.diktat.util.retry
 
 import mu.KotlinLogging
+import org.assertj.core.api.Assertions.assertThat
 import org.assertj.core.api.Assertions.fail
 import org.assertj.core.api.SoftAssertions.assertSoftly
 import org.junit.jupiter.api.AfterAll
@@ -24,9 +25,7 @@ import kotlin.io.path.createDirectories
 import kotlin.io.path.div
 import kotlin.io.path.exists
 import kotlin.io.path.listDirectoryEntries
-import kotlin.io.path.name
 import kotlin.io.path.outputStream
-import kotlin.io.path.pathString
 import kotlin.io.path.readText
 import kotlin.io.path.relativeTo
 import kotlin.system.measureNanoTime
@@ -99,6 +98,8 @@ class DiktatSaveSmokeTest : DiktatSmokeTestBase() {
 
     @Suppress("WRONG_ORDER_IN_CLASS_LIKE_STRUCTURES")  // False positives
     companion object {
+        private const val BUILD_DIRECTORY = "target"
+        private const val FAT_JAR_GLOB = "diktat-rules-*-fat-jar-for-smoke-tests.jar"
         private const val KTLINT_VERSION = "0.46.1"
 
         @Suppress("EMPTY_BLOCK_STRUCTURE_ERROR")
@@ -164,14 +165,20 @@ class DiktatSaveSmokeTest : DiktatSmokeTestBase() {
                 "The base directory for the smoke test is $baseDirectory."
             }
 
-            val diktatDir: String =
-                Path("../diktat-ruleset/target")
-                    .takeIf { it.exists() }
-                    ?.listDirectoryEntries()
-                    ?.single { it.name.contains("diktat") }
-                    ?.pathString ?: ""
+            /*
+             * The fat JAR should reside in the same directory as `ktlint` and
+             * `save*` and be named `diktat.jar`
+             * (see `diktat-rules/src/test/resources/test/smoke/save.toml`).
+             */
+            val diktatFrom = Path(BUILD_DIRECTORY)
+                .takeIf(Path::exists)
+                ?.listDirectoryEntries(FAT_JAR_GLOB)
+                ?.singleOrNull()
+            assertThat(diktatFrom)
+                .describedAs(diktatFrom?.toString() ?: "$BUILD_DIRECTORY/$FAT_JAR_GLOB")
+                .isNotNull
+                .isRegularFile
 
-            val diktatFrom = Path(diktatDir)
             val diktat = baseDirectory / "diktat.jar"
             val save = baseDirectory / getSaveForCurrentOs()
             val ktlint = baseDirectory / "ktlint"
@@ -179,7 +186,7 @@ class DiktatSaveSmokeTest : DiktatSmokeTestBase() {
             downloadFile(URL("https://github.com/saveourtool/save-cli/releases/download/v$SAVE_VERSION/${getSaveForCurrentOs()}"), save)
             downloadFile(URL("https://github.com/pinterest/ktlint/releases/download/$KTLINT_VERSION/ktlint"), ktlint)
 
-            diktatFrom.copyTo(diktat)
+            diktatFrom?.copyTo(diktat)
         }
 
         @AfterAll
diff --git a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/FixTestBase.kt b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/FixTestBase.kt
index 59d1a4ce78..82a7234cde 100644
--- a/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/FixTestBase.kt
+++ b/diktat-rules/src/test/kotlin/org/cqfn/diktat/util/FixTestBase.kt
@@ -69,8 +69,8 @@ open class FixTestBase(
         val systemName = System.getProperty("os.name")
         val result = when {
             systemName.startsWith("Linux", ignoreCase = true) || systemName.startsWith("Mac", ignoreCase = true) ->
-                ProcessBuilder("sh", "-c", "chmod 777 $savePath ; ./$savePath src/test/resources/test/smoke/src/main/kotlin $testPath --log all")
-            else -> ProcessBuilder(savePath, "src/test/resources/test/smoke/src/main/kotlin", testPath)
+                ProcessBuilder("sh", "-c", "chmod 777 $savePath ; ./$savePath $filesDir/src/main/kotlin $testPath --log all")
+            else -> ProcessBuilder(savePath, "$filesDir/src/main/kotlin", testPath)
         }
         return result
     }