From 0cd6d17b1d1af0a4b60d601dffee95b03cfbbb32 Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Thu, 7 Jul 2022 22:16:15 +0300 Subject: [PATCH 1/4] gradle-plugin: Set `user.home` property if SARIF reporter is active (#1426) ### What's done: * Updated logic * Improved logging * Added tests Closes #1269 --- .../plugin/gradle/DiktatJavaExecTaskBase.kt | 28 +++++++++++++------ .../plugin/gradle/DiktatJavaExecTaskTest.kt | 21 ++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) 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 95e7df7d2f..35b9cc5ca0 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 @@ -170,22 +170,32 @@ open class DiktatJavaExecTaskBase @Inject constructor( return flag.toString() } - @Suppress("SAY_NO_TO_VAR") private fun setReporter(diktatExtension: DiktatExtension, flag: java.lang.StringBuilder) { val name = diktatExtension.reporter.trim() val validReporters = listOf("sarif", "plain", "json", "html") - var reporterFlag = if (name.isEmpty() || !validReporters.contains(name)) { - project.logger.warn("Reporter name $name was not specified or is invalid. Falling to 'plain' reporter") - "--reporter=plain" - } else { - "--reporter=$name" + val reporterFlag = when { + diktatExtension.githubActions -> { + if (diktatExtension.reporter.isNotEmpty()) { + // githubActions should have higher priority than custom input + project.logger.warn("`diktat.githubActions` is set to true, so custom reporter [$name] will be ignored and SARIF reporter will be used") + } + "--reporter=sarif" + } + name.isEmpty() -> { + project.logger.info("Reporter name was not set. Using 'plain' reporter") + "--reporter=plain" + } + name !in validReporters -> { + project.logger.warn("Reporter name is invalid (provided value: [$name]). Falling back to 'plain' reporter") + "--reporter=plain" + } + else -> "--reporter=$name" } - // githubActions should have higher priority than a custom input - if (diktatExtension.githubActions) { + val isSarifReporterActive = reporterFlag.contains("sarif") + if (isSarifReporterActive) { // need to set user.home specially for ktlint, so it will be able to put a relative path URI in SARIF systemProperty("user.home", project.rootDir.toString()) - reporterFlag = "--reporter=sarif" } flag.append(reporterFlag) 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 f9b6ab1d00..07af3cd3b9 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 @@ -121,6 +121,11 @@ class DiktatJavaExecTaskTest { diktatConfigFile = project.file("../diktat-analysis.yml") githubActions = true } + val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatJavaExecTaskBase + Assertions.assertEquals( + project.rootDir.toString(), + task.systemProperties["user.home"] + ) } @Test @@ -137,6 +142,22 @@ class DiktatJavaExecTaskTest { } } + @Test + fun `should set system property with SARIF reporter`() { + assertCommandLineEquals( + listOf(null, "--reporter=sarif") + ) { + inputs { exclude("*") } + diktatConfigFile = project.file("../diktat-analysis.yml") + reporter = "sarif" + } + val task = project.tasks.getByName(DIKTAT_CHECK_TASK) as DiktatJavaExecTaskBase + Assertions.assertEquals( + project.rootDir.toString(), + task.systemProperties["user.home"] + ) + } + @Test fun `check system property with multiproject build with default config`() { setupMultiProject() From 739bd3a9e327fca02646e7cc92f51a5ddbd3d411 Mon Sep 17 00:00:00 2001 From: Peter Trifanov Date: Fri, 8 Jul 2022 11:14:01 +0300 Subject: [PATCH 2/4] gradle-plugin: fix docs and tests for Groovy DSL (#1428) ### What's done: * Update build.gradle in examples * Add functional test for Groovy DSL with explicit inputs * Fix docs for `diktatExtension.output`: reporter treats any non-empty string as a file name, there are no special values * Remove `dependsOn` relation between `test` and `functionalTest`, use `shouldRunAfter` instead This pull request closes #1422 --- diktat-gradle-plugin/build.gradle.kts | 9 +++---- .../DiktatGradlePluginGroovyFunctionalTest.kt | 24 ++++++++++++++----- .../org/cqfn/diktat/plugin/gradle/Utils.kt | 12 ++++++++++ .../diktat/plugin/gradle/DiktatExtension.kt | 3 +-- examples/gradle-groovy-dsl/build.gradle | 3 ++- 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/diktat-gradle-plugin/build.gradle.kts b/diktat-gradle-plugin/build.gradle.kts index 3a1b0f0423..95c506dbe5 100644 --- a/diktat-gradle-plugin/build.gradle.kts +++ b/diktat-gradle-plugin/build.gradle.kts @@ -27,8 +27,9 @@ repositories { } // default value is needed for correct gradle loading in IDEA; actual value from maven is used during build -val ktlintVersion = project.properties.getOrDefault("ktlintVersion", "0.43.0") as String -val diktatVersion = project.version.takeIf { it.toString() != Project.DEFAULT_VERSION } ?: "1.1.0" +// To debug gradle plugin, please set `diktatVersion` manually to the current maven project version. +val ktlintVersion = project.properties.getOrDefault("ktlintVersion", "0.46.1") as String +val diktatVersion = project.version.takeIf { it.toString() != Project.DEFAULT_VERSION } ?: "1.2.1" val junitVersion = project.properties.getOrDefault("junitVersion", "5.8.1") as String val jacocoVersion = project.properties.getOrDefault("jacocoVersion", "0.8.7") as String dependencies { @@ -107,7 +108,7 @@ val functionalTest = sourceSets.create("functionalTest") { runtimeClasspath += output + compileClasspath } tasks.getByName("functionalTest") { - dependsOn("test") + shouldRunAfter("test") testClassesDirs = functionalTest.output.classesDirs classpath = functionalTest.runtimeClasspath maxParallelForks = Runtime.getRuntime().availableProcessors() @@ -131,7 +132,7 @@ jacocoTestKit { applyTo("functionalTestRuntimeOnly", tasks.named("functionalTest")) } tasks.jacocoTestReport { - dependsOn(tasks.withType()) + shouldRunAfter(tasks.withType()) executionData( fileTree("$buildDir/jacoco").apply { include("*.exec") diff --git a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginGroovyFunctionalTest.kt b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginGroovyFunctionalTest.kt index 27200776e0..d883729d26 100644 --- a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginGroovyFunctionalTest.kt +++ b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginGroovyFunctionalTest.kt @@ -27,14 +27,26 @@ class DiktatGradlePluginGroovyFunctionalTest { } @Test - fun `should execute diktatCheck on default values`() { + fun `should execute diktatCheck with default values`() { val result = runDiktat(testProjectDir, shouldSucceed = false) - val diktatCheckBuildResult = result.task(":${DiktatGradlePlugin.DIKTAT_CHECK_TASK}") - requireNotNull(diktatCheckBuildResult) - Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome) - Assertions.assertTrue( - result.output.contains("[FILE_NAME_MATCH_CLASS]") + assertDiktatExecuted(result) + } + + @Test + fun `should execute diktatCheck with explicit configuration`() { + buildFile.appendText( + """${System.lineSeparator()} + diktat { + inputs { it.include("src/**/*.kt") } + reporter = "plain" + diktatConfigFile = file(rootDir.path + "/diktat-analysis.yml") + } + """.trimIndent() ) + + val result = runDiktat(testProjectDir, shouldSucceed = false) + + assertDiktatExecuted(result) } } diff --git a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/Utils.kt b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/Utils.kt index 246c54f705..4a0d552e28 100644 --- a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/Utils.kt +++ b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/Utils.kt @@ -2,7 +2,10 @@ package org.cqfn.diktat.plugin.gradle import org.gradle.buildinit.plugins.internal.modifiers.BuildInitDsl import org.gradle.internal.impldep.org.junit.rules.TemporaryFolder +import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.jupiter.api.Assertions import java.io.File import java.util.concurrent.atomic.AtomicInteger @@ -71,3 +74,12 @@ private fun GradleRunner.withJaCoCo(number: Int) = apply { } } } + +fun assertDiktatExecuted(result: BuildResult) { + val diktatCheckBuildResult = result.task(":${DiktatGradlePlugin.DIKTAT_CHECK_TASK}") + requireNotNull(diktatCheckBuildResult) + Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome) + Assertions.assertTrue( + result.output.contains("[FILE_NAME_MATCH_CLASS]") + ) +} diff --git a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt index 48595df852..f2d4c5e1c9 100644 --- a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt +++ b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatExtension.kt @@ -34,8 +34,7 @@ open class DiktatExtension( var reporter: String = "plain" /** - * Type of output - * Default: System.out + * Destination for reporter. If empty, will write to stdout. */ var output: String = "" diff --git a/examples/gradle-groovy-dsl/build.gradle b/examples/gradle-groovy-dsl/build.gradle index b471212824..034bb0c144 100644 --- a/examples/gradle-groovy-dsl/build.gradle +++ b/examples/gradle-groovy-dsl/build.gradle @@ -7,5 +7,6 @@ repositories { } diktat { - inputs { include ("src/**/*.kt") } + inputs { it.include ("src/**/*.kt") } + diktatConfigFile = file(rootDir.path + "/diktat-analysis.yml") } From 7edb63ff06d9e44c58e73cb3624ea19538c6be58 Mon Sep 17 00:00:00 2001 From: vtchem <74022270+vtchem@users.noreply.github.com> Date: Fri, 8 Jul 2022 11:40:09 +0300 Subject: [PATCH 3/4] Update guide-chapter-0.md (#1430) Co-authored-by: Andrey Shcheglov --- info/guide/guide-chapter-0.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/info/guide/guide-chapter-0.md b/info/guide/guide-chapter-0.md index 54774996a7..0e1c47f894 100644 --- a/info/guide/guide-chapter-0.md +++ b/info/guide/guide-chapter-0.md @@ -29,7 +29,7 @@ Like other modern programming languages, Kotlin is an advanced programming langu Also, we need to consider the following factors when programming on Kotlin: -1. Writing clean and simple Kotlin code +1. Writing a clean and simple Kotlin code Kotlin combines two of the main programming paradigms: functional and object-oriented. Both of these paradigms are trusted and well-known software engineering practices. @@ -43,7 +43,7 @@ Also, we need to consider the following factors when programming on Kotlin: 3. Using Kotlin efficiently - Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract. + Some Kotlin features can help you write high-performance code. Such features include: rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract. ### Terminology @@ -66,4 +66,4 @@ Unless otherwise stated, this specification applies to versions 1.3 and later of Even though exceptions may exist, it is essential to understand why rules and recommendations are needed. Depending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. When modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency. -Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style. \ No newline at end of file +The software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style. From eecab22ce2617d45314f431400a61364140ecdcb Mon Sep 17 00:00:00 2001 From: vtchem <74022270+vtchem@users.noreply.github.com> Date: Fri, 8 Jul 2022 13:04:52 +0300 Subject: [PATCH 4/4] Update guide-TOC.md (#1431) Co-authored-by: Andrey Shcheglov --- info/guide/guide-TOC.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/info/guide/guide-TOC.md b/info/guide/guide-TOC.md index 3926539583..d1ffb7914c 100644 --- a/info/guide/guide-TOC.md +++ b/info/guide/guide-TOC.md @@ -28,14 +28,14 @@ I [Preface](#c0) * [2.2 Adding comments on the file header](#c2.2) * [2.3 Comments on the function header](#c2.3) * [2.4 Code comments](#c2.4) - * [2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks](#r2.4.1) + * [2.4.1 Adding a blank line between the body of the comment and Kdoc tag-blocks](#r2.4.1) * [2.4.2 Do not comment on unused code blocks](#r2.4.2) - * [2.4.3 Code delivered to the client should not contain TODO/FIXME comments](#r2.4.3) + * [2.4.3 Code delivered to the client must not contain TODO/FIXME comments](#r2.4.3) [3. General formatting (typesetting)](#c3) * [3.1 File-related rules](#c3.1) * [3.1.1 Avoid files that are too long](#r3.1.1) - * [3.1.2 Code blocks in the source file should be separated by one blank line](#r3.1.2) + * [3.1.2 Code blocks in the source file must be separated by one blank line](#r3.1.2) * [3.1.3 Import statements order](#r3.1.3) * [3.1.4 Order of declaration parts of class-like code structures](#r3.1.4) * [3.1.5 Order of declaration of top-level code structures](#r3.1.5) @@ -50,7 +50,7 @@ I [Preface](#c0) * [3.6.2 Rules for line-breaking](#r3.6.2) * [3.7 Using blank lines](#c3.7) * [3.8 Horizontal space](#c3.8) - * [3.8.1 Usage of whitespace for code separation](#r3.8.1) + * [3.8.1 Using whitespace for code separation](#r3.8.1) * [3.8.2 No spaces for horizontal alignment](#r3.8.2) * [3.9 Enumerations](#c3.9) * [3.10 Variable declaration](#c3.10) @@ -61,7 +61,7 @@ I [Preface](#c0) * [3.13 Block comments](#c3.13) * [3.14 Modifiers and constant values](#c3.14) * [3.14.1 Declaration with multiple modifiers](#r3.14.1) - * [3.14.2 Separate long numerical values with an underscore](#r3.14.2) + * [3.14.2 Separating long numerical values with an underscore](#r3.14.2) * [3.15 Strings](#c3.15) * [3.15.1 Concatenation of Strings](#r3.15.1) * [3.15.2 String template format](#r3.15.2) @@ -73,10 +73,10 @@ I [Preface](#c0) * [4.1 Variables](#c4.1) * [4.1.1 Do not use Float and Double types when accurate calculations are needed](#r4.1.1) * [4.1.2 Comparing numeric float type values](#r4.1.2) - * [4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]](#r4.1.3) + * [4.1.3 Using 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]](#r4.1.3) * [4.2 Types](#c4.2) - * [4.2.1 Use Contracts and smart cast as much as possible](#r4.2.1) - * [4.2.2 Try to use type alias to represent types making code more readable](#r4.2.2) + * [4.2.1 Using Contracts and smart cast as much as possible](#r4.2.1) + * [4.2.2 Trying to use type alias to represent types making code more readable](#r4.2.2) * [4.3 Null safety and variable declarations](#c4.3) * [4.3.1 Avoid declaring variables with nullable types, especially from Kotlin stdlib](#r4.3.1) * [4.3.2 Variables of generic types should have an explicit type declaration](#r4.3.2) @@ -93,7 +93,7 @@ I [Preface](#c0) * [5.2.2 Number of function parameters should be limited to five](#r5.2.2) * [5.2.3 Use default values for function arguments instead of overloading them](#r5.2.3) * [5.2.4 Synchronizing code inside asynchronous code](#r5.2.4) - * [5.2.5 Long lambdas should have explicit parameters](#r5.2.5) + * [5.2.5 Long lambdas must have explicit parameters](#r5.2.5) * [5.2.6 Avoid using unnecessary, custom label](#r5.2.6) [6. Classes, interfaces, and extension functions](#c6) @@ -103,13 +103,13 @@ I [Preface](#c0) * [6.1.3 Do not use the primary constructor if it is empty or useless](#r6.1.3) * [6.1.4 Do not use redundant init blocks in your class](#r6.1.4) * [6.1.5 Explicit supertype qualification](#r6.1.5) - * [6.1.6 Abstract class should have at least one abstract method](#r6.1.6) + * [6.1.6 Abstract class must have at least one abstract method](#r6.1.6) * [6.1.7 When using the "implicit backing property" scheme, the name of real and back property should be the same](#r6.1.7) * [6.1.8 Avoid using custom getters and setters](#r6.1.8) * [6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)](#r6.1.9) * [6.1.10 No trivial getters and setters are allowed in the code](#r6.1.10) * [6.1.11 Use 'apply' for grouping object initialization](#r6.1.11) - * [6.1.12 Prefer Inline classes when a class has a single property](#r6.1.12) + * [6.1.12 Prefer Inline classes when the class has a single property](#r6.1.12) * [6.2 Extension functions](#c6.2) * [6.2.1 Use extension functions for making logic of classes less coupled](#r6.2.1) * [6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)](#r6.2.2) @@ -117,6 +117,6 @@ I [Preface](#c0) * [6.3 Interfaces](#c6.3) * [6.4 Objects](#c6.4) * [6.4.1 Instead of using utility classes/objects, use extensions](#r6.4.1) - * [6.4.2 Objects should be used for Stateless Interfaces](#r6.4.2) + * [6.4.2 Objects must be used for Stateless Interfaces](#r6.4.2) * [6.5 Kts Files](#c6.5) * [6.5.1 kts files should wrap logic into top-level scope](#r6.5.1)