Automating the Android library release process with Kotlin Scripts
We have a couple of proprietary libraries and tools that our Android apps at Ellation use. Releasing them was a manual process until recently when we had some time to play around with Kotlin Scripts.
What we wanted
- Run 1 script to cover the whole release process
- The script should be fail-proof (or at least has some instructions on how to recover from errors (or at least easy to understand what has failed))
- The script should be testable
Release process
In order to create a new release of a library or a tool, the following steps should be done:
- Pull the master branch and run
./gradlew build
- Run
./gradlew uploadArchives
to publish the artifact - Create a Git tag for the released version and push it to remote
- Prepare the next version:
1. Increment the version name ingradle.properties
2. Add it to the changelog file
3. Create a branch and a commit with these changes
4. Since all ourmaster
branches are protected, create a pull request on GitHub
Kotlin Scripts
We really wanted to find a way to incorporate the Kotlin Scripts into our release process. Although we considered writing a Gradle plugin initially, it appeared to be too “heavy-weight” for the small task we had.
We use kscript which provides support for resolving dependencies and running the script from a URL.
Result
As a result, the whole release process of any library is done by running:
kscript https://raw.githubusercontent.com/crunchyroll/android-library-release-script/master/src/main/kotlin/Release.kt
All steps of the script are split up into classes which are then called from the main
function. This makes it easier to read the script and unit test different pieces in isolation (I wish, though).
Config
The CliConfig
class represents all possible arguments and options that could be passed from the command line. We used xenomachina/kotlin-argparser to parse them.
Preconditions
This class tries running different command line utilities that have to be installed for the whole script to work correctly. If any of them fail, it will abort the whole procedure.
Steps
All steps are wrapped into a nice lambda in order to print a pretty report in the end if something has failed. The steps are batched in main
and are executed when all have been added.
- Upload artifact — this is just
./gradlew uploadArchives
- Create and push release tag
- Increment version in
gradle.properties
- Update release date in the changelog
- Add new version to the changelog
- Create a commit and pull request — using the
hub
command line utility
Development mode
To make the script development process more convenient, we bootstrapped a simple Gradle project with the help of kscript.
The script itself lives in the src/main
and since we use external dependencies in the script, we would like the IDE to know about them too. This is done by adding them to the dependencies
block in the build.gradle
file as usual.
What can be improved
- End-to-end testing
The script currently doesn’t have any end-to-end tests. This is hard to achieve as there are multiple tools used (e.g Nexus repository, GitHub). - Splitting up the script
Currently, the script is one giant (300 LoC).kt
file. It would be nice to have it split up into different files. - Linting
Since this script is inside a simple Gradle project, we could add tools like ktlint and detekt.