-
Notifications
You must be signed in to change notification settings - Fork 157
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
Add task class for KtlintCheck #90
Conversation
This allows declaring the outputs for the configured reports. The task class does not yet support the old report command line arguments (single report only).
import org.jlleitschuh.gradle.ktlint.reporter.KtlintReport | ||
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType | ||
|
||
open class KtlintCheck : DefaultTask() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⭕ Implementing VerificationTask
would make sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementing VerificationTask
would somewhat force me to drop the Property<Boolean>
type for ignoreFailures
. Then I would need to use convention mapping, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about SourceTask
then you'd get the filtering API for free.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main problem with SourceTask
is that I would need a way to turn the FileTree
into something ktlint understands (e.g. <baseDir>/**/*.kt
). I wouldn't know how to do this via the public API. This is why I opted for not extending SourceTask
.
I could add the individual files as command line arguments to ktlint. Would that work? Or will the command line become to long?
I am also not sure if filtering provides much extra value for the ktlint
task. Are you saying that a use case is to exclude some files from linting via include
s/exclude
s?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About SourceTask
, the extra use case of including/excluding individual files could be tackled later, as a separate PR.
About VerificationTask
, that's unfortunate but I see your point and agree @wolfs
val sources: FileTree = sourceDirectories.asFileTree.matching { it.include("**/*.kt") } | ||
|
||
@get:Input | ||
val verbose: Property<Boolean> = project.objects.property(Boolean::class.javaObjectType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌ Boolean::class.java
should be enough
There are many other instances of this below, not commented on each one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I use Boolean::class.java
I get:
Cannot get the value of a property of type boolean as the provider associated with this property returned a value of type java.lang.Boolean.
when running the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, fair enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about simplifying this to:
private fun Project.booleanObjectProperty() =
objects.property(Boolean::class.javaObjectType)
Just so we don't have this same logic repeated 5 times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
120d29c
to
ef60714
Compare
android.set(target.provider { extension.android && SemVer.parse(extension.version) >= SemVer(0, 12, 0) }) | ||
ignoreFailures.set(target.provider { extension.ignoreFailures }) | ||
outputToConsole.set(target.provider { extension.outputToConsole | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird formatting here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
this.applyReporters(target, extension, sourceSetName) | ||
classpath.setFrom(ktLintConfig) | ||
sourceDirectories.setFrom(kotlinSourceDirectories) | ||
verbose.set(target.provider { extension.verbose }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a huge fan of how you have to call set
on all of these properties. Seems so un-kotlin like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, that is the recommended usage. Do you have some better ideas?
@@ -38,6 +40,8 @@ class KtlintPluginVersionTest : AbstractPluginTest() { | |||
|
|||
@Test | |||
fun `with ktlint version less than 0_20`() { | |||
withCleanSources() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put this in a @BeforeEach
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are still here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They should be gone now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some things to fixup. On the right track though.
@JLLeitschuh Thank you for the review! I addressed/answered your comments. How are the requirements regarding support for older Gradle/ktlint versions? What do I still need to address? |
I'd feel more comfortable merging this PR after we've come to some sort of conclusion WRT the discussion here: gradle/kotlin-dsl-samples#597 I just want to make sure that we are really committing to using the best practices regarding API we are exposing. |
As I'm not currently even using this plugin myself, I'm going to defer to @Tapchicoma about this. This change doesn't seem to be an API breaking change so I'm fine with a minor version bump on this one. |
The setup method already takes care of this.
I am thinking that at some point plugin should drop support for older versions of KtLint and Gradle, to simplify code/reduce effort of supporting it. We can do it in this PR as well. @wolfs what is desired minimal supported versions of Gradle and KtLint in this PR?
Indeed it is not changing the API, but on the other hand will break update for those who is still using old Gradle wrapper/set older KtLint version in extension (I wonder if there such installations 🤔), so, IMHO, better major version bump. |
@wolfs I see that KtLint mininal version is |
project.javaexec { | ||
it.classpath = classpath | ||
it.main = "com.github.shyiko.ktlint.Main" | ||
it.args(sourceDirectories.map { "${it.path}/**/*.kt" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Include *.kts
incase someone is linting a buildSrc
project with script based plugins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do *.kts
files lint well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wolfs according to pinterest/ktlint#19 since 0.3.0
release
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making that change sounds orthogonal to this PR.
Even though it's a very interesting one :)
@Tapchicoma The PR is now compatible with Gradle 4.3. Being compatible with Gradle 4.0 is somewhat hard, since the methods/types for |
@wolfs yes, Gradle 4.3 should be fine 👍 |
@wolfs Are getting close to having this PR ready to be merged? |
@JLLeitschuh From my side, this is good to merge. What about your comment #90 (comment) ? Are you fine with the use of the |
I'm fine using the Can you resolve the comment and we can merge this in? Please make a note of your changes in the changelog. |
@JLLeitschuh Comment resolved (now |
CHANGELOG.md
Outdated
### Changed | ||
- Update Kotlin to 1.2.41 version | ||
- Update Gradle wrapper to 4.7 version | ||
### Fixed | ||
### Removed | ||
- KtLint versions prior to 0.10.0 are not supported any more |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be: "anymore"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
|
||
## [3.3.0] - 2018-4-24 | ||
### Added | ||
- Check for spaces in output path for KtLint versions earlier | ||
then 0.20.0 (#83) | ||
- Use relative for input file path sensivity (#67) | ||
- Use relative for input file path sensitivity (#67) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
4de3efc
to
7d5e27b
Compare
@JLLeitschuh Good catch. I re-added the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! @Tapchicoma Take a final pass and feel free to merge.
project.javaexec { | ||
it.classpath = classpath | ||
it.main = "com.github.shyiko.ktlint.Main" | ||
it.args(sourceDirectories.flatMap { dir -> KOTLIN_EXTENSIONS.map { extension -> "${dir.path}/**/*.$extension" } }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious why you don't just use the sources
property you already have in scope for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sources are all the Kotlin files in scope. This is possibly a big argument list. If you think Ktlink can happily cope with having all the to be checked .kt
files as separate arguments on the commandline than that would be fine. I am somewhat concerned about the length of the command line - especially on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally fair.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM, small improvements and ready to merge.
import javax.inject.Inject | ||
|
||
@CacheableTask | ||
open class KtlintCheck @Inject constructor(objectFactory: ObjectFactory) : DefaultTask() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, a lot of annotation "magic" to write a task 😱
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We love annotations ;)
Is there a less verbose way to do constructor injection in Kotlin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, this is the way to do constructor injection.
I'm actually really pleased that in Kotlin, constructor injection is actually simpler than field injection.
Because of this, it encourages developers to use Constructor injection.
throw GradleException("Ktlint versions less than 0.10.0 are not supported. Detected Ktlint version: $it.") | ||
} | ||
} | ||
ktlintVersion?.let { version -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to move into private method for readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
fun lint() { | ||
val reportsToProcess = enabledReports.values | ||
val ktlintVersion = determineKtlintVersion(classpath) | ||
ktlintVersion?.let { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to move into private method for readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
val ktlintJarRegex = "ktlint-(\\d+.*)\\.jar".toRegex() | ||
val ktlintJarName = ktlintClasspath.find { ktlintJarRegex.matches(it.name) }?.name | ||
val version = ktlintJarName?.let { | ||
val versionString = ktlintJarRegex.matchEntire(it)!!.groups[1]!!.value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to replace with:
val versionString = ktlintJarRegex.matchEntire(it)?.groups[1]?.value ?: return null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
### Changed | ||
- Update Kotlin to 1.2.41 version | ||
- Update Gradle wrapper to 4.7 version | ||
### Fixed | ||
### Removed | ||
- KtLint versions prior to 0.10.0 are not supported anymore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please also add that Gradle is supported from version 4.3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@wolfs thanks for implementing this changes! |
This PR adds an actual task class for the ktlint check task. This allows declaring outputs for configured reports.
The task class does not yet support the old report command line arguments (single report only).
Moreover, it currently works only on Gradle 4.7, since it uses
@Nested
on aMap
for declaring the outputs of the report.If the plugin maintainers think this is a good direction, then I can address the remaining problems like supporting older ktlint versions or older Gradle versions.
This PR addresses part of #85. I ended up not using source task since it does not provide any benefits in this simple case.