Examples

Using the cmdline

Save to file

By adding --output-file and --entry-id we can write the output to a markdown file.

Command

$ sgc save --start-ref HEAD~3 --end-ref HEAD --var header_text 0.0.1 --output-file CHANGELOG.md --entry-id 0.0.1

Outputs to CHANGELOG.md

[//]: # (SamsGenerateChangelog-0.0.1)
 # 0.0.1

 ## Sam Martin's Files


 ### Added

 - tests/fixtures/custom_template.j2 - 2020-09-02 11:26:13
 - tests/test_cmdline_arguments.py - 2020-09-02 11:26:13

 ### Modified

 - samsgeneratechangelog/__init__.py - 2020-09-02 11:26:13
 - samsgeneratechangelog/__main__.py - 2020-09-02 11:26:13
 - samsgeneratechangelog/config.py - 2020-09-02 11:26:13
 - samsgeneratechangelog/generatechangelog.py - 2020-09-02 11:26:13
 - tests/test_default_templates.py - 2020-09-02 11:26:13
 [//]: # (SamsGenerateChangelog-0.0.1)

You can see that this adds the Markdown comment syntax with a delimiter at the beginning and end of the changelog entry. This is invisible once rendered and ensures that running the same command repeatedly will replace the changelog entry rather than keep prepending it repeatedly.

Note

Note the repetition of 0.0.1 as the --var header_text and the --entry-id. The entry ID is used as a delimiter to uniquely identify an entry in the file.

Included templates

You can specify an alternative template (you can see a full list of templates in the samsgeneratechangelog/templates/ folder in the GitHub repo).

Command

sgc print --start-ref HEAD~3 --end-ref HEAD --var header_text 0.0.1 --template-name author_by_change_type

Outputs

# 0.0.1

## Sam Martin's Files


### Added

- tests/fixtures/custom_template.j2 - 2020-09-02 11:26:13
- tests/test_cmdline_arguments.py - 2020-09-02 11:26:13

### Modified

- docs/Makefile - 2020-09-02 10:00:21
- docs/source/class-reference.rst - 2020-09-02 10:00:21
- samsgeneratechangelog/__init__.py - 2020-09-02 11:26:13
- samsgeneratechangelog/__main__.py - 2020-09-02 11:26:13
- samsgeneratechangelog/config.py - 2020-09-02 11:26:13
- samsgeneratechangelog/generatechangelog.py - 2020-09-02 11:26:13
- samsgeneratechangelog/githelper.py - 2020-09-02 10:00:21
- tests/test_default_templates.py - 2020-09-02 11:26:13

By passing the template name author_by_change_type we can see tests/test_default_templates.py only appears once per change type, showing the commit time of the latest commit for that change type.

Custom templates & attributes

Using Jinja2 you can create your own custom templates and (optionally) use your own custom attributes.

Custom attributes are values returned from a regex matching group applied to a commit parameter.

In this example we’re going to match a Jira ID at the beginning of the commit message using the following JSON:

{
    "jira_id": {
        "derived_from": "message",
        "pattern": "^\\w+-\\d+"
    }
}

This will provide us a custom attribute jira_id pulled from the commit message using the ^\\w+-\\d+ pattern which will be accessible on each file_commit object inside the Jinja2 template.

We will group our commits by that custom attribute, then subgroup them by change type. Finally we will identify the last_commit for each file in that change type and print the author and commit date for it.

Note

Note how we escaped the regex character classes in the pattern JSON with an extra slash so ^\w+-\d+ became ^\\w+-\\d+. Without this we will get a JSON parsing error.

Commits for HEAD~9 to HEAD~8

ac77514 JIRA-1234 - Cleaned up unused methods
2f4dbc5 JIRA-1234 - Added additional templates

Contents of jira_id_by_change_type.j2

# {{header_text}}
{%- for jira_id, jira_id_files in file_commits | groupby('jira_id') | sort(attribute='grouper')  %}

## {{jira_id | default('No Jira ID in commit', true)}}
{%- for change_type, change_type_files in jira_id_files | groupby('friendly_change_type') | sort(attribute='grouper') %}

### {{change_type}}
{% for file_path, file_path_files in change_type_files | groupby('file_path')  | sort(attribute='grouper')   %}
{%- with %}
{%- set last_commit = file_path_files | sort(attribute='committed_date') | last %}
- {{file_path}} - {{last_commit.author.name}} - {{last_commit.committed_date}}
{%- endwith %}
{%- endfor %}
{%- endfor %}
{%- endfor %}

Command

sgc print --start-ref HEAD~9 --end-ref HEAD~8 --var header_text 0.0.1 --custom-attribute '{"jira_id": {"derived_from": "message", "pattern": "^\\w+-\\d+"}}' --template-file jira_id_by_change_type.j2

Outputs

# 0.0.1

## JIRA-1234

### Added

- samsgeneratechangelog/templates/author.j2 - Sam Martin - 2020-09-01 17:08:02
- samsgeneratechangelog/templates/author_single_file_entry.j2 - Sam Martin - 2020-09-01 17:08:02
- samsgeneratechangelog/templates/change_type.j2 - Sam Martin - 2020-09-01 17:08:02
- tests/fixtures/author_single_file_entry_template.md - Sam Martin - 2020-09-01 17:08:02
- tests/fixtures/author_template.md - Sam Martin - 2020-09-01 17:08:02
- tests/fixtures/change_type_template.md - Sam Martin - 2020-09-01 17:08:02

### Deleted

- samsgeneratechangelog/templates/default.j2 - Sam Martin - 2020-09-01 17:08:02
- tests/fixtures/basic_result.md - Sam Martin - 2020-09-01 17:08:02

### Modified

- samsgeneratechangelog/config.py - Sam Martin - 2020-09-01 17:08:02
- samsgeneratechangelog/generatechangelog.py - Sam Martin - 2020-09-01 17:08:02
- samsgeneratechangelog/githelper.py - Sam Martin - 2020-09-01 17:08:02
- tests/test_generatechangelog.py - Sam Martin - 2020-09-01 17:08:02

Custom template variables

All the templates bundled with Sam’s Generate Changelog allow header text to be specified using --var header_text <value>. But what if you want to add, say, a CR number to that?

Command

$ sgc print --start-ref 0.0.4 --end-ref 1.0.0 --var header_text 0.0.1 --var change_number CR-1234 --template-file test.j2

Contents of template_variables_example.j2

This template will output a list of commits, with our header_text followed by our change_number in the H1.

# {{header_text}} - {{change_number}}

{%for sha, file_commit in file_commits | groupby('hexsha') | sort(attribute='list.0.committed_date') | reverse -%}
- {{file_commit[0].hexsha_short}} - {{file_commit[0].committed_date}} - {{file_commit[0].message.split('\n')[0]}}
{%endfor%}

Outputs

# 0.0.1 - CR-1234

- 9ec90ba - 2020-09-04 11:14:05 - Fix yaml
- e3734ed - 2020-09-04 11:01:11 - Standardised docstrings with pydocstyle
- fb785a1 - 2020-09-03 15:46:59 - Merge pull request #9 from Sam-Martin/bugfix/typo{%endfor%}

Template Examples

Sam’s Generate Changelog uses Jinja2 templates to create the changelog. The following variables are passed into the Template().

  • start_ref

  • end_ref

  • file_commits

  • any variables passed in to GenerateChangelog via template_variables or the cmdline via --var

The first two are mandatory arguments when running sgc from the cmdline or instantiating GenerateChangelog from within a Python script.

The third one file_commits however is where the power of SamsGenerateChangelog resides.

The file_commits template variable

The file_commits variable in each template contains a list of FileCommit objects. This object makes it easy for you to group your changes by author_date, author, file_path, friendly_change_type, and more importantly, custom attributes.

At its most simple, you can loop over all file commits and just print out the detail about it.

{%- for file_commit in file_commits %}
- {{file_commit.file_path}} - {{file_commit.hexsha_short}} - {{file_commit.author.name}} {{file_commit.author.email}} - {{file_commit.committed_date}} - {{file_commit.friendly_change_type}}
{%- endfor %}

This will output something like the following:

- samsgeneratechangelog/templates/author.j2 - 2f4dbc5 - Sam Martin here@there.com - 2020-09-01 17:08:02 - Added
- samsgeneratechangelog/templates/author_single_file_entry.j2 - 2f4dbc5 - Sam Martin here@there.com - 2020-09-01 17:08:02 - Added
- samsgeneratechangelog/templates/change_type.j2 - 2f4dbc5 - Sam Martin here@there.com - 2020-09-01 17:08:02 - Added

This shows some of the attributes that are available on the file_commits objects, but the real power of this objects comes from how easy it is to group!

Grouping file_commits

With Jinja2’s groupby functionality we can group these file commits any way we like.

{%- for author_name, author_file_commits in file_commits | groupby('author.name') | sort(attribute='grouper') %}

## {{author_name}}

{%- for file_commit in author_file_commits  | sort(attribute='file_path')  %}
- {{file_commit.file_path}} - {{file_commit.hexsha_short}} - {{file_commit.author.name}} {{file_commit.author.email}} - {{file_commit.committed_date}} - {{file_commit.friendly_change_type}}
{%- endfor %}
{%- endfor %}

Two important things to note:

  1. We’re grouping by author.name indicating the attribute author in the FileCommit has its own attribute name

  2. We’re sorting by attribute='grouper'. The grouper attribute is the same as author_name at the beginning the for loop

This will output something like:

## Sam Martin
- samsgeneratechangelog/config.py - 2f4dbc5 - Sam Martin here@there.com - 2020-09-01 17:08:02 - Modified
- samsgeneratechangelog/generatechangelog.py - 2f4dbc5 - Sam Martin here@there.com - 2020-09-01 17:08:02 - Modified
- samsgeneratechangelog/githelper.py - 2f4dbc5 - Sam Martin here@there.com - 2020-09-01 17:08:02 - Modified

Custom Attributes Examples

With custom attributes you can for example group together:

  • Commits by Jira ID in the message

  • All Terraform files

  • All files by root folder

Argument structure

Whether supplying your custom attributes via the cmdline arguments or when instantiating GenerateChangelog you need to supply a structure as follows:

{
    "attribute_name": {
        "derived_from": "commit_attribute",
        "pattern": "regex pattern"
    }
}

e.g.

{
    "jira_id": {
        "derived_from": "message",
        "pattern": "^\w+-\d+"
    }
}

Usage

In the example above, the FileCommit objects (accessible in the template via the file_commits variable) will be given a new attribute called jira_id. This attribute will be produced by applying the pattern ^\\w+-\\d+ against the commit object’s message attribute.

The pattern ^\\w+-\\d+ will take a commit message like:

JIRA-1234 - Added additional templates

and return

JIRA-1234

Meaning that in your template you can do something like:

{%- for file_commit in file_commits %}
- {{file_commit.jira_id}} - {{file_commit.file_path}} - {{file_commit.hexsha_short}}
{%- endfor %}

and it will render as

- JIRA-1234 - samsgeneratechangelog/templates/change_type.j2 - 2f4dbc5

Using config files

By default SamsGenerateChangelog will look for a yaml config file named .sgc in the current working directory. You can use all named arguments you would supply to the cmdline as key names in the config file.

Example .sgc with custom attributes

output-file: CHANGELOG.md
template-name: jira_id_all_commits
custom-attributes: |
    {
        "jira_id": {
            "derived_from": "message",
            "pattern": "^\\w+-\\d+"
        }
    }

Note

Note the | character after custom-attributes:, this indicates a multi-line string (a JSON string specifically) that will be passed to the argument --custom-attributes as a single line string.