Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlinter is not ignoring generated files #208

Closed
joshmsamuels opened this issue Jun 28, 2021 · 30 comments
Closed

Kotlinter is not ignoring generated files #208

joshmsamuels opened this issue Jun 28, 2021 · 30 comments

Comments

@joshmsamuels
Copy link

joshmsamuels commented Jun 28, 2021

I have several generated kotlin files in my app (inside a build directory) which creates kotlin code that ktlint doesnt like. Since I have no control over the code generation and it is not being checked into git I would like ktlint to ignore the files within the build directory.

I tried adding several variations of exclude("build/**") but each time ktlint was failing on the generated files. Is there any way to ignore the build directory?

Note: I added the exclude directory to "lintKotlinMain"(org.jmailen.gradle.kotlinter.tasks.LintTask::class) { as stated in the README

Thanks so much!

@joshmsamuels
Copy link
Author

Since I wasnt sure the exact format expected, the other exclude variations I tried are:

exclude("**/build")
exclude("**/build/**")
exclude("build/***")

@jeremymailen
Copy link
Owner

Thanks Josh, let me see if I can figure this one out.
If you navigate to the module in question and do gradle tasks --all, are there other lintKotlinX tasks for other sourceSets? It could be your generated files aren't in the "main" source set, but maybe another kotlinter detected.

Is that the same "build" directory as the one gradle uses for output?

The LintTask extends the standard Gradle SourceTask so exclude takes standard pattern arguments https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceTask.html

@joshmsamuels
Copy link
Author

joshmsamuels commented Jun 29, 2021

there is a lintKotlin, lintKotlinMain, and lintKotlinTest for each of the subprojects inside my main project.

It could be your generated files aren't in the "main" source set, but maybe another kotlinter detected

kotlinter is only defined in the root project.

Is that the same "build" directory as the one gradle uses for output?

Yes!

Thanks so much for the quick follow-up. I'm very new to gradle so I may have done something wrong as well

@joshmsamuels
Copy link
Author

joshmsamuels commented Jun 29, 2021

Based on this issue in ktlint and the ant pattern docs it looks like the correct syntax is **/build/** or **/build/ which should be equivalent.

@jeremymailen I tried both formats just now and it still didnt work 🙃

@jeremymailen
Copy link
Owner

Can you show what the project structure looks like? Are these generated files being created by another gradle plugin or custom build code?

I ask because build seems unusual. Each of the kotlinter subtasks are associated with a sourceSet. For example the main source set for a project might have its root at project/src/main/kotlin and the exclude paths would be relative to that.
Kotlinter operates very similar to the gradle quality plugin which has some examples here: https://xvik.github.io/gradle-quality-plugin/2.4.0/guide/exclusion/

@joshmsamuels
Copy link
Author

is there a way to log the relative root for a source set?

@jeremymailen
Copy link
Owner

You should be able to do something like this in your Gradle script

sourceSets.forEach {
    val dirPaths = it.java.srcDirs.map { d -> d.path }
    println("${it.name} : ${dirPaths.joinToString()}")
}

Kotlin JVM gradle plugin uses java sourceSet to configure things (see https://kotlinlang.org/docs/gradle.html#kotlin-and-java-sources).

Typically a standard project will have two sourceSets main and test. For kotlinter itself

main : /path/to/git/kotlinter-gradle/src/main/java
test : /path/to/git/kotlinter-gradle/src/test/java

@jeremymailen
Copy link
Owner

Do you have any thoughts on the above questions -- what's generating your sources and your project structure?

@arnabkd
Copy link

arnabkd commented Jul 7, 2021

I have a similar problem (see image below):
image

My sources are being generated by Apollo Android and my project structure is like this:

/${projectDir}/src/main/kotlin <- where all the code resides for my app
/${projectDir}/src/test/kotlin <- tests
/${projectDir}/build/generated/... <- generated code from apollo android

@joshmsamuels
Copy link
Author

@jeremymailen where do I add that sourceSets block in the build.gradle.kts? sourceSets was not defined in the root, in tasks, or within the lintTask

@jeremymailen
Copy link
Owner

jeremymailen commented Jul 18, 2021

Sorry, was out of town -- if you're still looking for a solution:
It occurs to me the easiest way to debug the problem is probably just debugging which files being linted:

gradle -d lintKotlin | grep linting

You'll see output including the relative file path and name of the lint task that is operating on it. For example:

2021-07-18T15:44:06.584-0700 [DEBUG] [org.jmailen.gradle.kotlinter.tasks.LintTask] lintKotlinTest linting: src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt

The key is to make sure you're modifying the excludes for the correct lint task and a matching path.

That's helpful info about the Apollo plugin. It looks like what it does is add a new path to each sourceSet under build/generated. For Apollo, did you try exclude("**/generated/**")?

@jeremymailen
Copy link
Owner

Ok, did a few experiments with ordinary source sets. It appears the exclude path is oriented to the package, regardless of the root. For example to exclude my above file you'd need to:

tasks {
    "lintKotlinTest"(LintTask::class) {
        exclude("/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt")
    }
}

Or any glob including that exact path.

I know it's not the most user friendly when there's a whole root you need to exclude. Is there a pattern within the package or file names you can target instead?

I suppose we could break our dependency on Gradle's SourceTask but would take some careful thought on how to extend it to add something like excludeSources.

@arnabkd
Copy link

arnabkd commented Jul 19, 2021

Sorry, was out of town -- if you're still looking for a solution:
It occurs to me the easiest way to debug the problem is probably just debugging which files being linted:

gradle -d lintKotlin | grep linting

You'll see output including the relative file path and name of the lint task that is operating on it. For example:

2021-07-18T15:44:06.584-0700 [DEBUG] [org.jmailen.gradle.kotlinter.tasks.LintTask] lintKotlinTest linting: src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt

The key is to make sure you're modifying the excludes for the correct lint task and a matching path.

That's helpful info about the Apollo plugin. It looks like what it does is add a new path to each sourceSet under build/generated. For Apollo, did you try exclude("**/generated/**")?

I did try all of the variants that are described in the OP and with the generated blob as well:

exclude("**/build")
exclude("**/build/**")
exclude("build/***")

exclude("**/generated")
exclude("**/generated/**")
exclude("generated/***")

Those did not work. I am currently just contemplating running a ktlint check without the plugin, but it would be nice if the plugin was able to do this on its own.

@jeremymailen
Copy link
Owner

Sorry, was out of town -- if you're still looking for a solution:
It occurs to me the easiest way to debug the problem is probably just debugging which files being linted:

gradle -d lintKotlin | grep linting

You'll see output including the relative file path and name of the lint task that is operating on it. For example:

2021-07-18T15:44:06.584-0700 [DEBUG] [org.jmailen.gradle.kotlinter.tasks.LintTask] lintKotlinTest linting: src/test/kotlin/org/jmailen/gradle/kotlinter/functional/KotlinProjectTest.kt

The key is to make sure you're modifying the excludes for the correct lint task and a matching path.
That's helpful info about the Apollo plugin. It looks like what it does is add a new path to each sourceSet under build/generated. For Apollo, did you try exclude("**/generated/**")?

I did try all of the variants that are described in the OP and with the generated blob as well:

exclude("**/build")
exclude("**/build/**")
exclude("build/***")

exclude("**/generated")
exclude("**/generated/**")
exclude("generated/***")

Those did not work. I am currently just contemplating running a ktlint check without the plugin, but it would be nice if the plugin was able to do this on its own.

Ok, see my other note above -- it will work, but you must use a path matcher on the package or filename portion.

@arnabkd
Copy link

arnabkd commented Jul 19, 2021

Ok, see my other note above -- it will work, but you must use a path matcher on the package or filename portion.

So with that I can just do the following?

tasks {
    "lintKotlinMain"(LintTask::class) {
        exclude("build/generated/source/apollo/main/service/*.kt")
    }
}

@jeremymailen
Copy link
Owner

Ok, see my other note above -- it will work, but you must use a path matcher on the package or filename portion.

So with that I can just do the following?

tasks {
    "lintKotlinMain"(LintTask::class) {
        exclude("build/generated/source/apollo/main/service/*.kt")
    }
}

No you must use the package and filename portion of the path.

I'm just imagining how apollo might choose a package, but hopefully it's unique.

tasks {
    "lintKotlinMain"(LintTask::class) {
        exclude("service/graphql/*.kt")
    }
}

@arnabkd
Copy link

arnabkd commented Jul 19, 2021

Ok, see my other note above -- it will work, but you must use a path matcher on the package or filename portion.

So with that I can just do the following?

tasks {
    "lintKotlinMain"(LintTask::class) {
        exclude("build/generated/source/apollo/main/service/*.kt")
    }
}

No you must use the package and filename portion of the path.

I'm just imagining how apollo might choose a package, but hopefully it's unique.

tasks {
    "lintKotlinMain"(LintTask::class) {
        exclude("service/graphql/*.kt")
    }
}

Ah ok, but apollo unfortunately does not create a package for anything but primitive types. So most of the generated classes are not in a package. In my case for instance, I simply do import TripQuery (which is where the generated code resides).

@jeremymailen
Copy link
Owner

Ah ok, but apollo unfortunately does not create a package for anything but primitive types. So most of the generated classes are not in a package. In my case for instance, I simply do import TripQuery (which is where the generated code resides).

It's looks like they provide a rootPackageName?
https://www.apollographql.com/docs/android/essentials/plugin-configuration/

Also seems like here:
https://www.apollographql.com/docs/android/essentials/get-started-kotlin/

apollo {
  packageName.set("com.example")
}

@arnabkd
Copy link

arnabkd commented Jul 20, 2021

Ah ok, but apollo unfortunately does not create a package for anything but primitive types. So most of the generated classes are not in a package. In my case for instance, I simply do import TripQuery (which is where the generated code resides).

It's looks like they provide a rootPackageName?
apollographql.com/docs/android/essentials/plugin-configuration

Also seems like here:
apollographql.com/docs/android/essentials/get-started-kotlin

apollo {
  packageName.set("com.example")
}

Yes, it is possible to create one if required, but that's not the default configuration. Do I need to set a package name and then create the path?

@jeremymailen
Copy link
Owner

jeremymailen commented Jul 20, 2021

I'm not an apollo user. I'm just noting in their docs you can change the package. I don't know their rationale for choosing the root package as default.

Although Kotlinter wasn't designed specifically to support or not support apollo, I'm guessing any tool which generates source code will allow you to choose the output package because you'd need to be able to do that to prevent conflicts or control package visibility.

@RdeWilde
Copy link

RdeWilde commented Jul 22, 2021

So from what I understand, the exclude is not matching the full path (as in the debug output /build/generated/etc..), but just the last part?

As an example, lint errors are here: /Users/Robert/projects/core/common/build/generated/sqldelight/code/PeopleInSpaceDatabase/com/surrus/peopleinspace/db/*.kt

This does not work/exclude the file(s):

tasks {
    "lintKotlinCommonMain"(org.jmailen.gradle.kotlinter.tasks.LintTask::class) {
        exclude("**/excluded/**")
    }
}

But this does:

tasks {
    "lintKotlinCommonMain"(org.jmailen.gradle.kotlinter.tasks.LintTask::class) {
        exclude("/com/surrus/peopleinspace/db/**")
    }
}

Can I somehow still match on the 'generated'-part?
I think it is cleaner.

joreilly/PeopleInSpace#66

@jeremymailen
Copy link
Owner

You are correct @RdeWilde, the way SourceTask works is matching the package part of the path. I intend to clarify the documentation.
We would need to extend SourceTask and add another parameter to choose root trees to exclude as well.

It would be nice, but I wonder if we'll need it? It seems like any code generation plugin will allow you to specify a unique output package. Wouldn't you want a unique package anyway to keep your generated source separate in namespace from your hand written code?

@RdeWilde
Copy link

That could be true. But basically I'd like to just exclude anything from the generated-path, no matter what package.

If it is too much hassle, this can also work. Suggestion not requirement :-)

@jeremymailen
Copy link
Owner

Yes, will add it as an enhancement request. The Gradle Quality plugin has a similar extra param excludeSources
http://xvik.github.io/gradle-quality-plugin/4.6.0/guide/exclusion/

@jeremymailen
Copy link
Owner

Closing for now and will take note of the enhancement request.

@joshmsamuels
Copy link
Author

Just catching up on this. Thanks @jeremymailen ! I got the exclude working now.

+1 to the enhancement discussed above, it would have been a more intuitive solution to discover and is better "documentation" that it is generated code being ignored.

@jeremymailen
Copy link
Owner

Cool, noted. Glad you're able to find a solution for the meantime.

@ghost
Copy link

ghost commented May 23, 2022

Just catching up on this. Thanks @jeremymailen ! I got the exclude working now.

+1 to the enhancement discussed above, it would have been a more intuitive solution to discover and is better "documentation" that it is generated code being ignored.

Could you explain how you make it work?
Im facing the same issue, Im using a code generator plugin for my Graphql API (DGS codegen from netflix) and everything in goes into the /build/generated path outside the main project, and I cant make it work to ignore it, with ktlint gradle it works like a charm doing this:

ktlint {
    filter {
        exclude { element ->
            element.file.path.contains("generated/")
        }
    }
}

But with this plugin it doesnt work at all

We need a standard way to fix this problem...This issue must be open.

EDIT: Found a solution

tasks.formatKotlinMain {
    exclude { it.file.path.contains("generated/")}
}

tasks.lintKotlinMain {
    exclude { it.file.path.contains("generated/")}
}

@raquezha
Copy link

raquezha commented Jul 5, 2024

Just catching up on this. Thanks @jeremymailen ! I got the exclude working now.
+1 to the enhancement discussed above, it would have been a more intuitive solution to discover and is better "documentation" that it is generated code being ignored.

Could you explain how you make it work? Im facing the same issue, Im using a code generator plugin for my Graphql API (DGS codegen from netflix) and everything in goes into the /build/generated path outside the main project, and I cant make it work to ignore it, with ktlint gradle it works like a charm doing this:

ktlint {
    filter {
        exclude { element ->
            element.file.path.contains("generated/")
        }
    }
}

But with this plugin it doesnt work at all

We need a standard way to fix this problem...This issue must be open.

EDIT: Found a solution

tasks.formatKotlinMain {
    exclude { it.file.path.contains("generated/")}
}

tasks.lintKotlinMain {
    exclude { it.file.path.contains("generated/")}
}

Thanks this solves my problem!

raquezha pushed a commit to raquezha/nuecagram that referenced this issue Jul 5, 2024
- Updated lint to use `lintKotlinMain` instead of `lintKotlin`

- Fix generated file being included in kotlinter. jeremymailen/kotlinter-gradle#208

- Update kotlinter from 4.3.0 to 4.4.0
@TrueFiskibility
Copy link

Even more DRY:

import org.jmailen.gradle.kotlinter.tasks.ConfigurableKtLintTask

withType<ConfigurableKtLintTask> {
    exclude { it.file.path.contains("generated/") }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants