Spotless on Android
Setting up spotless
is quite easy, let’s take a look at what we did at Collect by WeTransfer to have a setup that is as much ready-to-go as possible.
🔍 What is spotless?
Is a code formatter: we can define rules and it will apply them every time we execute it.
It’s pretty useful in automating fixes for pretty simple (and common) formatting mistakes as in spaces, newlines, removing unnecessary imports, etc.
You can find more info at https://github.com/diffplug/spotless
🛠 Setup
The setup is pretty simple (you can follow the instructions in the GitHub repo as well): add the necessary dependencies, install ktlint on your machine and define a spotless
block in your project level build.gradle
file and inside that block define whatever rules you need for your codebase.
Something like this:
If we want to do something nicer, we can create a dedicated gradle
file and apply it to the project once. It is as simple as creating a spotless.gradle
file (you can give it any name), adding it to the root directory of our project and then, again, in the project level build.gradle
file we add
apply from: "$project.rootDir/spotless.gradle"
so our project level build.gradle
file will look something like
Now we have spotless
configured on our machine and we can run it, to that simply run the command:
./gradlew spotlessApply
Note that due to this line in our configuration
ratchetFrom 'origin/develop'
it will run only on modified files (in relation to the develop
branch in our case)
Want to try how is working?
Just add a class (or modify an existing one) as follows:
run ./gradlew spotlessApply
and it should become:
⏲ Let’s make it run at the right time
When could we run spotless
? Ideally before a commit, and that’s easy to achieve thanks to Git hooks. We will be looking more specifically at the pre-commit hooks.
As stated in the documentation, we can just modify (or create)the desired file (pre-commit
in our case) under the folder .git/hooks
and make it executable.
so a simple bash script like this:
will do the job.
Wait, do we have to configure this script for each machine that will pull the project? Well… Yes.
And we have two options here: going around gently forcing our lovely colleagues to configure that script or automate this process too 🤖.
I went for the latter :)
🤖 Automate pre-commit script setup
Let’s go back to the spotless.gradle
file (or wherever you choose to define your spotless configuration) and add this task at the end of the file:
Let me explain in detail what’s going on there.
In the first two lines
def gitHooksDirectory = new File("$project.rootDir/.git/hooks/")
if (!gitHooksDirectory.exists()) gitHooksDirectory.mkdirs()
we just make sure that the necessary directories that will hold the Git hooks are in place and, if not, create them.
Then we create a new file (as said before it must be named pre-commit
) and we write our script into that file.
new File("$project.rootDir/.git/hooks", "pre-commit").text = """
#!/bin/bash
echo "Running spotless check"
./gradlew spotlessApply
if [ \$? -eq 0 ]
then
echo "Spotless check succeed"
git add .
else
echo "Spotless check failed" >&2
exit 1
fi"""
Finally, we make that file executable.
"chmod +x .git/hooks/pre-commit".execute()
And we are done! We now have a fully automated code formatting check and relative fixes applied automatically! 🚀
🗒 Notes
If Gradle raises an error during the spotless
configuration
Cannot add task ‘clean’ as a task with that name already exists
then just remove the clean task in your build.gradle
file:
task clean(type: Delete) {
delete rootProject.buildDir
}
Android Studio configuration
Make sure you have single class imports
enabled in the settings for kotlin files (and java ones if you have java in your project)