Skip to content

Commit

Permalink
Merge pull request #40 from usefulness/updates
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuszkwiecinski authored Feb 4, 2023
2 parents 2a1305d + df6c483 commit 68aeafa
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 229 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/diffuse.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ jobs:
Diffuse output:
${{ steps.diffuse.outputs.diff-gh-comment }}
File path: `${{ steps.diffuse.outputs.diff-file }}`
edit-mode: replace
comment-id: ${{ steps.find_comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
Expand Down
140 changes: 36 additions & 104 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,18 @@ Gradle wrapper for [pinterest/ktlint](https://github.com/pinterest/ktlint)
### Installation

Available on the:

- [Gradle Plugin Portal](https://plugins.gradle.org/plugin/io.github.usefulness.ktlint-gradle-plugin)
- [Maven Central](https://mvnrepository.com/artifact/io.github.usefulness/kotlin-gradle-plugin)

#### Apply the plugin


```kotlin
```groovy
plugins {
id("io.github.usefulness.ktlint-gradle-plugin") version "{{version}}"
}
```


### Compatibility

| plugin version | min gradle version | min ktlint version |
Expand All @@ -31,158 +30,91 @@ plugins {
### Features

- Supports Kotlin Gradle plugins:
- [JVM](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm)
- [Multiplatform](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.multiplatform)
- [Android](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.android)
- [JS](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.js)
- [JVM](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm)
- [Multiplatform](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.multiplatform)
- [Android](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.android)
- [JS](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.js)
- Supports `.kt` and `.kts` files
- Incremental build support and fast parallelization with Gradle Worker API
- Leverages latest Gradle APIs (cacheable, incremental tasks using Gradle Worker API)
- Configurable reporters

### Tasks

When your project uses one of the supported Kotlin Gradle plugins, the plugin adds these tasks:

`formatKotlin`: format Kotlin source code according to `ktlint` rules or warn when auto-format not possible.
- `./gradlew formatKotlin`: format Kotlin source code according to `ktlint` rules or warn when auto-format not possible.

`lintKotlin`: report Kotlin lint errors and by default fail the build.
- `./gradlew lintKotlin`: report Kotlin lint errors and by default fail the build.

Also `check` becomes dependent on `lintKotlin`.

Granular tasks are added for each source set in the project: `formatKotlin`*`SourceSet`* and `lintKotlin`*`SourceSet`*.

### Configuration
Options are configured in the `ktlint` extension:

<details open>
<summary>Kotlin</summary>

```kotlin
ktlint {
ignoreFailures = false
reporters = emptyArray()
experimentalRules = false
disabledRules = emptyArray()
ktlintVersion = "x.y.z"
chunkSize = 50
}
```

</details>

<details>
<summary>Groovy</summary>
Options can be configured in the `ktlint` extension:

```groovy
ktlint {
ignoreFailures = false
reporters = []
experimentalRules = false
disabledRules = []
ktlintVersion = 'x.y.z'
reporters = ["checkstyle", "html", "json", "plain", "sarif"]
experimentalRules = true
disabledRules = ["no-wildcard-imports", "experimental:annotation", "your-custom-rule:no-bugs"]
ktlintVersion = "1.0.0-SNAPSHOT"
chunkSize = 50
baselineFile.set(file("config/ktlint_baseline.xml"))
}
```

</details>

`ignoreFailures` - makes the `LintTask` tasks alway spass
`reporters` - defines enable [reporters](https://pinterest.github.io/ktlint/install/cli/#violation-reporting) for all tasks. Supported values: `checkstyle`, `html`, `json`, `plain`, `sarif`
`experimentalRules` - enables rules from ktlint [Experimental](https://pinterest.github.io/ktlint/rules/experimental/) ruleset.
`disabledRules` - can include an array of rule ids you wish to disable. For example to allow wildcard imports:
```groovy
disabledRules = ["no-wildcard-imports"]
```
You must prefix rule ids not part of the standard rule set with `<rule-set-id>:<rule-id>`. For example `experimental:annotation`.

`ktlintVersion` There is a basic support for overriding ktlint version, but the plugin doesn't guarantee backwards compatibility with all `ktlint` versions.
Errors like `java.lang.NoSuchMethodError:` or `com/pinterest/ktlint/core/KtLint$Params` can be thrown if provided `ktlint` version isn't compatible with the latest ktlint apis.
- `ignoreFailures` - makes the `LintTask` tasks always pass
- `reporters` - defines enable [reporters](https://pinterest.github.io/ktlint/install/cli/#violation-reporting) for all
tasks.
- `experimentalRules` - enables rules from ktlint [Experimental](https://pinterest.github.io/ktlint/rules/experimental/)
ruleset.
- `disabledRules` - can include an array of rule ids you wish to disable
- `ktlintVersion` There is a basic support for overriding ktlint version, but the plugin doesn't guarantee backwards
compatibility with all `ktlint` versions.
Errors like `java.lang.NoSuchMethodError:` or `com/pinterest/ktlint/core/KtLint$Params` can be thrown if
provided `ktlint` version isn't compatible with the latest ktlint apis.

`chunkSize` - defines how many files will be processed by a single gradle worker in parallel
- `chunkSize` - defines how many files will be processed by a single gradle worker in parallel
- `baselineFile` - points at location of baseline file containing _known_ offenses that will be ignored during `lintKotlin` task execution

### Customizing Tasks

The `formatKotlin`*`SourceSet`* and `lintKotlin`*`SourceSet`* tasks inherit from [SourceTask](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceTask.html)
The `formatKotlin`*`SourceSet`* and `lintKotlin`*`SourceSet`* tasks inherit
from [SourceTask](https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceTask.html)
so you can customize includes, excludes, and source.

<details open>
<summary>Kotlin</summary>

```kotlin
tasks.lintKotlinMain {
exclude("com/example/**/generated/*.kt")
}
```

</details>

<details>
<summary>Groovy</summary>

```groovy
tasks.named('lintKotlinMain') {
exclude 'com/example/**/generated/*.kt'
tasks.named("lintKotlinMain") {
exclude("com/example/**/generated/*.kt")
}
```

</details>

Note that exclude paths are relative to the package root.

#### Advanced
By default, Gradle workers will use 256MB of heap size. To adjust this setting use:
<details>
<summary>Kotlin</summary>

```kotlin
import io.github.usefulness.tasks.KtlintWorkTask

tasks.withType<KtlintWorkTask> {
workerMaxHeapSize.set("512m")
}
```

</details>

<details>
<summary>Groovy</summary>
By default, Gradle workers will use 256MB of heap size. To adjust this setting use:

```groovy
import io.github.usefulness.tasks.KtlintWorkTask
tasks.withType(KtlintWorkTask::class).configureEach {
workerMaxHeapSize.set("512m")
tasks.withType(KtlintWorkTask).configureEach {
workerMaxHeapSize.set("512m")
}
```

</details>

### Custom Rules

You can add custom `ktlint` RuleSets using the `ktlintRuleSet` configuration dependency:

<details open>
<summary>Kotlin</summary>

```kotlin
```groovy
dependencies {
ktlintRuleSet(files("libs/my-custom-ktlint-rules.jar"))
ktlintRuleSet(project(":ktlint-custom-rules"))
ktlintRuleSet("org.other.ktlint:custom-rules:1.0")
ktlintRuleSet("com.twitter.compose.rules:ktlint:0.0.26")
}
```

</details>

<details>
<summary>Groovy</summary>

```groovy
dependencies {
ktlintRuleSet files('libs/my-custom-ktlint-rules.jar')
ktlintRuleSet project(':ktlint-custom-rules')
ktlintRuleSet 'org.other.ktlint:custom-rules:1.0'
}
```

</details>
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
package io.github.usefulness

import io.github.usefulness.support.versionProperties
import io.github.usefulness.tasks.listProperty
import io.github.usefulness.tasks.property
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property

public open class KtlintGradleExtension internal constructor(
objectFactory: ObjectFactory,
) {

public open class KtlintGradleExtension {
internal companion object {
const val DEFAULT_IGNORE_FAILURES = false
const val DEFAULT_EXPERIMENTAL_RULES = false
const val DEFAULT_CHUNK_SIZE = 50
val DEFAULT_DISABLED_RULES = emptyArray<String>()
val DEFAULT_DISABLED_RULES = emptyList<String>()
}

public var ignoreFailures: Boolean = DEFAULT_IGNORE_FAILURES
public var ignoreFailures: Property<Boolean> = objectFactory.property(default = DEFAULT_IGNORE_FAILURES)

public var reporters: ListProperty<String> = objectFactory.listProperty(default = emptyList())

public var reporters: Array<String> = emptyArray()
public var experimentalRules: Property<Boolean> = objectFactory.property(default = DEFAULT_EXPERIMENTAL_RULES)

public var experimentalRules: Boolean = DEFAULT_EXPERIMENTAL_RULES
public var disabledRules: ListProperty<String> = objectFactory.listProperty(default = DEFAULT_DISABLED_RULES)

public var disabledRules: Array<String> = DEFAULT_DISABLED_RULES
public var ktlintVersion: Property<String> = objectFactory.property(default = versionProperties.ktlintVersion())

public var ktlintVersion: String = versionProperties.ktlintVersion()
public var chunkSize: Property<Int> = objectFactory.property(default = DEFAULT_CHUNK_SIZE)

public var chunkSize: Int = DEFAULT_CHUNK_SIZE
public var baselineFile: RegularFileProperty = objectFactory.fileProperty()
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package io.github.usefulness

import io.github.usefulness.support.ReporterType
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import io.github.usefulness.pluginapplier.AndroidSourceSetApplier
import io.github.usefulness.pluginapplier.KotlinSourceSetApplier
import io.github.usefulness.tasks.KtlintWorkTask
import io.github.usefulness.support.ReporterType
import io.github.usefulness.tasks.FormatTask
import io.github.usefulness.tasks.KtlintWorkTask
import io.github.usefulness.tasks.LintTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import java.io.File

public class KtlintGradlePlugin : Plugin<Project> {
Expand Down Expand Up @@ -42,7 +42,7 @@ public class KtlintGradlePlugin : Plugin<Project> {
task.ktlintClasspath.setFrom(ktlintConfiguration)
task.ruleSetsClasspath.setFrom(ruleSetConfiguration)
task.reportersConfiguration.setFrom(reportersConfiguration)
task.chunkSize.set(provider { pluginExtension.chunkSize })
task.chunkSize.set(pluginExtension.chunkSize)
}

sourceResolver.applyToAll(this) { id, resolvedSources ->
Expand All @@ -51,14 +51,13 @@ public class KtlintGradlePlugin : Plugin<Project> {
LintTask::class.java,
) { task ->
task.source(resolvedSources)

task.experimentalRules.set(provider { pluginExtension.experimentalRules })
task.disabledRules.set(provider { pluginExtension.disabledRules.toList() })

task.ignoreFailures.set(provider { pluginExtension.ignoreFailures })
task.experimentalRules.set(pluginExtension.experimentalRules)
task.disabledRules.set(pluginExtension.disabledRules)
task.ignoreFailures.set(pluginExtension.ignoreFailures)
task.baselineFile.set(pluginExtension.baselineFile)
task.reports.set(
provider {
pluginExtension.reporters.associateWith { reporterId ->
pluginExtension.reporters.map {
it.associateWith { reporterId ->
val type = ReporterType.getById(reporterId)
reportFile("$id-lint.${type.fileExtension}")
}
Expand All @@ -72,12 +71,13 @@ public class KtlintGradlePlugin : Plugin<Project> {
FormatTask::class.java,
) { task ->
task.source(resolvedSources)
task.experimentalRules.set(provider { pluginExtension.experimentalRules })
task.disabledRules.set(provider { pluginExtension.disabledRules.toList() })
task.ignoreFailures.set(provider { true })
task.experimentalRules.set(pluginExtension.experimentalRules)
task.disabledRules.set(pluginExtension.disabledRules)
task.ignoreFailures.set(true)
task.baselineFile.set(pluginExtension.baselineFile)
task.reports.set(
provider {
pluginExtension.reporters.associateWith { reporterId ->
pluginExtension.reporters.map {
it.associateWith { reporterId ->
val type = ReporterType.getById(reporterId)
reportFile("$id-format.${type.fileExtension}")
}
Expand Down Expand Up @@ -112,7 +112,7 @@ public class KtlintGradlePlugin : Plugin<Project> {
isVisible = false

val dependencyProvider = provider {
val ktlintVersion = pluginExtension.ktlintVersion
val ktlintVersion = pluginExtension.ktlintVersion.get()
this@createKtlintConfiguration.dependencies.create("com.pinterest:ktlint:$ktlintVersion")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.usefulness.support

import com.pinterest.ktlint.core.LintError
import com.pinterest.ktlint.core.api.Baseline
import com.pinterest.ktlint.core.api.loadBaseline
import java.io.File

internal fun File.readKtlintBaseline(): Map<String, List<LintError>>? {
val baseline = loadBaseline(absolutePath)
when (baseline.status) {
Baseline.Status.VALID -> Unit
Baseline.Status.NOT_FOUND,
Baseline.Status.INVALID,
-> return null
}

return baseline.lintErrorsPerFile
}

internal fun File.getBaselineKey(projectDir: File) =
toRelativeString(projectDir).replace(File.separatorChar, '/')

/**
* Same as ktlint, avoids unnecessary incompatibility issues
*/
internal fun List<LintError>.doesNotContain(lintError: LintError) =
none {
it.col == lintError.col &&
it.line == lintError.line &&
it.ruleId == lintError.ruleId
}
Loading

0 comments on commit 68aeafa

Please sign in to comment.