Skip to content

Commit

Permalink
Updated arguments for diktat-cli (#1860)
Browse files Browse the repository at this point in the history
- `reporter` is optional now
- `output` is required now when `reporter` is provided
- renamed parameters are related to plain output
- added a new type `PLAIN_GROUP_BY_FILE`
  • Loading branch information
nulls authored Dec 15, 2023
1 parent d14f27d commit 6cb0093
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 81 deletions.
23 changes: 8 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,33 +45,26 @@ Main features of diktat are the following:

## Run as CLI-application

### Download and install binaries
[Info](diktat-cli/diktat-cli.adoc)

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

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

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

1. Load diKTat manually: [here](https://github.com/saveourtool/diKTat/releases/download/v1.2.5/diktat-1.2.5.jar)
1. Download diKTat manually: [here](https://github.com/saveourtool/diktat/releases)

**OR** use `curl`:
```console
$ curl -sSLO https://github.com/saveourtool/diKTat/releases/download/v1.2.5/diktat-1.2.5.jar && chmod a+x diktat-1.2.5.jar
```shell
curl -sSLO https://github.com/saveourtool/diktat/releases/download/v2.0.0/diktat && chmod a+x diktat
```

### 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,experimental,test,custom "dir/your/dir/**/*.kt"
$ ./diktat "dir/your/dir/**/*.kt"
```

To **autofix** all code style violations, use `-F` option.
To **autofix** all code style violations, use `--mode fix` 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 --add-opens=java.base/java.lang=ALL-UNNAMED` flag to the JVM. For more information, see: https://github.com/pinterest/ktlint/issues/1195
Expand All @@ -81,7 +74,7 @@ This can be done by setting `MAVEN_OPTS` variable:
export MAVEN_OPTS="--add-opens java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED"
```

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).
This plugin is available since version 0.1.3. You can see how it is configured in our examples for self-checks: [examples](examples/maven/pom.xml).
If you use it and encounter any problems, feel free to open issues on [github](https://github.com/saveourtool/diktat/issues).

<details>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ enum class DiktatReporterType(
CHECKSTYLE("checkstyle", "xml"),
HTML("html", "html"),
JSON("json", "json"),
NONE("none", ""),
PLAIN("plain", "txt"),
PLAIN_GROUP_BY_FILE("plain-group-by-file", "txt"),
SARIF("sarif", "sarif"),
;
}
89 changes: 89 additions & 0 deletions diktat-cli/diktat-cli.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
= _diktat-cli_, the command-line client for https://github.com/saveourtool/diktat[_diKTat_]
:toc:

[#features]
== Features

* Self-executable JAR in _UNIX Shell_ (requires installed _JAVA_)
* BSD-compatible
* Also works in Windows (_Git Bash_, _Cygwin_, or _MSys2_) via the dedicated _diktat.cmd_
* Can be used as a regular uber JAR
[#usage]
== Usage

[source,bash]
----
diktat [OPTION]... [FILE]...
----

[#options]
== Option summary

.Options
[cols="1,3"]
|===
| Command-line switch | Meaning

| `-c CONFIG`, `--config=CONFIG`
| Specify the location of the YAML configuration file. By default,
`diktat-analysis.yml` in the current directory is used.

| `-m MODE`, `--mode MODE`
| Mode of `diktat` controls that `diktat` fixes or
only finds any deviations from the code style.

| `-r REPORTER`, `--reporter=REPORTER`
| The reporter to use to errors to `output`, one of: `plain`, `plain_group_by_file`,
`json`, `sarif`, `checkstyle`, `html`.

| `-o OUTPUT`, `--output=OUTPUT`
| Redirect the reporter output to a file.
Must be provided when the reporter is provided.

| `--group-by-file`
| A flag to group found errors by files.

| `--color COLOR`
| Colorize the output, one of: `BLACK`, `RED`,
`GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, `LIGHT_GRAY`,
`DARK_GRAY`, `LIGHT_RED`, `LIGHT_GREEN`, `LIGHT_YELLOW`,
`LIGHT_BLUE`, `LIGHT_MAGENTA`, `LIGHT_CYAN`, `WHITE`

| `-l`, `--log-level`
| Control the log level.

| `-h`, `--help`
| Display the help text and exit.

| `-l`, `--license`
| Display the license and exit.

| `-v`, `--verbose`
|Enable the verbose output.

| `-V`, `--version`
|Output version information and exit.
|===

[#exit-codes]
== Exit codes

.Exit codes
[cols="1,3"]
|===
| Exit code | Meaning

| 0
| _diKTat_ found no errors in your code

| 1
| _diKTat_ reported some errors in your code

| 2
| The JVM was not found (probably, you need to set up the JVM explicitly, using
the `JAVA_HOME` environment variable)

| 3
| Incompatible _Bash_ version
|===
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import java.io.OutputStream
import java.nio.file.Path
import java.nio.file.Paths

import kotlin.io.path.absolute
import kotlin.io.path.createDirectories
import kotlin.io.path.exists
import kotlin.io.path.inputStream
Expand All @@ -31,22 +32,22 @@ import kotlinx.cli.default
import kotlinx.cli.vararg

/**
* @param groupByFileInPlain
* @param colorNameInPlain
* @param reporterType
* @param output
* @param groupByFileInStdout
* @param colorNameInStdout
* @param logLevel
* @property config path to `diktat-analysis.yml`
* @property mode mode of `diktat`
* @property reporterType
* @property output
* @property patterns
*/
data class DiktatProperties(
val config: String,
val config: String?,
val mode: DiktatMode,
val reporterType: DiktatReporterType,
val output: String?,
private val groupByFileInPlain: Boolean?,
private val colorNameInPlain: String?,
private val reporterType: DiktatReporterType?,
private val output: String?,
private val groupByFileInStdout: Boolean?,
private val colorNameInStdout: String?,
private val logLevel: Level,
val patterns: List<String>,
) {
Expand Down Expand Up @@ -78,19 +79,26 @@ data class DiktatProperties(
sourceRootDir: Path,
loggingListener: DiktatProcessorListener,
): DiktatRunnerArguments {
val reporterCreationArguments = DiktatReporterCreationArguments(
reporterType = reporterType,
outputStream = getReporterOutput(),
groupByFileInPlain = groupByFileInPlain,
colorNameInPlain = colorNameInPlain,
val stdoutReporterCreationArguments = DiktatReporterCreationArguments(
reporterType = DiktatReporterType.PLAIN,
outputStream = null,
sourceRootDir = sourceRootDir,
groupByFileInPlain = groupByFileInStdout,
colorNameInPlain = colorNameInStdout,
)
val reporterCreationArguments = reporterType?.let {
DiktatReporterCreationArguments(
reporterType = it,
outputStream = getRequiredReporterOutput(),
sourceRootDir = sourceRootDir,
)
}
return DiktatRunnerArguments(
configInputStream = Paths.get(config).takeIf { it.exists() }?.inputStream(),
configInputStream = config?.let { Paths.get(it).inputStream() } ?: Paths.get(DIKTAT_ANALYSIS_CONF).takeIf { it.exists() }?.inputStream(),
sourceRootDir = sourceRootDir,
files = getFiles(sourceRootDir),
baselineFile = null,
reporterArgsList = listOf(reporterCreationArguments),
reporterArgsList = listOfNotNull(stdoutReporterCreationArguments, reporterCreationArguments),
loggingListener = loggingListener,
)
}
Expand All @@ -99,10 +107,11 @@ data class DiktatProperties(
.filter { file -> file.isKotlinCodeOrScript() }
.toList()

private fun getReporterOutput(): OutputStream? = output
?.let { Paths.get(it) }
private fun getRequiredReporterOutput(): OutputStream = output
?.let { Paths.get(it).absolute() }
?.also { it.parent.createDirectories() }
?.outputStream()
?: throw IllegalArgumentException("A file for the reporter output is not provided")

companion object {
/**
Expand All @@ -119,38 +128,13 @@ data class DiktatProperties(
args: Array<String>,
): DiktatProperties {
val parser = ArgParser(DIKTAT)
val config: String by parser.option(
type = ArgType.String,
fullName = "config",
shortName = "c",
description = "Specify the location of the YAML configuration file. By default, $DIKTAT_ANALYSIS_CONF in the current directory is used.",
).default(DIKTAT_ANALYSIS_CONF)
val mode: DiktatMode by parser.option(
type = ArgType.Choice<DiktatMode>(),
fullName = "mode",
shortName = "m",
description = "Mode of `diktat` controls that `diktat` fixes or only finds any deviations from the code style."
).default(DiktatMode.CHECK)
val reporterType: DiktatReporterType by parser.reporterType()
val output: String? by parser.option(
type = ArgType.String,
fullName = "output",
shortName = "o",
description = "Redirect the reporter output to a file.",
)
val groupByFileInPlain: Boolean? by parser.option(
type = ArgType.Boolean,
fullName = "plain-group-by-file",
shortName = null,
description = "A flag for plain reporter"
)
val config: String? by parser.config()
val mode: DiktatMode by parser.diktatMode()
val reporterType: DiktatReporterType? by parser.reporterType()
val output: String? by parser.output()
val groupByFile: Boolean? by parser.groupByFile()
val colorName: String? by parser.colorName(diktatReporterFactory)
val logLevel: Level by parser.option(
type = ArgType.Choice<Level>(),
fullName = "log-level",
shortName = "l",
description = "Enable the output with specific level",
).default(Level.INFO)
val logLevel: Level by parser.logLevel()
val patterns: List<String> by parser.argument(
type = ArgType.String,
description = "A list of files to process by diktat"
Expand Down Expand Up @@ -187,39 +171,88 @@ data class DiktatProperties(
mode = mode,
reporterType = reporterType,
output = output,
groupByFileInPlain = groupByFileInPlain,
colorNameInPlain = colorName,
groupByFileInStdout = groupByFile,
colorNameInStdout = colorName,
logLevel = logLevel,
patterns = patterns,
)
}

/**
* @return a single type of [com.saveourtool.diktat.api.DiktatReporter] as parsed cli arg
* @return a single and optional [String] for location of config as parsed cli arg
*/
private fun ArgParser.config() = option(
type = ArgType.String,
fullName = "config",
shortName = "c",
description = "Specify the location of the YAML configuration file. By default, $DIKTAT_ANALYSIS_CONF in the current directory is used.",
)

/**
* @return a single type of [DiktatMode] as parsed cli arg. [DiktatMode.CHECK] is default value
*/
private fun ArgParser.diktatMode() = option(
type = ArgType.Choice<DiktatMode>(),
fullName = "mode",
shortName = "m",
description = "Mode of `diktat` controls that `diktat` fixes or only finds any deviations from the code style."
).default(DiktatMode.CHECK)

/**
* @return a single and optional type of [DiktatReporterType] as parsed cli arg
*/
private fun ArgParser.reporterType() = option(
type = ArgType.Choice<DiktatReporterType>(),
fullName = "reporter",
shortName = "r",
description = "The reporter to use"
description = "The reporter to use to log errors to output."
)

/**
* @return a single and optional [String] for output as parsed cli arg
*/
private fun ArgParser.output() = option(
type = ArgType.String,
fullName = "output",
shortName = "o",
description = "Redirect the reporter output to a file. Must be provided when the reporter is provided.",
)

/**
* @return an optional flag to enable a grouping errors by files
*/
private fun ArgParser.groupByFile() = option(
type = ArgType.Boolean,
fullName = "group-by-file",
shortName = null,
description = "A flag to group found errors by files."
)
.default(DiktatReporterType.PLAIN)

/**
* @param diktatReporterFactory
* @return a single and optional color name as parsed cli args
*/
private fun ArgParser.colorName(diktatReporterFactory: DiktatReporterFactory) = this.option(
private fun ArgParser.colorName(diktatReporterFactory: DiktatReporterFactory) = option(
type = ArgType.Choice(
choices = diktatReporterFactory.colorNamesInPlain.toList(),
toVariant = { it },
variantToString = { it },
),
fullName = "plain-color",
fullName = "color",
shortName = null,
description = "Colorize the output.",
)

/**
* @return a single log leve as parser cli args. [Level.INFO] is default value
*/
private fun ArgParser.logLevel() = option(
type = ArgType.Choice<Level>(),
fullName = "log-level",
shortName = "l",
description = "Control the log level.",
).default(Level.INFO)

private fun ArgParser.addOptionAndShowTextWithExit(
fullName: String,
shortName: String?,
Expand Down
Loading

0 comments on commit 6cb0093

Please sign in to comment.