Skip to content

Commit

Permalink
Merge branch 'master' into bugfix/configurable-dot-qualified
Browse files Browse the repository at this point in the history
  • Loading branch information
orchestr7 committed Jul 9, 2022
2 parents 70bd351 + eecab22 commit e39843c
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 70 deletions.
61 changes: 28 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@


DiKTat is a strict [coding standard ](info/guide/diktat-coding-convention.md) for Kotlin and a collection of [Kotlin](https://kotlinlang.org/) code style rules implemented
as AST visitors on the top of [KTlint](https://ktlint.github.io/). It can be used for detecting and autofixing code smells in CI/CD process.
as AST visitors on the top of [KTlint](https://ktlint.github.io/). It can be used for detecting and autofixing code smells in CI/CD process.
The full list of available supported rules and inspections can be found [here](info/available-rules.md).

Now diKTat was already added to the lists of [static analysis tools](https://github.com/analysis-tools-dev/static-analysis), to [kotlin-awesome](https://github.com/KotlinBy/awesome-kotlin) and to [kompar](https://catalog.kompar.tools/Analyzer/diKTat/1.2.1). Thanks to the community for this support!
Now diKTat was already added to the lists of [static analysis tools](https://github.com/analysis-tools-dev/static-analysis), to [kotlin-awesome](https://github.com/KotlinBy/awesome-kotlin) and to [kompar](https://catalog.kompar.tools/Analyzer/diKTat/1.2.1). Thanks to the community for this support!

## See first

| | | | | | |
| | | | | | |
| --- | --- | --- | --- | --- | --- |
|[Codestyle](info/guide/diktat-coding-convention.md)|[Inspections](info/available-rules.md) | [Examples](examples) | [Demo](https://ktlint-demo.herokuapp.com) | [White Paper](wp/wp.pdf) | [Groups of Inspections](info/rules-mapping.md) |

Expand All @@ -36,47 +36,42 @@ First of all - actually you can combine diktat with any other static analyzers.
Main features of diktat are the following:

1) **More inspections.** It has 100+ inspections that are tightly coupled with it's [Codestyle](info/guide/diktat-coding-convention.md).

2) **Unique [Inspections](info/available-rules.md)** that are missing in other linters.

3) **Highly configurable**. Each and every inspection can be [configured](#config) or [suppressed](#suppress).

4) **Strict detailed [Codestyle](info/guide/diktat-coding-convention.md)** that you can adopt and use in your project.

## Run as CLI-application
<details>
<summary>Download and install binaries:</summary>

### Download and install binaries

1. Install KTlint manually: [here](https://github.com/pinterest/ktlint/releases)

**OR** use curl:
```bash
# another option is "brew install ktlint"
**OR** use `curl`:
```shell
# another option is "brew install ktlint"

curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.43.2/ktlint && chmod a+x ktlint
```

2. Load diKTat manually: [here](https://github.com/saveourtool/diKTat/releases/download/v1.2.1/diktat-1.2.1.jar)
curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.46.1/ktlint && chmod a+x ktlint
```

**OR** use curl:
```bash
$ curl -sSLO https://github.com/saveourtool/diKTat/releases/download/v1.2.1/diktat-1.2.1.jar
```
</details>
1. Load diKTat manually: [here](https://github.com/saveourtool/diKTat/releases/download/v1.2.1/diktat-1.2.1.jar)

<details>

<summary>Run diktat:</summary>

3. Finally, run KTlint (with diKTat injected) to check your '*.kt' files in 'dir/your/dir':

```bash
**OR** use `curl`:
```console
$ curl -sSLO https://github.com/saveourtool/diKTat/releases/download/v1.2.1/diktat-1.2.1.jar
```

### Run diKTat

Finally, run KTlint (with diKTat injected) to check your '*.kt' files in 'dir/your/dir':

```console
$ ./ktlint -R diktat.jar --disabled_rules=standard "dir/your/dir/**/*.kt"
```

To **autofix** all code style violations use `-F` option.
</details>

To **autofix** all code style violations, use `-F` option.

## Run with Maven using diktat-maven-plugin
:heavy_exclamation_mark: If you are using **Java 16+**, you need to add `--add-opens java.base/java.util=ALL-UNNAMED` flag to the JVM. For more information, see: https://github.com/pinterest/ktlint/issues/1195
Expand All @@ -91,7 +86,7 @@ If you use it and encounter any problems, feel free to open issues on [github](h
<details>
<summary>Add this plugin to your pom.xml:</summary>
```xml
<plugin>
<groupId>org.cqfn.diktat</groupId>
Expand Down Expand Up @@ -360,7 +355,7 @@ For example:
```yaml
- name: HEADER_MISSING_OR_WRONG_COPYRIGHT
# all rules are enabled by the default. To disable add 'enabled: false' to the config.
enabled: true
enabled: true
configuration:
isCopyrightMandatory: true
copyrightText: Copyright (c) Jeff Lebowski, 2012-2020. All rights reserved.
Expand Down Expand Up @@ -421,12 +416,12 @@ disabling of the inspection on that particular code block:
<summary>Suppress groups of inspections by chapters</summary>
It is easy to suppress even groups of inspections in diKTat.

These groups are linked to chapters of [Codestyle](info/guide/diktat-coding-convention.md).
These groups are linked to chapters of [Codestyle](info/guide/diktat-coding-convention.md).

To disable chapters, you will need to add the following configuration to common configuration (`- name: DIKTAT_COMMON`):
```yaml
disabledChapters: "1, 2, 3"
```
```

Mapping of inspections to chapters can be found in [Groups of Inspections](info/rules-mapping.md).
</details>
Expand All @@ -442,5 +437,5 @@ java -jar ktlint -R dikat.jar --baseline=diktat-baseline.xml **/*.kt
or with corresponding configuration options in maven or gradle plugins. Baseline report is intended to be added into the VCS,
but it can be removed and re-generated later, if needed.

## Contribution
## Contribution
See our [Contributing Policy](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md)
9 changes: 5 additions & 4 deletions diktat-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -107,7 +108,7 @@ val functionalTest = sourceSets.create("functionalTest") {
runtimeClasspath += output + compileClasspath
}
tasks.getByName<Test>("functionalTest") {
dependsOn("test")
shouldRunAfter("test")
testClassesDirs = functionalTest.output.classesDirs
classpath = functionalTest.runtimeClasspath
maxParallelForks = Runtime.getRuntime().availableProcessors()
Expand All @@ -131,7 +132,7 @@ jacocoTestKit {
applyTo("functionalTestRuntimeOnly", tasks.named("functionalTest"))
}
tasks.jacocoTestReport {
dependsOn(tasks.withType<Test>())
shouldRunAfter(tasks.withType<Test>())
executionData(
fileTree("$buildDir/jacoco").apply {
include("*.exec")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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]")
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down
3 changes: 2 additions & 1 deletion examples/gradle-groovy-dsl/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ repositories {
}

diktat {
inputs { include ("src/**/*.kt") }
inputs { it.include ("src/**/*.kt") }
diktatConfigFile = file(rootDir.path + "/diktat-analysis.yml")
}
24 changes: 12 additions & 12 deletions info/guide/guide-TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -103,20 +103,20 @@ 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)
* [6.2.3 Don't use extension functions for the class in the same file](#r6.2.3)
* [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)
Loading

0 comments on commit e39843c

Please sign in to comment.