diff --git a/README.md b/README.md
index 707fbb8226..1c7d41036a 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,8 @@ Main features of diktat are the following:
4) **Strict detailed coding convention** that you can use in your project.
## Run as CLI-application
+
+Download and install binaries:
1. Install KTlint manually: [here](https://github.com/pinterest/ktlint/releases)
**OR** use curl:
@@ -68,12 +70,34 @@ Main features of diktat are the following:
```
To **autofix** all code style violations use `-F` option.
+
+
+## GitHub Native Integration
+We suggest everyone to use common ["sarif"](https://docs.oasis-open.org/sarif/sarif/v2.0/sarif-v2.0.html) format as a `reporterType` in CI/CD.
+GitHub has an [integration](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning)
+with SARIF format and provides you a native reporting of diktat issues in Pull Requests.
+
+```text
+ reporterType = "sarif"
+ output = "diktat-report.sarif"
+```
+
+Add the following code to your GitHub Action to upload diktat sarif report (after it was generated).
+
+```yml
+ - name: Upload SARIF to Github using the upload-sarif action
+ uses: github/codeql-action/upload-sarif@v1
+ if: ${{ always() }}
+ with:
+ sarif_file: build/diktat-report.sarif
+```
## Run with Maven using diktat-maven-plugin
This plugin is available since version 0.1.3. You can see how it is configured in our project for self-checks: [pom.xml](pom.xml).
If you use it and encounter any problems, feel free to open issues on [github](https://github.com/cqfn/diktat/issues).
-Add this plugin to your pom.xml:
+
+Add this plugin to your pom.xml:
```xml
org.cqfn.diktat
@@ -101,6 +125,7 @@ Add this plugin to your pom.xml:
```
+
To run diktat in **only-check** mode use command `$ mvn diktat:check@diktat`.
To run diktat in **autocorrect** mode use command `$ mvn diktat:fix@diktat`.
@@ -109,7 +134,9 @@ To run diktat in **autocorrect** mode use command `$ mvn diktat:fix@diktat`.
Requires a gradle version no lower than 5.3.
This plugin is available since version 0.1.5. You can see how the plugin is configured in our examples: [build.gradle.kts](examples/gradle-kotlin-dsl/build.gradle.kts).
-Add this plugin to your `build.gradle.kts`:
+
+
+Add this plugin to your `build.gradle.kts`:
```kotlin
plugins {
id("org.cqfn.diktat.diktat-gradle-plugin") version "1.0.2"
@@ -141,29 +168,21 @@ diktat {
}
```
-Also `diktat` extension has different reporters. You can specify `json`, `html`, `checkstyle`, `plain` (default) or your own custom reporter:
+Also `diktat` extension has different reporters. You can specify `json`, `html`, `sarif`, `plain` (default) or your own custom reporter (it should be added as a dependency into `diktat` configuration):
```kotlin
diktat {
- reporter = "json" // "html", "checkstyle", "plain"
+ reporterType = "json" // "html", "json", "plain" (default), "sarif"
}
```
-Example of your custom reporter:
-```kotlin
-diktat {
- reporter = "custom:name:pathToJar"
-}
-```
-Name parameter is the name of your reporter and as the last parameter you should specify path to jar, which contains your reporter.
-[Example of the junit custom reporter.](https://github.com/kryanod/ktlint-junit-reporter)
-
You can also specify an output.
```kotlin
diktat {
- reporter = "json"
+ reporterType = "json"
output = "someFile.json"
}
```
+
You can run diktat checks using task `diktatCheck` and automatically fix errors with tasks `diktatFix`.
diff --git a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt
index 723368d3eb..1d6f19d9f5 100644
--- a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt
+++ b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt
@@ -45,7 +45,7 @@ class DiktatGradlePluginFunctionalTest {
"""${System.lineSeparator()}
diktat {
inputs { include("src/**/*.kt") }
- reporterType = "json"
+ reporter = "json"
output = "test.txt"
}
""".trimIndent()
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 abd56fed5e..18ff49ea3f 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
@@ -27,7 +27,7 @@ open class DiktatExtension(
/**
* Type of the reporter to use
*/
- var reporterType: String = "plain"
+ var reporter: String = "plain"
/**
* Type of output
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 ca9442ff6a..3b11de7bc4 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
@@ -87,10 +87,6 @@ open class DiktatJavaExecTaskBase @Inject constructor(
main = "com.pinterest.ktlint.Main"
}
- // Plain, checkstyle and json reporter are provided out of the box in ktlint
- if (diktatExtension.reporterType == "html") {
- diktatConfiguration.dependencies.add(project.dependencies.create("com.pinterest.ktlint:ktlint-reporter-html:$KTLINT_VERSION"))
- }
classpath = diktatConfiguration
project.logger.debug("Setting diktatCheck classpath to ${diktatConfiguration.dependencies.toSet()}")
if (diktatExtension.debug) {
@@ -155,13 +151,8 @@ open class DiktatJavaExecTaskBase @Inject constructor(
private fun createReporterFlag(diktatExtension: DiktatExtension): String {
val flag: StringBuilder = StringBuilder()
- // Plain, checkstyle and json reporter are provided out of the box in ktlint
- when (diktatExtension.reporterType) {
- "json" -> flag.append("--reporter=json")
- "html" -> flag.append("--reporter=html")
- "checkstyle" -> flag.append("--reporter=checkstyle")
- else -> customReporter(diktatExtension, flag)
- }
+ // appending the flag with the reporter
+ setReporter(diktatExtension, flag)
if (diktatExtension.output.isNotEmpty()) {
flag.append(",output=${diktatExtension.output}")
@@ -170,19 +161,14 @@ open class DiktatJavaExecTaskBase @Inject constructor(
return flag.toString()
}
- private fun customReporter(diktatExtension: DiktatExtension, flag: java.lang.StringBuilder) {
- if (diktatExtension.reporterType.startsWith("custom")) {
- val name = diktatExtension.reporterType.split(":")[1]
- val jarPath = diktatExtension.reporterType.split(":")[2]
- if (name.isEmpty() || jarPath.isEmpty()) {
- project.logger.warn("Either name or path to jar is not specified. Falling to plain reporter")
- flag.append("--reporter=plain")
- } else {
- flag.append("--reporter=$name,artifact=$jarPath")
- }
- } else {
+ private fun setReporter(diktatExtension: DiktatExtension, flag: java.lang.StringBuilder) {
+ val name = diktatExtension.reporter.trim()
+ val validReporters = listOf("sarif", "plain", "json", "html")
+ if (name.isEmpty() || !validReporters.contains(name)) {
+ project.logger.warn("Reporter name $name was not specified or is invalid. Falling to 'plain' reporter")
flag.append("--reporter=plain")
- project.logger.debug("Unknown reporter was specified. Falling back to plain reporter.")
+ } else {
+ flag.append("--reporter=$name")
}
}
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 439b8ee823..b332471742 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
@@ -37,6 +37,6 @@ class DiktatGradlePluginTest {
@Test
fun `check that the right reporter dependency added`() {
val diktatExtension = project.extensions.getByName("diktat") as DiktatExtension
- Assertions.assertTrue(diktatExtension.reporterType == "plain")
+ Assertions.assertTrue(diktatExtension.reporter == "plain")
}
}
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 0d3710723d..146c4d68e7 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
@@ -94,7 +94,7 @@ class DiktatJavaExecTaskTest {
) {
inputs { exclude("*") }
diktatConfigFile = project.file("../diktat-analysis.yml")
- reporterType = "json"
+ reporter = "json"
output = "some.txt"
}
}
@@ -106,38 +106,10 @@ class DiktatJavaExecTaskTest {
) {
inputs { exclude("*") }
diktatConfigFile = project.file("../diktat-analysis.yml")
- reporterType = "json"
+ reporter = "json"
}
}
- @Test
- fun `check command line has custom reporter type with output`() {
- assertCommandLineEquals(
- listOf(null, "--reporter=customName,artifact=customPath")
- ) {
- inputs { exclude("*") }
- diktatConfigFile = project.file("../diktat-analysis.yml")
- reporterType = "custom:customName:customPath"
- }
- }
-
- @Test
- fun `check that project has html dependency`() {
- val task = project.registerDiktatTask {
- inputs { exclude("*") }
- diktatConfigFile = project.file("../diktat-analysis.yml")
- reporterType = "html"
- }
-
- Assertions.assertTrue(
- project
- .configurations
- .getByName("diktat")
- .dependencies
- .any { it.name == "ktlint-reporter-html" })
- Assertions.assertEquals(File(project.projectDir.parentFile, "diktat-analysis.yml").absolutePath, task.systemProperties[DIKTAT_CONF_PROPERTY])
- }
-
@Test
fun `check system property with multiproject build with default config`() {
setupMultiProject()
diff --git a/diktat-maven-plugin/pom.xml b/diktat-maven-plugin/pom.xml
index 5fab75ffaf..b8dba2f2f9 100644
--- a/diktat-maven-plugin/pom.xml
+++ b/diktat-maven-plugin/pom.xml
@@ -54,6 +54,21 @@
ktlint-reporter-plain
${ktlint.version}
+
+ com.pinterest.ktlint
+ ktlint-reporter-sarif
+ ${ktlint.version}
+
+
+ com.pinterest.ktlint
+ ktlint-reporter-json
+ ${ktlint.version}
+
+
+ com.pinterest.ktlint
+ ktlint-reporter-html
+ ${ktlint.version}
+
org.junit.vintage
junit-vintage-engine
diff --git a/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt b/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt
index 88b87fe277..d0408ecd4e 100644
--- a/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt
+++ b/diktat-maven-plugin/src/main/kotlin/org/cqfn/diktat/plugin/maven/DiktatBaseMojo.kt
@@ -4,9 +4,13 @@ import org.cqfn.diktat.ruleset.rules.DiktatRuleSetProvider
import com.pinterest.ktlint.core.KtLint
import com.pinterest.ktlint.core.LintError
+import com.pinterest.ktlint.core.Reporter
import com.pinterest.ktlint.core.RuleExecutionException
import com.pinterest.ktlint.core.RuleSet
+import com.pinterest.ktlint.reporter.html.HtmlReporter
+import com.pinterest.ktlint.reporter.json.JsonReporter
import com.pinterest.ktlint.reporter.plain.PlainReporter
+import com.pinterest.ktlint.reporter.sarif.SarifReporter
import org.apache.maven.plugin.AbstractMojo
import org.apache.maven.plugin.MojoExecutionException
import org.apache.maven.plugin.MojoFailureException
@@ -14,6 +18,8 @@ import org.apache.maven.plugins.annotations.Parameter
import org.apache.maven.project.MavenProject
import java.io.File
+import java.io.FileOutputStream
+import java.io.PrintStream
/**
* Base [Mojo] for checking and fixing code using diktat
@@ -25,8 +31,19 @@ abstract class DiktatBaseMojo : AbstractMojo() {
@Parameter(property = "diktat.debug")
var debug = false
- // FixMe: Reporter should be chosen via plugin configuration
- private val reporter = PlainReporter(System.out)
+ /**
+ * Type of the reporter to use
+ */
+ @Parameter(property = "diktat.reporter")
+ var reporter = "plain"
+
+ /**
+ * Type of output
+ * Default: System.out
+ */
+ @Parameter(property = "diktat.output")
+ var output = ""
+ private lateinit var reporterImpl: Reporter
/**
* Path to diktat yml config file. Can be either absolute or relative to project's root directory.
@@ -64,6 +81,7 @@ abstract class DiktatBaseMojo : AbstractMojo() {
* @throws MojoExecutionException if [RuleExecutionException] has been thrown
*/
override fun execute() {
+ reporterImpl = resolveReporter()
val configFile = resolveConfig()
if (!File(configFile).exists()) {
throw MojoExecutionException("Configuration file $diktatConfigFile doesn't exist")
@@ -83,12 +101,26 @@ abstract class DiktatBaseMojo : AbstractMojo() {
checkDirectory(it, lintErrors, ruleSets)
}
- reporter.afterAll()
+ reporterImpl.afterAll()
if (lintErrors.isNotEmpty()) {
throw MojoFailureException("There are ${lintErrors.size} lint errors")
}
}
+ private fun resolveReporter(): Reporter {
+ val output = if (this.output.isBlank()) System.`out` else PrintStream(FileOutputStream(this.output, true))
+ return when (this.reporter) {
+ "sarif" -> SarifReporter(output)
+ "plain" -> PlainReporter(output)
+ "json" -> JsonReporter(output)
+ "html" -> HtmlReporter(output)
+ else -> {
+ log.warn("Reporter name ${this.reporter} was not specified or is invalid. Falling to 'plain' reporter")
+ PlainReporter(output)
+ }
+ }
+ }
+
/**
* Function that searches diktat config file in maven project hierarchy.
* If [diktatConfigFile] is absolute, it's path is used. If [diktatConfigFile] is relative, this method looks for it in all maven parent projects.
@@ -128,9 +160,9 @@ abstract class DiktatBaseMojo : AbstractMojo() {
.forEach { file ->
log.debug("Checking file $file")
try {
- reporter.before(file.path)
+ reporterImpl.before(file.path)
checkFile(file, lintErrors, ruleSets)
- reporter.after(file.path)
+ reporterImpl.after(file.path)
} catch (e: RuleExecutionException) {
log.error("Unhandled exception during rule execution: ", e)
throw MojoExecutionException("Unhandled exception during rule execution", e)
@@ -151,7 +183,7 @@ abstract class DiktatBaseMojo : AbstractMojo() {
userData = mapOf("file_path" to file.path),
script = file.extension.equals("kts", ignoreCase = true),
cb = { lintError, isCorrected ->
- reporter.onLintError(file.path, lintError, isCorrected)
+ reporterImpl.onLintError(file.path, lintError, isCorrected)
lintErrors.add(lintError)
},
debug = debug
diff --git a/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatMavenPluginIntegrationTest.kt b/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatMavenPluginIntegrationTest.kt
index 231273b66b..dd44337614 100644
--- a/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatMavenPluginIntegrationTest.kt
+++ b/diktat-maven-plugin/src/test/kotlin/org/cqfn/diktat/plugin/maven/DiktatMavenPluginIntegrationTest.kt
@@ -46,6 +46,7 @@ class DiktatMavenPluginIntegrationTest {
Assertions.assertTrue(result.isFailure)
val mavenLog = result.mavenLog.stdout.readText()
+
Assertions.assertTrue(
mavenLog.contains(Regex("""Original and formatted content differ, writing to [:\w/\\]+Test\.kt\.\.\."""))
)