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.
Python code
42 linesimport 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
## 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
- Sort the grouped commit types alphabetically for consistent output
- 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
More from Modern tooling
- Build a Recipe Runner Mock in Python easy
- Build a Textual TUI App Skeleton in Python easy
- Configure ruff linter rules in pyproject.toml with Python easy
- Data Conversion Helper Functions in Python easy
- How to Bind and Mock structlog Context in Python medium
- How to Build a Chainable Filter Helper in Python easy
Keep learning
Related tutorials and quizzes for this topic.