Kotlin Gradle Spotless ktlint configuration - kotlin

I currently use the following way to apply ktlint to my projects:
plugins{
id("com.diffplug.spotless") version "6.7.2"
}
allprojects {
apply(plugin = "com.diffplug.gradle.spotless")
spotless {
kotlin {
target("**/*.kt")
ktlint("0.45.2")
}
kotlinGradle {
target("*.gradle.kts", "additionalScripts/*.gradle.kts")
ktlint("0.45.2")
}
}
}
I want to tweak some on the configurations so that the linter fits with what we want in the team. for example, set a max line length to 120.
For this, I found that we can do something like:
ktlint("0.30.0").userData(mapOf("max_line_length" to "120"))
in the build.gradle.kts file. However, as we go on adding more tweaks, this becomes very difficult to manage and copy from project to project, and the spotlessApply task fails to format the code and simply raises it as an issue during the build.Is it possible to get it to auto-format in this case?
ktlint itself supports the .editorconfig file for such configurations. How do I apply that with spotless?

Three years later - but better late than never! - it works.
Starting in Spotless version 6.13.0 and ktlint versions 0.47.1 and 0.48.1 this behavior now works out of the box.
Issue where this has been tracked.
PR where this has been implemented.
Plugin release where the feature was first shipped.

Related

Why can't JUnit Platform find my cucumber tests?

I am currently running my cucumber scenarios like this with JUnit 4:
#RunWith(Cucumber::class)
#CucumberOptions(
features = ["src/features"],
tags = "not #ignored"
)
class RunCucumberTest
I am trying to get the same working on JUnit Platform, and currently have:
#Suite
#IncludeEngines("cucumber")
#SelectDirectories("src/features")
#ConfigurationParameter(key = Constants.PLUGIN_PROPERTY_NAME, value = "pretty")
#ConfigurationParameter(key = Constants.GLUE_PROPERTY_NAME, value = "garden.ephemeral.rocket")
class RunCucumberTest
I have updated the stuff on the Gradle side as well:
tasks.withType<Test> {
useJUnitPlatform {
// TODO: Not needed? Doesn't seem to work with or without.
includeEngines("cucumber")
}
jvmArgs("--add-modules=jdk.incubator.vector")
// Workaround. Gradle does not include enough information to disambiguate
// between different examples and scenarios.
// TODO: Move to cucumber.properties?
systemProperty("cucumber.junit-platform.naming-strategy", "long")
// TODO: Move to junit-platform.properties?
systemProperty("junit.jupiter.execution.parallel.enabled", "true")
}
When I run Gradle, the :test task runs, but the test report is empty.
When I try to run the test class from IDEA, I get:
> No tests found for given includes: [garden.ephemeral.rocket.RunCucumberTest](--tests filter)
How do I make this work?
Investigation so far:
I also tried moving the features into the resources and using #SelectClasspathResource("features") instead, but got the same result.
I tried cloning this project and it does run its scenarios, but everything is written in Java instead of Kotlin. Other than that, everything is mostly the same between the two. That project uses #SelectClasspathResource instead of #SelectDirectories, but I already tried that. I also tried using #SelectDirectories over in that project, and that works too.
If I breakpoint inside DiscoverySelectors.selectDirectory, it doesn't seem to stop there. Best guess is, maybe JUnit isn't even finding and running the suite? Or maybe breakpointing inside JUnit just doesn't work.
Best current idea is to convert that skeleton project to Kotlin and see if it still runs.
At a glance this doesn't look right:
useJUnitPlatform {
// TODO: Not needed? Doesn't seem to work with or without.
includeEngines("cucumber")
}
With the #Suite annotation you are using the JUnit Platform Suite engine to kick of the Cucumber engine. By setting the included engines to cucumber you exclude the suite engine from gradles discovery process.
Note that the skeleton project uses:
tasks.withType<Test> {
useJUnitPlatform()
// Work around. Gradle does not include enough information to disambiguate
// between different examples and scenarios.
systemProperty("cucumber.junit-platform.naming-strategy", "long")
}

How to optionally apply some plugins using Kotlin DSL and plugins block with gradle and android

I want to apply some plugins optionally to improve build time in development time.
I mean I have this:
app/gradle.build.kts:
plugins {
id("com.android.application")
id("com.google.firebase.crashlytics")
}
But I dont want to apply firebase crashlytics plugin all the time (and other plugins like perf monitor), but if I try to access the project inside of the plugins block I get:
plugins {
id("com.android.application")
if (!project.hasProperty("build_fast")) {
id("com.google.firebase.crashlytics")
}
}
I get:
'val Build_gradle.project: Project' can't be called in this context by implicit receiver. Use the explicit one if necessary
So my questions are:
I can access the System env variables with System.getenv("CI") but replacing those values from android studio is a little bit hacky currently to me, someone can show a way to update those variables?
How can I do it using project.hasPropperty("")?
You can't. The plugins DSL is limited in what you can and can't do. This is documented in Limitations of the plugins DSL.
To conditionally apply a plugin, you must use Project.apply(T):
plugins {
id("com.android.application")
id("com.google.firebase.crashlytics") apply false
}
The apply false is necessary because we don't want to apply the plugin, but we want the types or classes that are available from that plugin so we can programmatically apply the plugin in a type safe manner.
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsPlugin
plugins {
id("com.android.application")
id("com.google.firebase.crashlytics") apply false
}
apply<CrashlyticsPlugin>()
I can access the System env variables with System.getenv("CI") but replacing those values from android studio is a little bit hacky currently to me, someone can show a way to update those variables?
You can't update the environment (System.getenv()), it is a unmodifiable map.
How can I do it using project.hasPropperty("")
Use that as a conditional which you have done:
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsPlugin
plugins {
id("com.android.application")
id("com.google.firebase.crashlytics") apply false
}
if (!hasProperty("build_fast")) {
apply<CrashlyticsPlugin>()
}

Is #uifabric/build private package?

I would like to investigate possibility of using just-scripts in my project. So for inspiration I've took a look at its use in office-ui-react. However there is not much I can read from it's just.config.json.
const { preset, just } = require('#uifabric/build');
const { chain, task } = just;
preset();
chain('verify-api-extractor').after('build');
My question is, if all it's build, test, etc. configuration in #uifabric/build preset function? And if so, if it's a public package?
Author of just-scripts here. I realize that documentation may be a bit lacking at the moment - definitely can use help here!
just-scripts github: https://github.com/microsoft/just
documentation: https://microsoft.github.io/just/
I don't recommend taking #uifabric/build as a dependency for another project. I recommend folks to build on top of the just-scripts one:
https://github.com/microsoft/just/tree/master/packages/just-scripts/src/task-presets
These presets are exported by just-scripts, so you can use them as you wish. task() can override already defined tasks, so you can feel free to override build, test, etc.

How do I separate gradle unit tests from integration tests in the same source set?

The problem is that we are an IntelliJ shop and this issue has been a thorn in our sides. It basically means that everything has to be in ./test/ in order to work. ./it/ isn't acceptable because IntelliJ picks it up as the wrong kind of source every time you try to do anything. So.... how do I separate integration tests from unit tests so that they can be run separately in Gradle if they are in the same source set? Anyone have an example?
We use the *Test*.java and *ITCase*.java naming conventions, if that helps. Anothing thing we were thinking of is some kind of use of JUnit's #Category annotation.
P.S. Please vote for this issue. It will be a thorn in the side of any IntelliJ shop considering Gradle that has integration tests in a different directory from unit tests.
I can't speak to IntelliJ configuration, but in build.gradle, if you have:
test {
if (! project.hasProperty("ITCASE")) {
exclude "**/*ITCase*"
}
}
then the following command-line would include the integration tests:
gradle test -PITCASE=true
then and the standard would exclude them:
gradle test

gradle test phases?

Is there a way to build custom test phases in gradle?
I have a series of tests, namely
/unit
/local
/remote
which is running JUnit managed tests for a couple different purposes. I'd love to be able to run these as test phases, such as gradle test:unit, or something like that. Ideally, I could also specify a description for each test phase, so gradle tasks describes the role of each of the tests.
Is this possible? If so, how?
I tried this:
sourceSets {
unit {
java.srcDir file('src/test/groovy/local')
resources.srcDir file('src/local/resources')
}
}
dependencies {...}
task unitTest(type: Test){
testClassesDir = sourceSets.local.output.classesDir
classpath = sourceSets.local.runtimeClasspath
}
...as copied from withIntegrationTests in the provided samples, but when I run gradle unitTest, no tests run.
You just need to add three Test tasks (testUnit, testLocal, testRemote) and configure them accordingly. (Instead of introducing testUnit, you could also reuse the test task that comes with the Java plugin.) If the sources are in different source folders, it also makes sense to add additional source sets. For the details, have a look at samples/java/withIntegrationTests in the full Gradle distribution.