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

Add task class for KtlintCheck #90

Merged
merged 20 commits into from
May 14, 2018

Conversation

wolfs
Copy link
Contributor

@wolfs wolfs commented Apr 26, 2018

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 a Map 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.

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() {
Copy link
Contributor

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

Copy link
Contributor Author

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?

Copy link
Owner

@JLLeitschuh JLLeitschuh Apr 27, 2018

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.

Copy link
Contributor Author

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 includes/excludes?

Copy link
Contributor

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)
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah right, fair enough

Copy link
Owner

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

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
})
Copy link
Owner

Choose a reason for hiding this comment

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

Weird formatting here.

Copy link
Contributor Author

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 })
Copy link
Owner

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.

Copy link
Contributor Author

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()
Copy link
Owner

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Owner

Choose a reason for hiding this comment

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

They are still here.

Copy link
Contributor Author

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.

Copy link
Owner

@JLLeitschuh JLLeitschuh left a 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.

@wolfs
Copy link
Contributor Author

wolfs commented May 1, 2018

@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?

@JLLeitschuh
Copy link
Owner

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.

@JLLeitschuh
Copy link
Owner

How are the requirements regarding support for older Gradle/ktlint versions?

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.
@Tapchicoma
Copy link
Collaborator

How are the requirements regarding support for older Gradle/KtLint versions?

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?

This change doesn't seem to be an API breaking change so I'm fine with a minor version bump on this one.

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.

@Tapchicoma
Copy link
Collaborator

Tapchicoma commented May 3, 2018

@wolfs I see that KtLint mininal version is 0.11.1 that introduced multiple reporters - it is ok. As for Gradle 4.7 - it is questionable - people not updating Gradle wrapper so fast, so better to support older versions. Ideally starting 4.0.

project.javaexec {
it.classpath = classpath
it.main = "com.github.shyiko.ktlint.Main"
it.args(sourceDirectories.map { "${it.path}/**/*.kt" })
Copy link
Owner

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.

Copy link
Contributor Author

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?

Copy link
Collaborator

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

Copy link
Contributor

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 :)

@wolfs
Copy link
Contributor Author

wolfs commented May 5, 2018

@Tapchicoma The PR is now compatible with Gradle 4.3. Being compatible with Gradle 4.0 is somewhat hard, since the methods/types for Propertys changed between Gradle 4.2 and Gradle 4.3.
Would Gradle 4.3 be OK?

@Tapchicoma
Copy link
Collaborator

@wolfs yes, Gradle 4.3 should be fine 👍

@JLLeitschuh
Copy link
Owner

@wolfs Are getting close to having this PR ready to be merged?

@wolfs
Copy link
Contributor Author

wolfs commented May 8, 2018

@JLLeitschuh From my side, this is good to merge. What about your comment #90 (comment) ? Are you fine with the use of the Provider API for now/

@JLLeitschuh
Copy link
Owner

I'm fine using the Provider API for now, yes. Still not a huge fan.

Can you resolve the comment and we can merge this in? Please make a note of your changes in the changelog.

@uzzu uzzu mentioned this pull request May 10, 2018
@wolfs
Copy link
Contributor Author

wolfs commented May 11, 2018

@JLLeitschuh Comment resolved (now **/kts files are checked, too) and updated changelog.

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
Copy link
Owner

Choose a reason for hiding this comment

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

Should be: "anymore"

Copy link
Contributor Author

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)
Copy link
Owner

Choose a reason for hiding this comment

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

👍

@JLLeitschuh
Copy link
Owner

@wolfs I just want to make sure that the feature added by this PR didn't get dropped in all the changes you made:
#89

@wolfs
Copy link
Contributor Author

wolfs commented May 11, 2018

@JLLeitschuh Good catch. I re-added the ruleSets feature.

Copy link
Owner

@JLLeitschuh JLLeitschuh left a 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" } })
Copy link
Owner

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?

Copy link
Contributor Author

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.

Copy link
Owner

Choose a reason for hiding this comment

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

Totally fair.

Copy link
Collaborator

@Tapchicoma Tapchicoma left a 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() {
Copy link
Collaborator

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 😱

Copy link
Contributor Author

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?

Copy link
Owner

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 ->
Copy link
Collaborator

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

Copy link
Contributor Author

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 {
Copy link
Collaborator

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

Copy link
Contributor Author

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
Copy link
Collaborator

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

Copy link
Contributor Author

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
Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@Tapchicoma Tapchicoma merged commit 788963c into JLLeitschuh:master May 14, 2018
@Tapchicoma
Copy link
Collaborator

@wolfs thanks for implementing this changes!

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

Successfully merging this pull request may close these issues.

None yet

4 participants