Skip to main content

ChangelogBuilder

The ChangelogBuilder class transforms raw commit data into structured changelog objects.

Constructor

ChangelogBuilder(
    summarizer: Optional[BaseSummarizer] = None,
    section_order: Optional[Sequence[str]] = None,
    include_scopes: bool = True,
    dedupe_prs: bool = True
)

Parameters

summarizer
BaseSummarizer
Optional AI summarizer for enhancing commit descriptions.
from helixcommit.summarizer import PromptEngineeredSummarizer

summarizer = PromptEngineeredSummarizer(api_key="sk-...", model="gpt-4o-mini")
builder = ChangelogBuilder(summarizer=summarizer)
Pass None to disable AI summarization.
section_order
List[str]
Custom ordering for changelog sections.
from helixcommit.grouper import DEFAULT_ORDER

# Use default order
builder = ChangelogBuilder(section_order=DEFAULT_ORDER)

# Custom order
custom_order = [
    "breaking",
    "features",
    "fixes",
    "docs"
]
builder = ChangelogBuilder(section_order=custom_order)
Default order:
  1. Breaking Changes
  2. Features
  3. Bug Fixes
  4. Performance
  5. Documentation
  6. Refactoring
  7. Tests
  8. Build
  9. CI/CD
  10. Chores
  11. Style
include_scopes
bool
default:"true"
Whether to include commit scopes in output.
# With scopes: "**api**: Add authentication"
builder = ChangelogBuilder(include_scopes=True)

# Without scopes: "Add authentication"
builder = ChangelogBuilder(include_scopes=False)
dedupe_prs
bool
default:"true"
Whether to deduplicate pull requests across commits.
# Deduplicate PRs (recommended)
builder = ChangelogBuilder(dedupe_prs=True)

# Show all PR references
builder = ChangelogBuilder(dedupe_prs=False)

build() method

Generate a structured changelog from commits.
changelog = builder.build(
    version: Optional[str],
    release_date: datetime,
    commits: Sequence[CommitInfo],
    commit_prs: Optional[Dict[str, List[PullRequestInfo]]] = None,
    pr_index: Optional[Dict[int, PullRequestInfo]] = None,
    stream_handler: Optional[Callable[[str, str, bool], None]] = None,
) -> Changelog

Parameters

version
str
Version number for the release (e.g., “v2.0.0”).
changelog = builder.build(version="v2.0.0", ...)
release_date
datetime
required
Date and time of the release.
from datetime import datetime, timezone

changelog = builder.build(
    release_date=datetime.now(timezone.utc),
    ...
)
commits
List[CommitInfo]
required
List of commits to include in the changelog.
from helixcommit.git_client import GitRepository, CommitRange

repo = GitRepository(Path("."))
commits = list(repo.iter_commits(CommitRange(since="v1.0.0", until="v2.0.0")))

changelog = builder.build(commits=commits, ...)
commit_prs
Dict[str, List[PullRequestInfo]]
Mapping of commit SHAs to associated pull requests.
# Populated by GitHub client
commit_prs = {
    "abc123": [pr_info_1],
    "def456": [pr_info_2]
}

changelog = builder.build(commit_prs=commit_prs, ...)
pr_index
Dict[int, PullRequestInfo]
Mapping of PR numbers to PR information.
# Populated by GitHub client
pr_index = {
    123: pr_info_1,
    456: pr_info_2
}

changelog = builder.build(pr_index=pr_index, ...)
stream_handler
Callable[[str, str, bool], None]
Optional handler to receive incremental streaming chunks from an AI summarizer. The handler is called as handler(identifier, chunk, final) where identifier is the summary id, chunk is a piece of text, and final is a boolean set to True on the last chunk. When provided, summarization will stream chunks to the handler; final summaries are still returned in the resulting Changelog object.

Returns

Changelog
Changelog
Structured changelog object containing:
  • version: Optional[str] - Version number
  • release_date: datetime - Release date
  • sections: List[ChangelogSection] - Organized sections
  • metadata: Dict[str, Any] - Additional metadata
changelog = builder.build(...)

print(f"Version: {changelog.version}")
print(f"Release date: {changelog.release_date}")
print(f"Sections: {len(changelog.sections)}")

for section in changelog.sections:
    print(f"  {section.title}: {len(section.items)} items")

Complete example

from datetime import datetime
from pathlib import Path
from helixcommit.changelog import ChangelogBuilder
from helixcommit.formatters.markdown import render_markdown
from helixcommit.git_client import CommitRange, GitRepository
from helixcommit.github_client import GitHubClient, GitHubSettings

# Initialize repository
repo = GitRepository(Path("."))

# Get commits
commit_range = CommitRange(since="v1.0.0", until="v2.0.0")
commits = list(repo.iter_commits(commit_range))

# Optional: Enrich with GitHub data
pr_index = {}
commit_prs = {}
slug = repo.get_github_slug()

if slug:
    settings = GitHubSettings(owner=slug[0], repo=slug[1], token="ghp_...")
    client = GitHubClient(settings)
    
    try:
        for commit in commits:
            if commit.pr_number:
                pr = client.get_pull_request(commit.pr_number)
                if pr:
                    pr_index[commit.pr_number] = pr
    finally:
        client.close()

# Build changelog
builder = ChangelogBuilder(
    include_scopes=True,
    dedupe_prs=True
)

changelog = builder.build(
    version="v2.0.0",
    release_date=datetime.now(),
    commits=commits,
    commit_prs=commit_prs,
    pr_index=pr_index
)

# Render output
markdown = render_markdown(changelog)
print(markdown)

# Access structured data
for section in changelog.sections:
    print(f"\n{section.title}")
    for item in section.items:
        print(f"  - {item.description}")

Changelog data model

Changelog

@dataclass
class Changelog:
    version: Optional[str]
    release_date: datetime
    sections: List[ChangelogSection]
    metadata: Dict[str, Any]

ChangelogSection

@dataclass
class ChangelogSection:
    title: str
    items: List[ChangelogItem]
    order: int

ChangelogItem

@dataclass
class ChangelogItem:
    description: str
    commit_sha: str
    commit_type: str
    scope: Optional[str]
    breaking: bool
    pr_numbers: List[int]

Next steps

Git client

Learn about fetching commits

Formatters

Render changelogs in different formats

Python API

Complete API reference

Examples

See practical usage examples