Automating dependency updates in a Compose project

Jose Alcérreca
Android Developers
4 min readMar 10, 2023

--

We recommend using the latest libraries in your Android projects as they have more features and bug fixes. However, bumping versions and fixing breaking changes can be an intricate process, especially if you try to fix many at the same time. Automating this process reduces errors but there are some considerations to take into account if you use Compose.

Reduce time spent on maintenance with automation

Because maintenance can feel like a thankless task, you should try to automate as much of it as possible by:

  • Having a Continuous Integration system to ensure that the code is constantly in a healthy state.
  • Running automated tests to give your team fast feedback on how the app behaves after changes, catching regressions.
  • Automating the generation of updates, which is what this post is about.

Bumping versions generally means opening the build file where you define your dependencies or their versions and then going to either Google’s Maven repository or Maven Central to figure out which one you should use. Usually:

  • If you are using a stable version of a library, you usually bump to the latest stable (e.g. 2.5.0 to 2.6.2).
  • If you’re on an unstable track, you choose either a more recent stable version, or a more recent unstable artifact of the same version (e.g. 1.2.0-alpha05 would move to 1.2.0-beta01 or 1.2.1, but not to 1.2.2-alpha01).
  • If there’s a new major version of a library, there are probably breaking changes and you should do that update in its own PR (e.g. 1.2.5 to 2.0.1).

Android Studio provides hints with proposed library updates (and Version Catalogs support is coming in Android Studio Giraffe!) but you can also automate this process in two different ways:

For Architecture samples, we prefer not to pollute build files with plugins that developers might not use, so we went with an external service. In our particular case we’re using Renovate because Dependabot doesn’t support dependency grouping, which is crucial if you use Compose.

Automating updates with Compose dependencies

The version bumping algorithm described above is simple, but it doesn’t always work with the default setup. For example, automatic updates might fail when using Compose dependencies. The reason is that the Compose Compiler has a strict mapping to specific versions of Kotlin. You can find the table here. Typically, these two dependencies aren’t released at the same time, so there is a delay of several days between Kotlin’s new version and the corresponding Compose Compiler. This means that you can’t update Kotlin to the latest version if the Compose Compiler hasn’t been released yet.

With Renovate we group all updates in one PR using the group:all directive (see it in action in one of our configuration files). This makes maintenance even easier because we only have to approve one PR every week. However, doing this means that every time there’s a Kotlin release, our Compose project would break until the Compose compiler is released. This wouldn’t be a huge deal if it wasn’t for the fact that when your build is broken the rest of the updates will have to wait.

To fix this, you can group updates together. The idea is to separate the Kotlin updates from the other changes so that you can keep updating your other dependencies.

In Renovate, that’s done with packageRules:


"packageRules": [
{
"matchPackagePatterns": [
"androidx.compose.compiler:compiler"
],
"groupName": "kotlin"
},
{
"matchPackagePatterns": [
"org.jetbrains.kotlin.*"
],
"groupName": "kotlin"
},
{
"matchPackagePatterns": [
"com.google.devtools.ksp"
],
"groupName": "kotlin"
}
]

These rules create a group name called “kotlin” and add Kotlin itself, the Compose compiler and KSP.

With this, Renovate will generate two different PRs per branch. One for the “kotlin” group, and the other for the rest of the dependencies.

The Kotlin PR only contains updates related to Kotlin as expected:

Example PR only updating Kotlin dependencies

This means that when a new version of Kotlin is available, this PR will be created and its build will initially fail until the Compose Compiler is available. Having a failing PR for a while might not be ideal and there are feature requests that seem to tackle a similar problem, but I personally don’t mind it as a reminder that a new Kotlin version is coming.

An important feature of Renovate is that if you add a commit to one of its PRs, the bot will stop trying to update it, letting you make tweaks. The day-to-day is configured in a clever dashboard (see example) and it has a massive set of configuration options.

Renovate has been working flawlessly and we’re adding it to more Architecture repositories. However, I think that the documentation could benefit from more use-case based examples as I found myself relying a bit too much on Stackoverflow and snippets found on Github issues.

In conclusion, setting up a system to keep your dependencies fresh is a great investment. It doesn’t matter which system you use as long as it reduces the maintenance burden of your projects so you can be more productive… or go home early.

Code snippets license:

Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0

--

--

Jose Alcérreca
Android Developers

Developer Relations Engineer @ Google, working on Android