How We Have Automated Release Notes Generation

Semyon Kirekov
Level Up Coding
Published in
11 min readSep 12, 2021

--

This article has been written originally in the Russian language. You can check out the source by this link.

Hello there! My name is Semyon. I’m a Java developer and Java Team Lead in the MTS Digital company of the Big Data department. In this article, I want to talk about Release Notes. What are Release Notes? Why you shouldn’t write them manually? How you can automate Release Notes generation? Today I’m answering these questions. Also, I’m showing the real example of the Release Notes automation in our project.

And what is this?

Release Notes describe the latest product’s increment. New bug fixes, features, and so on. It is valuable not only for software engineers but for managers as well. Because they also want to be aware of the development progress. If you have ever presented the current product state on a weekly demo, then you know that it’s tough to keep in mind all the tasks that have been done lately.

So, how to make Release Notes? The most obvious approach is to do it manually.

Manual Approach

This way provides a significant advantage. It requires neither additional technical knowledge nor any CI/CD processes changes to implement. We just need to hire a tech writer and delegate the job for them. Profit! But there are some caveats.

  1. Tech writer is not the one who fully understands the product. So, they will not be able to concretize the new product updates by themselves. There has to be a developer who can deliver this information. That means that the job is being done twice. Firstly, the developer explains the latest product updates to the tech writer. And then the tech writer explains it to everyone else.
  2. The process is tedious. There are a lot of circumstances that can impact the speed of the manual Release Notes writing. How do you describe the tasks in the management system? What’s the process of incoming changes contribution? Do you have any tech docs? What is the product architecture? Is it self-explained or vague?
  3. There is a high probability to make a mistake. You could forget about an important bug fix. On the contrary, you could mention something that is not released yet.

As you can see, it is not reasonable to write Release Notes manually. So, we need to automate the process, right? It is. But there are also issues to be solved.

  1. How to track the changes?
  2. If we set some contributing rules that can help to point the changes, how we can guarantee that no one breaks any of them?
  3. What if we support multiple versions of our product? How to automate the process uniformly?

What is a “change”?

You can measure the project updates in several ways. There are small steps and big steps approach. The small one is described by the commit in the repository. While the large one is by the task in the management system. It can be Jira, Trello, GitHub/GitLab tickets, etc.

I would call these strategies technical-oriented and business-oriented. By the way, one does not exclude the other. You can apply them simultaneously. And each of them has pros and cons.

Technical-Oriented Release Notes

Let’s start with an easier option. Suppose that we use the classic Git Flow branching model. Nightly builds deploy every day from the develop branch. While each merge to the master branch creates a new release. And we need Release Notes for that.

It is easy to find all the commits from the new release.

git rev-list $PREV_HASH..HEAD

$PREV_HASH is the last commit of the previous release. When we get commit hashes, we can also retrieve the corresponding commit messages. Then just put the collected information into the e-mail and send it to the subscribers. Besides, lots of CI systems can generate a similar changelog automatically.

It all sounds tempting. But there are pitfalls.

  1. Developers often don’t pay attention to writing meaningful commit messages. So, you could end up having a scroll of fix, add, delete, remove, etc.
  2. If you do automate the Release Notes in that way, it may also contain Git server log messages (Merge branch x to y, Merge pull request z to t)
  3. There are plenty of teams that squash commits on each Pull Request merge. This approach is unapplicable with the described Release Notes generation strategy. Because you shall lose the majority of the release information.

However, that’s not the complete list of potential problems. The thing is that commits themselves are not valuable to the business. Even if all of your commits have a detailed and clarifying message, this won’t be needed by Product Owners in most cases. Because it’s difficult to split the list of ungrouped commits into concrete units of work.

There is an option to store “business logs” in CHANGELOG.md. But keeping the file in the relevant state is also manual work. There is no automation. Anyway, it has a benefit. CHANGELOG.md is stored in the repository as the rest of the code. So, it can be checked on the code-review stage before merging.

Business-Oriented Release Notes

If you put the tasks’ summary and description to the Release Notes, that would be much better.

Product Owner.

Well, let’s try.

The only information that we can get while creating a new release is the list of commits. It means that we need to connect commits and tasks from the management system between each other. The solution is rather straightforward. Each commit message should contain the task ID. Then it’s easy to parse them and retrieve the required task information via REST API.

Picture 1. The base schema of the Release Notes automation process

This approach helps us to combine both code changes and particular business requirements. Besides, commits’ metainformation (hashes, messages) can be put into e-mail as additional technical references.

Well, it all sounds optimistic. But there is a problem. How can we know that developers are going to write the commit messages in the way we have declared? That’s a good question. We can make a long CONTRIBUTING.md with a list of rules and hope that everyone will follow them.

It would be nice if we automated the checks that prevent programmers from contributing something inappropriate. Thankfully, the tool exists.

There is also another caveat. How can we know that the tasks are described precisely and firmly in the management system? Actually, it’s a problem. Sometimes developers discuss a task in messengers or during a meeting. Then one just put a short summary without any context. Sadly there is no silver bullet to deal with such cases. The only way is to integrate the culture. As a manager, you have to deliver the importance of declaring the tasks properly. For example, if you submit a vague description on Friday evening there is a probability that you won’t remember what you need to do on Monday morning.

Git Hooks

When someone mentions “Git hooks” there are a lot of people thinking about webhooks. It can be Pull Requests triggers, comments notifications, approves watchers, and so on. But Git also supports local hooks that listen to the events in the repository on your machine. For example, you can check a commit execution attempt. That’s what the commit-msg hook does. Now that sound’s interesting.

By default, all hooks should be placed in the .git/hooks directory. You need to create a file with the required name (in our case, commit-msg) to make the hook start working. For instance, here is a simple Python hook that checks a task ID presence in a commit message.

Python commit-msg hook

The first command-line argument points to the .git/COMMIT_EDITMSG file. It contains the message itself. We can easily validate it according to the Regular Expression by reading the file.

Though there are nuances that should you should be aware of.

The first nuance. Git hooks are not versioned because the .git directory is not indexed. It means that we can’t just push newly added hooks to the repository and apply them to all contributors automatically.

But there is a solution. For example, the hooks can be stored in a separate directory that is indexed by Git. Then a developer needs to create a symlink between the custom directory and the .git/hooks one. It’s even better to write a script that does these steps programmatically.

The second nuance. It’s difficult to make hooks compatible with different operating systems. If you are on Linux and the Bash hook is working perfectly on your machine, then another developer on Windows or MacOS might face issues. That’s why hooks are usually written in high-level programming languages. On the contrary, it requires all contributors to install the particular language on their machines (even the version might be crucial). Unnecessary dependencies lead to extra problems.

Fortunately, lots of package managers and build tools provide plugins and libraries to implement cross-platform Git hooks easily. My personal fave is the Husky npm package. To create a custom Git hook you just need to write a few configuration files. Then you can put the hooks update command in the “preinstall” script of package.json. Now all the hooks are updated on each npm install command execution.

Besides, the pre-commit package is a good standalone solution too.

Semantic Release

The problem of software versioning becomes major when we come across the automation of the Release Notes generation. We could define the list of contribution rules. For instance, you can increase the version’s number depending on a branch name or commit message content. Or you can take a look at solutions on the market. Perhaps one may fit your project.

Semantic Release is the npm package that fully automates the process of deployment and release’s version increment.

The library follows the underlined concepts.

  1. There is one main branch in the repository (e.g., master branch). The other ones are short-lived.
  2. New Pull Request defines the new release.
  3. The initial product version is 1.0.0.

Semantic Release is tuned for Angular Commit Messages guideline by default. Though it can be overridden which may help to overcome the problem of the commit messaging culture inception that I described earlier.

Each time a new Pull Request got merged to the master branch Semantic Release scans the commits from the last release tag to the current repository state. The fix increases the patch part. The feat increases the minor one. And the ! symbol increases the major part of the version (you can override this behavior, if you need to).

The previous version is 1.0.1 
feat: …
feat: …
fix: …
feat: …
The new one is 1.1.0
The previous version is 2.0.3
build: ...
refactor: …
fix: …
The new one is 2.0.4
The previous version is 12.12.4
docs: …
feat!: …
fix: …
The new one is 13.0.0

The library creates the new tag after the successful release execution. The tag description contains the formatted documentation parsed from the received commits.

Here is an example of the Release Notes from the eslint-plugin-unicorn repository.

Picture 2. The example of the Release Notes generated by Semantic Release

I’d like to mention that Semantic Release is not closed within the Javascript/Typescript environment. It provides a flexible configuration that helps us to integrate the library with many other build tools and languages. Besides, there are some ready-to-use solutions. For example, Maven and Gradle plugins.

As you notice, Semantic Release suggests the Technical-Oriented Release Notes generation strategy. In my opinion, it fits perfectly with libraries and frameworks development (especially open-source ones). Though it’s a controversial solution for enterprise projects.

Firstly, Semantic Release is not a good option for maintaining multiple versions simultaneously. Well, this feature is supported. But I think that the final result is not worth it because of the too complex configuration and the need to apply tricky contribution rules.

Secondly, releases are usually bound to milestones and stories. These artifacts are submitted according to business requirements and not the commit message format that you’re using.

And finally, launching a release process on each Pull Request merge is an overengineering in some cases.

How We Have Automated Release Notes Generation

Now we’ve come close to the major topic of the article. How we have implemented the Release Notes generation in our company. The technical stack consists of GitLab, Jenkins, Jira, and SonarQube. Picture 3 describes the process's key points.

Picture 3. The process of automatic Release Notes generation after the deploy stage

A developer pushes the commits to the feature branch (docs, refactoring, bugfix, etc.). Then they create a new Pull Request. If all checks are passed (including code-review), the changes are transfered to the develop branch. Once a day the develop branch is being deployed on the dev environment (nightly builds).

Right after the deployment end, the received commits are parsed to retrieve the Jira tasks that were closed in the current release.

[MTS-2312] - PUT /rest/safe/rule/{ruleId} is accessed only by admin
...
[MTS-2326] - Add sort by 'stage' field

In this case, we are getting the list of MTS-2312 and MTS-2326 tasks.

And now we can request the tasks summary and description via JIRA REST API.

GET /rest/api/2/issue/{issueIdOrKey}?fields=summary,description&expand=renderedFields

You should pay attention to expand=renderedFields parameter. A task’s information is returned formatted in JIRA markup by default. Those texts are hard to read and understand in the e-mail. The parameter puts the same fields rendered in HTML which is much easier to represent prettily.

Then we mark the touched JIRA tasks with deployments’ environment labels. dev goes for the dev environment and staging for the staging one.

PUT /rest/api/2/issue/{issueIdOrKey}{ "update": { "labels": [ { "add": "staging" } ] } }

In the end, the combined information is put into e-mails and sent to the subscribers.

The significant advantage of this approach is that it can be easily expanded. For example, if we need to maintain multiple versions in production, then there is no problem cloning the process for each release branch.

As a result, we have implemented an automated mailing system that informs the subscribers about the tasks completed in the last release. More than that, the process requires no major shifts in the coding process. Developers just need to put the task ID in each commit message they write. Anyway, if you want to make this work, you have to integrate the commit messaging culture in your team. You need to explain the essence of the coding rules to the programmers. Why is it so important and how it can increase the quality of the product tremendously. Because the Release Notes are also part of the final result.

I guess that’s all I wanted to tell you about the Release Notes generation. Please, share the stories in the comment section. It will be great if you tell us how does the process work in your company. Thanks for reading!

--

--

Java Dev and Team Lead. Passionate about clean code, tea, pastila, and smooth jazz/blues. semyon@kirekov.com