I am trying to use ktlint on my android project.
Currently I am using these gradle plugins:
org.jlleitschuh.gradle.ktlint
org.jlleitschuh.gradle.ktlint-idea
I can check the code using a manual gradle task, where the warnings will be displayed by the terminal.
Is it possible to achive something like eslint in javascript? Example:
Perhaps the following advice does not directly solve your requirement. But, what about making the auto format process part of the build process? I mean, your code will be auto formatted and then checked according to the ktlint rules and you only will be worried about to run the build command (i.e. ./gradlew clean build) before committing your code. This is how I have done that:
First of all, I am using Gradle 6.3 and I have implemented the version 9.1.2 of org.jlleitschuh.gradle.ktlint plugin.
Once the plugin has been imported to the project, some tasks are added as the plugin's documentation describes:
This plugin adds two maintasks to every source set: ktlint[source set name]SourceSetCheck and ktlint[source set name]SourceSetFormat
Usually the added tasks are:
ktlintMainSourceSetCheck and ktlintMainSourceSetFormat for src/kotlin/main source set
ktlintTestSourceSetCheck and ktlintTestSourceSetFormat for src/kotlin/test source set
In order to make ktlintMainSourceSetFormat and ktlintTestSourceSetFormat part of the build process, you should add the following gradle action inside subprojects { } section:
For kotlin-based gradle scripts (build.gradle.kts):
afterEvaluate {
tasks["ktlintMainSourceSetCheck"].dependsOn(tasks["ktlintMainSourceSetFormat"])
tasks["ktlintTestSourceSetCheck"].dependsOn(tasks["ktlintTestSourceSetFormat"])
}
For groovy-based gradle scripts (build.gradle):
afterEvaluate {
tasks.getByName('ktlintMainSourceSetCheck').dependsOn(tasks.getByName('ktlintMainSourceSetFormat'))
tasks.getByName('ktlintTestSourceSetCheck').dependsOn(tasks.getByName('ktlintTestSourceSetFormat'))
}
This makes the "format" tasks mentioned above run before the "check" tasks after the build process of the current sub project has succeeded. These "check" tasks are the ones that display formatting errors in the console whenever the build is run, but making them children of the "format" tasks will force the build process to format the code before checking it so that no formatting errors will show up in the console.
Additionally, you can also apply code checks and formats to build script files (build.gradle(.kts)) by adding the following code inside allprojects { } section:
afterEvaluate {
tasks["ktlintKotlinScriptCheck"].dependsOn(tasks["ktlintKotlinScriptFormat"])
}
For Git support:
If you want to add the auto formatting feature at pre-commit stage, you can use these tasks: addKtlintCheckGitPreCommitHook and addKtlintFormatGitPreCommitHook as explained here
For IntelliJ IDEA support:
If you want to apply the ktlint rules to your current project, just execute the following gradle command once you have imported the org.jlleitschuh.gradle.ktlint-idea plugin: ./gradlew ktlintApplyToIdea and this will replace the codeStyles file inside .idea/ folder as described here
Finally, here is an example of a build.gradle.kts where all the mentioned above is applied.
You will not get an error message like in eslint but using following method you won't need to deal with ktlint styling issues manually. Is not it much better than manually fixing things up?
Install ktlint commandline tools as described here.
Set IntelliJ IDEA's code styles to align with ktlint's code styles as described here.
So when you make a commit using IntelliJ IDEA's commit window (CTRL + K or Command + K) and you have reformat code before commit enabled then your commit will be made with correct code styles.
Try to install plugin Ktlint (unofficial) and follow setup instructions.
Go to Preferences > Tools > ktlint and make sure Enabled ktlint checkbox is selected.
In case of android project also select Android mode check box.
Related
I would like to write a custom gradle plugin that manipulates either com.android.build.gradle.AppExtension or com.android.build.gradle.LibraryExtension. The basic form of the plugin is:
class AndroidLibrary : Plugin<Project> {
override fun apply(project: Project) {
var lib: LibraryExtension = project.extensions.getByName("android") as LibraryExtension
lib.minSdkVersion = "26"
}
}
The problem is that the class LibraryExtension cannot be resolved. That class is contained in "com.android.tools.build:gradle:7.1.2". Note, there is no problem accessing either of these classes in a gradle.build.kts script file. I just can't access either of those classes from within a custom plugin like seen above. I've tried adding a dependency to com.android.tools.build.gradle 7.1.2 in the build script, but that doesn't work. I also tried adding it as a buildscript dependency, and that didn't help either. I also got the
com.android.tools.build:gradle jar file and added it as a dependency, but that too didn't work.
It seems to me to be reasonable to expect a custom plugin of being able to manipulate the android build settings but I just can't find a way to resolve either LibraryExtension or AppExtension from within the custom plugin project.
If someone knows what I need to do to resolve those two classes, that would be greatly appreciated. I'm currently under the impression, that this is an architectural limitation of with android's gradle plugin and that I really can't access the "android" build section using LibraryExtension or AppExtension from a custom plugin and dsl. If that is the case, that too would be useful to know.
check this answer for your question, it is gonna solve your problem.
Initially I was building the plugin using IDEA. I could build the project by using a "gradlew build" command. I noticed that I would get the following message whenever I tried to sync the project:
This version of the Android Support plugin for IntelliJ IDEA (or Android Studio) cannot open this project, please retry with version 2020.1.1 or newer
I had been ignoring that issue since I could successfully build the project using gradle commands. Here's a link the explains what the message means: https://intellij-support.jetbrains.com/hc/en-us/community/posts/4405168877202-This-version-of-the-Android-Support-plugin-for-IntelliJ-IDEA-or-Android-Studio-cannot-open-this-project-please-retry-with-version-2020-3-1-or-newer-
One of the suggestions to this problem was to build the project in Android Studio instead of waiting for IDEA to incorporate later android build. I did that and that indeed fixed that issue. The additional side effect was that I could now build the plugin. I was able to add dependencies for both gradleApi and to com.android.build.gradle and was able to resolve AppExtension of LibraryExtension. I had added the same dependencies I when I was using IDEA IDE. I had been customarily building my custom gradle plugin using IDEA. This was my first custom gradle plugin that I was going to manipulate an "android" build configuration.
Trying to find the bare minimum source and build files needed to build an android project in Android Studio. I want to publish to github and avoid uploading generated build files or binaries.
I do have a Android.gitignore from but I still see some more files getting pushed into the repo which may not be necessary. I understand the few obvious ones but about others, do I need them and if so kindly explain the usage.
So the question, do I need the following and if so then a short description of why?
root
build.gradle
gradle.properties
gradlew
gradlew.bat
settings.gradle
/app
app/build.gradle
app/proguard-rules.pro
/gradle (tested, android can re-download/generate following it if not present)
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
This question can have two different answers based on the meaning of the word needed.
First (the real one)
Assuming your project has currently those files, if your question is:
Should I commit these files on my Git repo?
The answer is yes, all of them, and I'm explaining why:
root
build.gradle -> defines the configuration for all the Gradle modules in your project (e.g. use the same remote repositories to download some Gradle plugins)
gradle.properties -> defines some optional flags used when building the app (e.g. enabling the incremental KAPT, enabling the AndroidX jetifier)
gradlew -> invokes the Gradle wrapper (which can be found under gradle/wrapper/gradle-wrapper.jar) to avoid to have Gradle installed when building your project on Darwin/Linux
gradlew.bat -> the same of gradlew but for Windows
settings.gradle -> defines the list of modules which are part of your project
app/
app/build.gradle -> defines the configuration only for your app module (e.g. its build types, its flavors, its version code and version name)
app/proguard-rules.pro -> defines the obfuscation rules when your app enables the minification
gradle/
gradle/wrapper/gradle-wrapper.jar -> provides the same version of the Gradle wrapper jar for all the users. This is very important because it forces the users to use the same version of the Gradle wrapper to compile your app
gradle/wrapper/gradle-wrapper.properties -> same as above, it defines which version of the Gradle wrapper you need
Second (the useless one)
Now, I'll give you the answer to the question:
Are these files strictly needed to compile an Android project?
To successfully compile an Android project with Gradle you just need the root build.gradle if you have Gradle installed on your machine or build.gradle + the wrapper files if you have not Gradle installed on your machine.
Theoretically you can:
put your application code in the root project and that avoids you one build.gradle and settings.gradle
disable the obfuscation and that avoids you proguard-rules.pro
remove gradle.properties and set the properties via command line
Obviously this solution won't happen on a real project scenario.
I need to run some tasks that occur after an Android project's assemble* task finishes. In particular, these tasks need to know what was the output directory for all the compiled classes for a particular build variant. How do I retrieve the output directory for an assembleFlavor1Debug task?
My current workaround is something like this (although this workaround presents problems of its own, like not being able to find the assemble tasks even though it's been placed after the android configuration block):
android.buildTypes.all { theBuildType ->
android.productFlavors.all { theFlavor ->
String capitalizedType = ... //Type name with first letter capitalized
String capitalizedFlavor = ... //Flavor name with first letter capitalized
...
project.tasks["assemble${capitalizedType}${capitalizedFlavor}"].configure {
doLast {
project.ext.variantOutput = "build/intermediates/classes/${theFlavor.name}/${theBuildType.name}"
}
}
}
}
EDIT #1: I was able to fix my workaround. The major issue was that the Android assemble* tasks (assembleProdDebug, assembleProdRelease, etc.) were not yet created on the project, even though configuration was occurring after the Android configuration block. I was able to get the additional configuration on the assemble* tasks done by enclosing the entire code snippet above into a gradle.taskGraph.whenReady {...} block, but this did mean I lose out on the ability to continue configuring the dependency graph. Fortunately, not being to configure dependencies in my particular case was not a major loss; all I needed was the ability to record the last assembled build type and product flavor.
I'd also like to note that this behavior is with version 1.0.0 of the Android Gradle plugin. Although I have not checked, the absence of these Android tasks might not occur on newer versions of this plugin.
EDIT #2: So I've also tried version 1.3.0 of the Android Gradle plugin. I'd also like to note that this is the LIBRARY Android plugin, and not the application plugin (I suspect these missing assemble* tasks are not generated during project configuration for the application plugin as well, however).
You might want to try instead of wrapping the entire thing with gradle.taskGraph.whenReady try using afterEvaluate closure. The tasks should exist after the project is evaluated.
This means your closure would run at the end of the configuration phase and before the execution phase. At this time all tasks would have to be registered.
afterEvaluate { project ->
// do work on `Project` object just like normal
project.android.buildTypes.all { theBuildType ->
...
}
}
ref: https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#afterEvaluate(groovy.lang.Closure)
So ultimately I'm trying to separate my integration tests from the unit tests in an Android Studio project. I've found a few resources on the subject:
http://selimober.com/blog/2014/01/24/separate-unit-and-integration-tests-using-gradle/
https://blog.safaribooksonline.com/2013/08/22/gradle-test-organization/
Separating integration tests from unit tests in Android Studio
All these seem to indicate that the way to go is to create a new sourceSet for the integration tests, and then to create a new test task which builds and runs the tests in that source set. I can't get past the first step of creating a source set which is recognized by Android Studio.
Here's what I have within app/build.gradle, which builds without errors, but does not result in an integrationTest source root I can add classes to:
android{
...
sourceSets{
integrationTest {
java.srcDir('src/integrationTest/java')
}
}
}
My questions are:
Where precisely do I have to add the sourceSets block? In build.gradle? in app/build.gradle? In app/build.gradle inside the android block?
Once I've added my source set in he right place using the correct syntax, is this sufficient for Android Studio to detect and present it in the UI along side the main and test sources, or are there additional steps?
edit:
I've attempted to follow the instructions in marius' answer, but integrationTest isn't showing up in my build variants. Here's what I'm seeing:
This is enough:
android{
...
productFlavors{
integrationTest {
}
}
}
Regarding your 1st question: The productFlavors block should be in your app/build.gradle, inside android block.
Regarding your 2nd question: Once you add this to your build.gradle file, you also need to create your folders /src/integrationTest and /src/integrationTest/java . Once that is done, sync your gradle files and choose your new Build Variant from the Build Variant window, in order for the IDE to detect it as the active source folder.
Managing Android's dependencies with Gradle is done in a weird way. They have to be downloaded differently into a local repo. This is a pain when setting up CI build as there are multiple nodes this could run on. As such I'm using the sdk-manager-plugin to have the Android dependencies downloaded at build time. There seems to be an old bug that I'm experiencing with the sdk-manager-plugin though in that it will download the dependencies at build time, but they won't be available on that command.
The next time the command is run everything works fine (as everything is already downloaded), but I need to find a way to ignore the build failure of the first gradle command so that everything is downloaded and good to go for the second. I realize this is hacky, but I'm done messing with this.
Ideally something like this would work:
./gradlew clean --ignoreBuildFailures
./gradlew distributeCIBuild
The closest thing I could find in the Gradle documentation is --quite but that doesn't look like it'd work.
Any creative solutions welcome.
The flag to use is --continue.
From the documentation:
Continues task execution after a task failure.
add this in the build.gradle file :
tasks.withType(JavaCompile) {
options.failOnError(false)
}
You can use ignoreExitValue
task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
ignoreExitValue = true
}