Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,44 @@ ktlint {
```
</details>

#### KtLint IntelliJ Plugin Integration

If you're using the [ktlint IntelliJ plugin](https://github.com/nbadal/ktlint-intellij-plugin), you can automatically synchronize the ktlint version between your IDE and Gradle builds by creating a `ktlint-plugins.properties` file in your project root directory.

The IntelliJ plugin can read and write the ktlint version to this file. When this file exists and contains a `ktlint-version` property, the Gradle plugin will automatically use that version as the default.

Example `ktlint-plugins.properties` file:
```properties
ktlint-version=1.2.1
```

**Key benefits:**
- Ensures consistency between IDE and build tool ktlint versions
- Simplifies version management across your development team
- Allows IntelliJ plugin to manage the version

**Override behavior:**
Even when the `ktlint-plugins.properties` file exists, you can still explicitly set the version in your `build.gradle` or `build.gradle.kts` file, which will take precedence:

<details>
<summary>Groovy</summary>

```groovy
ktlint {
version = "1.3.0" // This overrides the version in ktlint-plugins.properties
}
```
</details>
<details open>
<summary>Kotlin</summary>

```kotlin
ktlint {
version.set("1.3.0") // This overrides the version in ktlint-plugins.properties
}
```
</details>

### Configuration
The following configuration block is _optional_.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,19 @@ open class KtlintExtension @Inject internal constructor(

/**
* The version of KtLint to use.
*
* If a `ktlint-plugins.properties` file exists in the project root with a `ktlint-version` property,
* that version will be used as the default. Otherwise, defaults to "1.5.0".
*
* This property can be explicitly set in the build script to override the default behavior.
*/
val version: Property<String> = objectFactory.property { set("1.5.0") }
val version: Property<String> = objectFactory.property {
// Try to read version from ktlint-plugins.properties file first
val versionFromFile = readKtlintVersionFromPropertiesFile(
projectLayout.projectDirectory.asFile.toPath()
)
set(versionFromFile ?: "1.5.0")
}

/**
* Enable relative paths in reports
Expand Down
29 changes: 29 additions & 0 deletions plugin/src/main/kotlin/org/jlleitschuh/gradle/ktlint/PluginUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,35 @@ internal inline fun <reified T : Task> Project.registerTask(
}

internal const val EDITOR_CONFIG_FILE_NAME = ".editorconfig"
internal const val KTLINT_PLUGINS_PROPERTIES_FILE_NAME = "ktlint-plugins.properties"
internal const val KTLINT_PLUGINS_VERSION_PROPERTY = "ktlint-version"

/**
* Reads the ktlint version from the ktlint-plugins.properties file if it exists.
* This file is used by the ktlint IntelliJ plugin to store the ktlint version.
*
* @param projectDir The project directory to search for the properties file
* @return The ktlint version string if found, null otherwise
*/
internal fun readKtlintVersionFromPropertiesFile(projectDir: Path): String? {
val propertiesFile = projectDir.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME)
if (!Files.exists(propertiesFile) || !Files.isReadable(propertiesFile)) {
return null
}

return propertiesFile.toFile().useLines { lines ->
lines
.filter { it.contains("=") }
.map {
val key = it.substringBefore("=").trim()
val value = it.substringAfter('=').trim()
key to value
}
.firstOrNull { it.first == KTLINT_PLUGINS_VERSION_PROPERTY }
?.second
?.takeIf { it.isNotBlank() }
}
}

internal fun getEditorConfigFiles(currentProjectDir: Path): Set<Path> {
val result = mutableSetOf<Path>()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package org.jlleitschuh.gradle.ktlint

import org.assertj.core.api.Assertions.assertThat
import org.gradle.util.GradleVersion
import org.jlleitschuh.gradle.ktlint.testdsl.CommonTest
import org.jlleitschuh.gradle.ktlint.testdsl.GradleTestVersions
import org.jlleitschuh.gradle.ktlint.testdsl.build
import org.jlleitschuh.gradle.ktlint.testdsl.project

@GradleTestVersions
class KtlintPluginsPropertiesTest : AbstractPluginTest() {

@CommonTest
fun shouldUseVersionFromKtlintPluginsPropertiesFileWhenPresent(gradleVersion: GradleVersion) {
project(gradleVersion) {
// Create ktlint-plugins.properties file with version
projectPath.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).writeText(
"""
ktlint-version=1.2.1
""".trimIndent()
)

withCleanSources()

buildGradle.appendText(
"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this extra white space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed extra whitespace in commit de73ef6.

tasks.register("printKtlintVersion") {
doLast {
println("Ktlint version: " + ktlint.version.get())
}
}
""".trimIndent()
)

build("printKtlintVersion") {
assertThat(output).contains("Ktlint version: 1.2.1")
}
}
}

@CommonTest
fun shouldUseDefaultVersionWhenKtlintPluginsPropertiesFileIsAbsent(gradleVersion: GradleVersion) {
project(gradleVersion) {
withCleanSources()

buildGradle.appendText(
"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this extra white space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed extra whitespace in commit de73ef6.

tasks.register("printKtlintVersion") {
doLast {
println("Ktlint version: " + ktlint.version.get())
}
}
""".trimIndent()
)

build("printKtlintVersion") {
assertThat(output).contains("Ktlint version: 1.5.0")
}
}
}

@CommonTest
fun shouldAllowExplicitVersionOverrideEvenWhenPropertiesFileExists(gradleVersion: GradleVersion) {
project(gradleVersion) {
// Create ktlint-plugins.properties file with version
projectPath.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).writeText(
"""
ktlint-version=1.2.1
""".trimIndent()
)

withCleanSources()

buildGradle.appendText(
"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this extra white space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed extra whitespace in commit de73ef6.

ktlint {
version = "1.3.0"
}
tasks.register("printKtlintVersion") {
doLast {
println("Ktlint version: " + ktlint.version.get())
}
}
""".trimIndent()
)

build("printKtlintVersion") {
assertThat(output).contains("Ktlint version: 1.3.0")
}
}
}

@CommonTest
fun shouldUseDefaultVersionWhenKtlintVersionPropertyIsBlank(gradleVersion: GradleVersion) {
project(gradleVersion) {
// Create ktlint-plugins.properties file with blank version
projectPath.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).writeText(
"""
ktlint-version=
""".trimIndent()
)

withCleanSources()

buildGradle.appendText(
"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this extra white space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed extra whitespace in commit de73ef6.

tasks.register("printKtlintVersion") {
doLast {
println("Ktlint version: " + ktlint.version.get())
}
}
""".trimIndent()
)

build("printKtlintVersion") {
assertThat(output).contains("Ktlint version: 1.5.0")
}
}
}

@CommonTest
fun shouldUseDefaultVersionWhenPropertiesFileHasNoKtlintVersionProperty(gradleVersion: GradleVersion) {
project(gradleVersion) {
// Create ktlint-plugins.properties file without ktlint-version
projectPath.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).writeText(
"""
some-other-property=value
""".trimIndent()
)

withCleanSources()

buildGradle.appendText(
"""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot remove this extra white space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed extra whitespace in commit de73ef6.

tasks.register("printKtlintVersion") {
doLast {
println("Ktlint version: " + ktlint.version.get())
}
}
""".trimIndent()
)

build("printKtlintVersion") {
assertThat(output).contains("Ktlint version: 1.5.0")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,99 @@ internal class PluginUtilTest {
delete()
}
}

@Test
fun `test readKtlintVersionFromPropertiesFile returns version when file exists`() {
temporaryFolder.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).apply {
createNewFile()
writeText(
"""
ktlint-version=1.2.1
""".trimIndent()
)
val version = readKtlintVersionFromPropertiesFile(temporaryFolder.toPath())
Assertions.assertEquals("1.2.1", version) {
"correctly reads version from properties file"
}
delete()
}
}

@Test
fun `test readKtlintVersionFromPropertiesFile returns null when file does not exist`() {
val version = readKtlintVersionFromPropertiesFile(temporaryFolder.toPath())
Assertions.assertNull(version) {
"returns null when properties file does not exist"
}
}

@Test
fun `test readKtlintVersionFromPropertiesFile returns null when version property is missing`() {
temporaryFolder.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).apply {
createNewFile()
writeText(
"""
some-other-property=value
""".trimIndent()
)
val version = readKtlintVersionFromPropertiesFile(temporaryFolder.toPath())
Assertions.assertNull(version) {
"returns null when ktlint-version property is missing"
}
delete()
}
}

@Test
fun `test readKtlintVersionFromPropertiesFile handles whitespace correctly`() {
temporaryFolder.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).apply {
createNewFile()
writeText(
"""
ktlint-version = 1.3.0
""".trimIndent()
)
val version = readKtlintVersionFromPropertiesFile(temporaryFolder.toPath())
Assertions.assertEquals("1.3.0", version) {
"correctly handles whitespace around equals sign"
}
delete()
}
}

@Test
fun `test readKtlintVersionFromPropertiesFile returns null when version is blank`() {
temporaryFolder.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).apply {
createNewFile()
writeText(
"""
ktlint-version=
""".trimIndent()
)
val version = readKtlintVersionFromPropertiesFile(temporaryFolder.toPath())
Assertions.assertNull(version) {
"returns null when ktlint-version is blank"
}
delete()
}
}

@Test
fun `test readKtlintVersionFromPropertiesFile handles multiple properties`() {
temporaryFolder.resolve(KTLINT_PLUGINS_PROPERTIES_FILE_NAME).apply {
createNewFile()
writeText(
"""
some-property=value1
ktlint-version=1.4.0
another-property=value2
""".trimIndent()
)
val version = readKtlintVersionFromPropertiesFile(temporaryFolder.toPath())
Assertions.assertEquals("1.4.0", version) {
"correctly finds ktlint-version among multiple properties"
}
delete()
}
}
}
Loading