Enforce Commit Message Standards and Generate Changelogs via Git

In past projects my release note strategy has been a combination of custom scripts (to pull the changesets between releases) and good old fashioned elbow grease to manually create the notes. I was curious to know ways about the ways to achieve the same in git and learning about the techniques used in popular open source projects.

In order to automatically generate a changelog the repository requires consistent commits - and I found that there are three steps that can be done to achieve this:

  1. Enforcing commit message rules.
  2. Install and setup tools that help generate commit messages that are compliant.
  3. Generate the changelog for the project based on the commits.

Prerequisites

  • Node.js - instructions on installing node can be found here.
  • A package.json file for your project. One can be generated by navigating to the root folder of the project, run the npm init command and follow the instructions

Enforcing Commit Message Rules

The enforcing of the rules are done using husky and validate-commit-msg packages. Husky makes it very easy to tap into the commit event and execute custom validation scripts and uses git hooks to do this. validate-commit-msg implements the validation scheme - conventional commits - that we would be used when the commit occurs.

The conventional commits specification site summarizes its advantages very well:

  • Automatically generating CHANGELOGs.
  • Automatically determining a semantic version bump (based on the types of commits landed).
  • Communicating the nature of changes to teammates, the public, and other stakeholders.
  • Triggering build and publish processes.
  • Making it easier for people to contribute to your projects, by allowing them to explore a more structured commit history.
  1. First, navigate to the root of your project folder and install husky.

    npm install husky --save-dev
    
  2. Next, install the validate-commit-msg package.

    npm install --save-dev validate-commit-msg
    
  3. Update the package.json scripts node to let husky know that we want to use the validate-commit-msg validations with husky.

    "scripts": {
        "commitmsg": "validate-commit-msg"
    },
    

From now on any commits done would be validated against the standard.

Scaffold and Commit

Now that we have the validation in place, let make life easier by installing some tools that help us adhere to the rules.

  1. Install Commitizen by running the following command.

    npm install -g commitizen 
    
  2. Install the cz-conventional-changelog adapter as part of the project - this is the conventional commits guide lines. Read more about this standard here and here.

    commitizen init cz-conventional-changelog --save-dev --save-exact
    

    Verify that commitizen has been conifgured automatically in the package.json:

      "config": {
        "commitizen": {
          "path": "./node_modules/cz-conventional-changelog"
        }
      }
    

Now that we have commitizen and its adapter installed, now its time to do some commits. The following command now replaces the usual git commit command:

git cz

It would guide you interactively to create the best commit message based on the conventional-changelog adapter. Find a recap of the message format here.

Commitizen

Generate Changelog

Now to generate the changelog. In my non-node.js based projects, I usually rely on the build process to bump the version number of the release, but node.js projects and tools appear to like the explicit versioning in the package.json file and the same checked into source control. I can work with that.

The following is the recommended workflow for generating the changelog:

  1. Make changes
  2. Commit those changes
  3. Make sure Travis turns green
  4. Bump version in package.json
  5. conventionalChangelog
  6. Commit package.json and CHANGELOG.md files
  7. Tag
  8. Push

Let's adapt these steps to work with our own workflow:

  1. I am going to install the command line version of conventional-changelog which is conventional-changelog-cli.

    npm install -g conventional-changelog-cli
    
  2. Since this is the first time I am running it, I want the changelog to take all historical commits into consideration. I am going to run the following command:

    conventional-changelog -p angular -i CHANGELOG.md -s -r 0
    
    • -p being the preset being used. I am using angular in this case and uses this kind . More detailed explanation of the format can be found here.

    • -i the input file.

    • -s indicates that the input file and the output file are the same.
    • -r 0 How many releases to be generated from the latest. If 0, the whole changelog will be regenerated and the outfile will be overwritten Default: 1

    The full list of options available can be found by executing conventional-changelog --help

  3. Continue creating commits using the git cz command.

  4. If you have a CI build setup, make sure that its successful. Then update the version number in the package.json to a higher one.
  5. Now lets update the changelog using the following command:

    conventional-changelog -p angular -i CHANGELOG.md -s 
    
  6. Confirm that the changelog has been updated with the new significant features.

  7. Commit the changes back into git.

Final Thoughts

These same steps can be applied to almost any project type including .NET. So I am pretty excited to test this out in the Dynamics CRM/365 projects. I also found out that visual studio 2017 plays nice with git hooks.

Client Side

It is important to remember that Git Hooks are client site and that it can be overridden:

... Client side hooks can often be bypassed, either by using low-level “plumbing” commands instead of the high-level “porcelain” commands, and often by passing the –no-verify option to the command. For example, git commit –no-verify will not run the pre-commit hook. ...

On an open-source project, maybe the maintainer could possibly eye-ball the pull request and ensure that it is valid or squash and provide a different message?

Versioning

Since the package.json would be driving the version number, in my .NET/Dynamics CRM projects, I can possibly implement a PowerShell script that would bumps the version of the CRM solution based on the package.json instead of the build.

References

comments powered by Disqus