Automatic release generation based on commit message history with GitLab

The objective is to automatically generate a changelog based on the commits and to feed the GitLab release notes with this changelog.

Requirements

The automatic generation of the changelog will be based on the commit messages and requires the use of the standard Conventional Commits.

This standard defines a list of prefixes for your commit messages to help categorize them. Available prefixes are fix:, feat:, docs:, style:, refactor:, etc.

Once the right prefix has been chosen, just add a short description for this commit. This description will then be used in the changelog. Example: feat: automatic release note generation based on commits.

Generate the changelog with git-cliff

Now that our commit history is clean and follows the Conventional Commits convention, we will be able to generate the changelog and for that we will use git-cliff.

Introduction to git-cliff

git-cliff is a tool whose objective is to generate the changelog by taking the commits and providing the result in Markdown format. Commits are grouped according to version and type of commit (fix:, feat:, etc.).

A git-cliff Docker image allows you to run it locally with the following command from the root of your Git project:

docker run --rm -t -v $(pwd)/.git:/app/ orhunp/git-cliff

An example of result file:

# Changelog

## [unreleased]

### Features

- Automatic release note generation based on commits

## [1.0.0] - 2022-06-23

### Features

- Initial commit
- Creating a Hadoop TDP cluster on AWS

### Styling

- Update font-color
- Update profil picture

It is possible to customize the result by modifying the configuration file to translate or modify the titles associated with each of the categories.

For more information on customizing the result, please refer to the project’s README git-cliff.

Integration in a GitLab pipeline

In order to automate the generation of this changelog, we will add a job in the GitLab pipeline:

build:changelog:
  stage: build
  image:
    name: orhunp/git-cliff:latest
    entrypoint: [""]
  before_script:
    - apt update
    - apt install -y git
    - export PREVIOUS_TAG=`git describe --abbrev=0 HEAD~`
    - echo ${PREVIOUS_TAG}
  script:
    - |
      if [ -z "${PREVIOUS_TAG}" ]; then
        git-cliff -c config/cliff.toml > CHANGELOG.md
      else
        git-cliff -c config/cliff.toml -r . ${PREVIOUS_TAG}.. > CHANGELOG.md
      fi
  needs: []
  cache:
    key: ${CI_COMMIT_REF_SLUG}-CL
    policy: push
    paths:
      - CHANGELOG.md
  variables:
    GIT_STRATEGY: clone # clone entire repo instead of reusing workspace
    GIT_DEPTH: 0 # avoid shallow clone to give cliff all the info it needs

By default, the git-cliff tool generates the complete changelog. As we only want to have the changelog of the current version, we retrieve in the variable PREVIOUS_TAG the previous tag with the command git describe --abbrev=0 HEAD~. Then we just need to specify to git-cliff that we want to generate the changelog from the previous tag to the current commit.

The result file in Markdown format is then added to the pipeline cache.

Generation of the release

The last step in our pipeline once the changelog file is generated is to create the release. To achieve it, GitLab provides a dedicated image that will be perfect for our use:

deploy:release:
  stage: deploy
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  before_script: []
  script:
    - echo 'running release_job'
  needs: [
    "build:changelog",
  ]
  cache:
    key: ${CI_COMMIT_REF_SLUG}-CL
    policy: pull
    paths:
      - CHANGELOG.md
  release:
    name: '${CI_COMMIT_TAG}'
    description: 'CHANGELOG.md'
    tag_name: '${CI_COMMIT_TAG}'
    ref: '${CI_COMMIT_TAG}'
  rules:
    - if: $CI_COMMIT_TAG

The changelog file generated during the previous step is then extracted to feed the description of the release. Note that if the build:changelog job was executed at each commit pushed to the GitLab repository, we have here logically limited the execution of the deploy:release job to the presence of a tag.

Conclusion

Thanks to these two jobs, which can be added to any GitLab pipeline, it is possible to automatically create a release with the changelog of your project.

All you have to do is to take care of the commit messages to allow you to have a perfect changelog associated with the releases!