Spotless on Android

Alessandro Mautone
The Startup
Published in
3 min readAug 31, 2020
Image of programming code

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)

--

--

Alessandro Mautone
The Startup

Android Lead Engineer @Canyon 🤖 🇻🇪🇮🇹 Paraglider, Runner, Kayaker.