Skip to content

Templates

The changelog is generated with over-ridable Jinja templates. You don’t have to override all the templates, simply the ones you want to.

You can configure where generate-changelog looks for custom templates.

The core of the changelog is the commit. The rest is just a grouping of the commits in a desired method.

base.md.jinja

The base template is rendered when generating the changelog from scratch. Incremental generations will only use the heading and versions templates.

base.md.jinja
{% include "heading.md.jinja" %}

{% include "versions.md.jinja" %}

{% include "footer.md.jinja" %}

heading.md.jinja

The heading template is rendered for the title of the changelog.

heading.md.jinja
# Changelog

versions.md.jinja

versions.md.jinja
{% for version in versions -%}
{% include "version_heading.md.jinja" %}

{% for grp_commit in version.grouped_commits -%}
    {% if loop.previtem is defined %}
        {% set heading_level = diff_index(loop.previtem.grouping, grp_commit.grouping) %}
    {% else %}
        {% set heading_level = 0 %}
    {%- endif %}
    {% for level in range(heading_level, group_depth) -%}
        {% include "section_heading.md.jinja" %}
    {% endfor %}

    {% for commit in grp_commit.commits %}
        {% include "commit.md.jinja" %}
    {% endfor %}
{%- endfor %}
{%- endfor %}

To understand how this template works, understanding how the commits are processed and grouped will help.

The commits are enriched with metadata and sorted by the version and grouping values. In this table you can see the commit version and the values of the group_by configuration, sorted.

version committer, metadata.category Commit
1.0.1 Alice, Changes commit8
1.0.1 Alice, New commit2
1.0.1 Alice, New commit5
1.0.1 Bob, Changes commit7
1.0.1 Bob, Fixes commit10
1.0.1 Bob, New commit1
1.0.1 Bob, New commit4
1.0.1 Charly, Changes commit6
1.0.1 Charly, Fixes commit9
1.0.1 Charly, New commit3

This is consolidated into the context that looks something like this (See the VersionContext for better information):

simplified_version_context = {
    "label": "1.0.1",
    "grouped_commits": {
        ("Alice", "Changes"): ["commit8"],
        ("Alice", "New"): ["commit2", "commit5"],
        ("Bob", "Changes"): ["commit7"],
        ("Bob", "Fixes"): ["commit10"],
        ("Bob", "New"): ["commit1", "commit4"],
        ("Charly", "Changes"): ["commit6"],
        ("Charly", "Fixes"): ["commit9"],
        ("Charly", "New"): ["commit3"],
    }
}

The template looks for changes in the grouping values and renders section headings for the new value. The result is something like:

## 1.0.1 (2022-01-01)

### Alice

#### Changes

- commit8

#### New

- commit2

- commit5

...

version_heading.md.jinja

The version heading template is rendered for the title of each tagged version.

version_heading.md.jinja
## {{ version.label }} ({{ version.date_time.strftime("%Y-%m-%d") }})

section_heading.md.jinja

The section heading template is rendered for the value changes in the grouping. The heading level is adjusted based on the level parameter set in the version_heading.md.jinja template.

section_heading.md.jinja
###{{ "#" * level }} {{ grp_commit.grouping[level] or "Other" }}

commit.md.jinja

This template is rendered for each commit.

commit.md.jinja
- {{ commit.summary }}
  {{ commit.body|indent(2, first=True) }}
  {% for key, val in commit.metadata["trailers"].items() %}
  {% if key not in valid_author_tokens %}
  **{{ key }}:** {{ val|join(", ") }}

  {% endif %}
{% endfor %}

footer.md.jinja

The default footer templaate is blank. You can override this to add your own information.

footer.md.jinja