Create a changelog automatically

If you provide source code, may it be as an application or as an open source tool, you might want to ship a changelog with it. Using git and gruntjs, makes it easy to create such a changelog fast and automatically.

We don't want to care about the creation of a changelog by our own. We better invest that time to develop our tools. Because of that, we need a simple bashscript, which does the work for us. Thanks to git, such a script is written easily.

Getting the last changes

To get the last changes on my code, I use:

git log

As you can see, the output is pretty extensive. We do not need so many details. So we'll limit the output a bit, by shrinking the format:

git log --format="  * %s"

Now the output is just the message with a * as prefix:

* switched to grunt

Limit the output even more

Our changelog should only include the most important commit messages, not every commit is interessesting enough to make its way into our changelog. So, at first, we'll get rid of the merge messages:

git log --format="  * %s" --no-merges

Now we just want to see really relevant commits. To do so, we need a syntax for our commit messages. Some tools like Stash or GitHub come with such a predefined syntax. You can point to issues or stories by using hashtags, like so:

ISSUE-123 #resolve nasty IE Bug
STORY-456 #close do those fancy css-transitions

Of course eventually you can define the syntax. But it is important every collaborator knows and uses it. So, now we know our syntax we can use it to limit the output even more:

git log --format="  * %s" --no-merges --grep=#resolve --grep=#close

This way we'll only see commit messages including one of the tags. You can, of course, define more or less tags, if you want to.

Limit the time period

Okay, we do have our output as we want to, only the most important messages will be shown. But there still is way too much output, right? We also want to limit the period of time:

git log --since="2 Weeks" --format="  * %s" --no-merges --grep=#resolve --grep=#close

Now we'll get the most important commit messages of the last two weeks. Good, isn't it? But not good enough. We do not want a fixed period. What we need, are all changes since the last creation of our changelog.

For that, we need to know when we created the changelog the last time. You could also use release-tags as an idicator, if you're working with those. We'll use the date of the changelog file. We'll start creating an empty one:

touch changelog.txt

Now we can read the modification date of the file and format it the way we need, to get it work with git log:

ls -l changelog.txt | awk '{print $6,  $7}'
> 16 Sep

The date output can vary a bit according to the system you use, but in most cases, you'll be fine with that.

Getting the authors

What would our changelog be without the authors of the code? I'll be honest, I didn't find a solution I like a hundert percent, yet. I use the following for now:

git log --format='-- %aN' | sort -u 

This way we get all the names and remove doublicates.

Getting the version number

Now let's have some fun. We also want a version number to be part of our changelog. I use the version number set in my package.json, which I use with grunt:

  "name": "Mein Beispiel",
  "version": "1.2.3",

So, somehow we need to read that version number. I use a function I found here. I modified it a bit, so I only get the values not the keys as output.

Combining everything

So we limited our commits to a certain subset and we can determine the date of our last changelog-creation, so we can use that date as starting point.

Now we'll bundle all that in a shellscript:


function jsonval {
    temp=`echo $json | sed 's/\\\\\//\//g' | sed 's/[{}]//g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | sed 's/\"\:\"/\|/g' | sed 's/[\,]/ /g' | sed 's/\"//g' | grep -w $prop | cut -d":" -f2| sed -e 's/^ *//g' -e 's/ *$//g'`
    echo ${temp##*|}

lastDate=`ls -l changelog.txt | awk '{print $6,  $7}'`
json=`cat package.json`

echo "MyCoolTool ($appversion) UNRELEASED; urgency=low\n" > changelog.txt
git log --since="$lastDate" --format="  * %s" --no-merges --grep=#resolve --grep=#close >> changelog.txt
echo "\n" >> changelog.txt
git log --format='-- %aN' | sort -u  >> changelog.txt

If you want to, you can modifiy the script for your needs. But I think it's a good foundation and creates a nice, usable changelog. You can run that script with a git hook or in a build job, so you'll get a fresh new changelog all the time.

You can find the script in my repository on GitHub.

blog comments powered by Disqus