Android Pro Tip: Generating your app’s changelog from Git inside build.gradle

Welcome to my Android Pro Tip’s series — where I’ll try to share the most interesting, useful & little known tips & tricks I’ve learned in my 8+ years of being a freelance Android developer.

To start with we’re going to start with one of the more boring but advantageous components of your app — the changelog.

I’ve always shipped changelog’s with my apps as they’re a nice way of keeping users updated of what’s changed in the app. Especially if it’s a bug fix they’ve been waiting for, or a feature that they might not realize has been added unless they’re explicitly informed. Hell I even built a library to reuse across all of my apps so I didn’t have to keep building the front end for it over & over again!

The annoying part of this setup however was always actually writing the changelog. Mostly because I’d forget and ship a build with an old changelog 🙈 but also because when I actually remembered I’d find it pretty tedious to go back through my commits to remember what’s changed, so I could write the damn thing.

I recently discovered a pretty nifty way to automate this process entirely using the app’s own git log.

Git -> Changelog

The benefits of this approach

  • Your changelog will always be up to date. This method builds the changelog from the last tagged commit until now. So as long as you tag your release’s appropriately — your changelog will always be up to date.
  • It requires no developer intervention whatsoever. It run’s when you build your APK so every time you commit, a new changelog item will appear in the next build.
  • It’s easily customizable to meet your needs or even ignore commits based on some specific string identified. For example, if you don’t want a specific commit listed in the changelog you could prefix it with “**” & then just ignore commit’s prefixed with that when building the changelog.

Sounds easy enough right? Let’s look at the code.

The code

git describe --tags --abbrev=0

Next you can generate a list of commits since that tag, prettified into a format we can use, using the git command: (where $lastTag is the result of the previous command)

git log $lastTag..HEAD --oneline --no-merges --pretty=format:"%s"

The good bit about this being you can run both commands in your terminal, outside of Android Studio, to see exactly what is going to be output without having to keep re-syncing your Gradle file to run the task & see the result.

Once we’ve got that all we need to do is loop each line, format it in a way we want & append it to our changelog string — easy!

We also need to make sure we escape special characters as we’ll be outptting the result of this Gradle task into a String inside our BuildConfig file. As this is a Java class we’ll need to make sure any special characters are escaped so the final string produced is a compliant Java String.

The final Gradle task will look something like this.. (with println used to output useful information into our Gradle build output for debugging purposes)

String generateChangelog() {
println "Generating changelog.."
//Get the last tag
def
lastTag = "git describe --tags --abbrev=0".execute().text.trim()
//Get all the commits since the last tag
def gitLogCmd = "git log $lastTag..HEAD --oneline --no-merges --pretty=format:\"%s\"".execute().text.trim()
//Loop each line of the commits to build your changelog
def changelog = "\""
gitLogCmd.eachLine { line ->
//Remove surrounding quotation marks generated by the git log comand
def escapedLine = line.substring(1, line.length() - 1)
//Escape backslashes
escapedLine = escapedLine.replaceAll(/(\\)/, "\\/")
//Escape quotation marks
escapedLine = escapedLine.replaceAll('"', '\\\\"')
//Add each item to the changelog as a bullet point
changelog += "• $escapedLine \\n"

}
//Close the changelog string
changelog = (changelog + "\"").trim()
//Useful log so you can see what was generated in the Gradle output
println "Changelog generated, $changelog, from $lastTag to now."
return changelog
}

Nearly done

android {
...
defaultConfig {
...
buildConfigField "String","CHANGELOG","${generateGitChangelog()}"
...
}
...
}

Et voila! You end up with a single, bullet pointed Java string, containing every change since your last release, easily accessible by calling BuildConfig.CHANGELOG. Easy.

Side note

Job done

If you have any thoughts or feedback on this approach, or know of a better way of doing this I’d love to hear what you think in the comments! Also if you have any requests for little hacks or tip’s like this you might be interested let me know & I’ll see what I can do!

Let me know what you think! 🤓

Freelance Android Developer since 2012 🎙️Host of CoffeeAndCodingPod.com 🌍 World Tourist ☕ Coffee Addict | robj.me

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store