How to Mock a semantic-release Changelog in Python

This Python code simulates a semantic-release changelog generator, grouping commits by type and formatting them into a markdown changelog.

Medium Python 3.9+ Aug 9, 2026 Modern tooling 15 views 0 copies

Python code

42 lines
Python 3.9+
import json
from datetime import datetime


class SemanticReleaseChangelog:
    def __init__(self, version, commits):
        self.version = version
        self.commits = commits
        self.release_date = datetime.now().isoformat()

    def generate_changelog(self):
        grouped = {}
        for commit in self.commits:
            type_name = commit["type"]
            if type_name not in grouped:
                grouped[type_name] = []
            grouped[type_name].append(commit["message"])

        sections = []
        for type_name, messages in grouped.items():
            section = f"### {type_name.capitalize()}\n"
            section += "\n".join(f"- {msg}" for msg in messages)
            sections.append(section)

        changelog = (
            f"## v{self.version} ({self.release_date[:10]})\n\n"
            + "\n\n".join(sections)
            + "\n"
        )
        return changelog


if __name__ == "__main__":
    mock_commits = [
        {"type": "feat", "message": "add new API endpoint"},
        {"type": "fix", "message": "resolve memory leak"},
        {"type": "feat", "message": "implement dark mode"},
        {"type": "docs", "message": "update readme"},
    ]
    cl = SemanticReleaseChangelog("1.4.0", mock_commits)
    output = cl.generate_changelog()
    print(output)

Output

stdout
## v1.4.0 (2025-04-06)

### Feat
- add new API endpoint
- implement dark mode

### Fix
- resolve memory leak

### Docs
- update readme

How it works

The SemanticReleaseChangelog class takes a version string and a list of commit dictionaries. The generate_changelog method groups commits by their type key, capitalizes the type name as a section header, and lists each message as a bullet point. The final markdown string includes the version and the release date (first 10 characters of the ISO timestamp). This simulates the output of a real semantic-release changelog tool using only the standard library.

Common mistakes

  • Assuming commits always have a 'type' key, causing KeyError
  • Forgetting to handle empty commit lists, resulting in missing sections
  • Misformatting markdown headers with wrong number of '#' characters
  • Not sorting commits by type in a deterministic order

Variations

  1. Sort the grouped commit types alphabetically for consistent output
  2. Use a dictionary with default lists via `collections.defaultdict` for cleaner grouping

Real-world use cases

  • Generating release notes locally before committing to a CI pipeline that uses semantic-release.
  • Testing changelog formatting logic without a real Git history during development.
  • Creating a markdown summary for internal release documentation from structured commit data.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Modern tooling

Related tutorials and quizzes for this topic.