Automation of filling Changelog via CI

In this article I will try to tell you how in my work I implemented the automatic generation of Changelog from commits and the creation of tags based on them.

Foreword

As the number of micro-services in our team grew, we began to move some common pieces of code into separate repositories (hereinafter I will call such repositories libraries), which are connected to projects through composer.

When the number of micro-services was small, the commit history was enough to track the history of changes. Over time, other teams began to use our libraries. Questions began to appear often, such as: “Tell me, what version of the library do we need to connect in order for such and such functionality to appear?”.

It became obvious that the commit history was no longer responding to requests, and a friendlier solution had to be sought. This solution was the maintenance of the Changelog file in the libraries, which at first we filled in with our hands and assigned tags with versions with our hands.

Having lived like this for some time, I had a desire to somehow automate this process. And after a while, I came across information about the changelog generators and the agreement on the rules for registering commits https://www.conventionalcommits.org/

Implementation

The generator that caught my eye was the project https://github.com/marcocesarato/php-conventional-changelog… Since our projects are also written in PHP, the generator seemed interesting and I wanted to try it out in practice.

Step 1

The first step was the introduction of a new requirement for the registration of commits within the team, so that they comply with the agreement above and the generator can work with them.

Step 2

Add a task for CI to the project (in my case, this is Gitlab CI).

generate-changelog:
    image: php:7.4-cli # у нас используется свой образ, поэтому пишу условно
    before_script:
        - git config --global user.email "$GITLAB_USER_EMAIL" # email и имя пользователя, от чьего имени будет создаваться коммит
        - git config --global user.name "$GITLAB_USER_NAME"
        - git fetch --tags -f
        - composer install --no-interaction --no-scripts
        - composer require marcocesarato/php-conventional-changelog # у нас используется свой форк с доработками    
    script:
        - bin/changelog-generator --commit --no-verify # у нас скрипты устанавливаются в папку bin
        - git push -o ci.skip --tags https://root:$ACCESS_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$CI_COMMIT_REF_NAME
    stage: changelog
    # делаем автозапуск задачи только для мастер ветки.
    # Так как мы не пушим напрямую в мастер, а используем merge request, то задача выполняется после слияния MR
    # так же запрещаем задачу, если проставляем тег и для коммитов с chore (значит, что команда уже была выполнена)
    only:
        - master
    except:
        refs:
            - tags
        variables:
            - $CI_COMMIT_MESSAGE =~ /chore/

Our team uses a feature-branch approach and requires that there is only one commit per merge request. Therefore, in our case, one commit = a new version of the library.

The idea behind the script is as follows:

  • we connect the generator to the project and run it with the necessary flags

  • then the generator:

    • determines the current (aka the last) commit and, based on the commit header, determines which version of the Semver need to assign

    • adds changes to CHANGELOG.md

    • creates a new commit with modified CHANGELOG.md. Note that in our version, only the CHANGELOG file is included in the commit.

    • assigns a tag with the resulting version to a commit

  • push the new commit back to the project repository

Step 3

In order for CI to push changes to the repository, we created a special technical user, and added a variable to the projects ACCESS_TOKEN , with that user’s access token.

Step 4

We have been working with this approach for a while. But the thought was spinning in my head what to use composer require a so-so idea and perfectionism requires a better solution.

I wanted the generator to either be present all the time in the image, or it could be downloaded and run.

For some reason, I chose the second path. To do this, I put the generator in a phar archive and uploaded it to Gitlab Packages. And the following version of the CI script turned out

generate-changelog:
    image: php:7.4-cli
    before_script:
        - git config --global user.email "$GITLAB_USER_EMAIL"
        - git config --global user.name "$GITLAB_USER_NAME"
        - git fetch --tags -f
        # скачиваем генератор из Packages
        - 'curl --header "PRIVATE-TOKEN: ${PACKAGE_TOKEN}" "${CI_API_V4_URL}/projects/615/packages/generic/changelog-generator/latest/changelog-generator.phar" --output changelog-generator.phar'
        - chown 755 changelog-generator.phar
    script:
        - php ./changelog-generator.phar --commit --no-verify
        - git push -o ci.skip --tags https://root:$ACCESS_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$CI_COMMIT_REF_NAME
    stage: changelog
    only:
        - master
    except:
        refs:
            - tags
        variables:
            - $CI_COMMIT_MESSAGE =~ /chore/

Problems

At some point, due to a change in user rights, we ended up with a situation with endless creation of pipelines and launching a task with a generator. I don’t remember the exact solution, one of the ways to solve the situation was to add sections to the script except and only

Result

I tried to outline the idea of ​​automation, since different projects may have their own characteristics.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *