GitRepository
Interface for working with Git repositories.
Constructor
GitRepository(path: Path, *, prefer_gitpython: bool = True)
Path to the Git repository directory.
Prefer using GitPython when available, with automatic fallback to the git CLI.
Methods
Iterate over commits in a given range.commits = repo.iter_commits(commit_range)
for commit in commits:
print(commit.subject)
Parameters:
commit_range: CommitRange - Range of commits to fetch
Returns: Iterator of CommitInfo objects
List all tags in the repository, sorted by date (newest first).tags = repo.list_tags()
latest_tag = tags[0] if tags else None
Returns: List of TagInfo objects
get_github_slug
Optional[Tuple[str, str]]
Extract GitHub owner/repo from remote URL.slug = repo.get_github_slug()
if slug:
owner, repo_name = slug
print(f"{owner}/{repo_name}")
Returns: Tuple of (owner, repo) or None
Example
from pathlib import Path
from helixcommit.git_client import GitRepository, CommitRange
# Initialize repository
repo = GitRepository(Path("."))
# Get commits
commits = list(repo.iter_commits(
CommitRange(since="v1.0.0", until="v2.0.0")
))
# List tags
tags = repo.list_tags()
for tag in tags:
print(f"{tag.name}: {tag.tagged_date}")
CommitRange
Define a range of commits to process.
Constructor
CommitRange(
since: Optional[str] = None,
until: Optional[str] = None,
include_merges: bool = True,
max_count: Optional[int] = None
)
Starting ref (tag, commit SHA, or branch). Commits after this ref are included.
Ending ref. Commits up to and including this ref are included.
Whether to include merge commits in the output.
Maximum number of commits to process.
Example
from helixcommit.git_client import CommitRange
# Between tags
range1 = CommitRange(since="v1.0.0", until="v2.0.0")
# Unreleased changes
range2 = CommitRange(since="v1.0.0", until="HEAD")
# With filtering
range3 = CommitRange(
since="v1.0.0",
until="HEAD",
include_merges=False,
max_count=100
)
ChangelogBuilder
Build structured changelogs from commits.
Constructor
ChangelogBuilder(
summarizer: Optional[BaseSummarizer] = None,
section_order: Optional[Sequence[str]] = None,
include_scopes: bool = True,
dedupe_prs: bool = True,
summary_body_limit: int = 1600,
)
AI summarizer for generating enhanced descriptions. Pass None to disable AI.
Custom order for changelog sections. Uses default order if not specified.
Whether to include commit scopes in descriptions.
Whether to deduplicate pull requests.
Methods
Build a changelog from commits.changelog = builder.build(
version="v2.0.0",
release_date=datetime.now(),
commits=commits,
commit_prs={},
pr_index={},
)
Parameters:
version: Optional[str] - Version number
release_date: datetime - Release date
commits: Sequence[CommitInfo] - List of commits
commit_prs: Dict[str, List[PullRequestInfo]] - Commit to PRs mapping
pr_index: Dict[int, PullRequestInfo] - PR number to PR info mapping
Returns: Changelog object
Example
from datetime import datetime
from helixcommit.changelog import ChangelogBuilder
# Basic usage
builder = ChangelogBuilder(include_scopes=True)
changelog = builder.build(
version="v2.0.0",
release_date=datetime.now(),
commits=commits,
commit_prs={},
pr_index={},
)
# With AI summarization
from helixcommit.summarizer import PromptEngineeredSummarizer
summarizer = PromptEngineeredSummarizer(
api_key="sk-...",
model="gpt-4o-mini",
)
builder = ChangelogBuilder(summarizer=summarizer)
changelog = builder.build(
version="v2.0.0",
release_date=datetime.now(),
commits=commits,
commit_prs={},
pr_index={},
)
Render changelogs in different formats.
Markdown
from helixcommit.formatters.markdown import render_markdown
markdown_output = render_markdown(changelog)
Path("RELEASE_NOTES.md").write_text(markdown_output)
HTML
from helixcommit.formatters.html import render_html
html_output = render_html(changelog)
Path("changelog.html").write_text(html_output)
Text
from helixcommit.formatters.text import render_text
text_output = render_text(changelog)
print(text_output)
GitHubClient
Interface with GitHub’s API.
Constructor
GitHubClient(settings: GitHubSettings)
GitHub configuration including owner, repo, and token.
Methods
get_pull_request
Optional[PullRequestInfo]
Fetch pull request by number.pr = client.get_pull_request(123)
if pr:
print(f"PR #{pr.number}: {pr.title}")
Parameters:
number: int - Pull request number
Returns: PullRequestInfo or None
find_pull_requests_by_commit
Find pull requests associated with a commit.prs = client.find_pull_requests_by_commit("abc123def")
for pr in prs:
print(f"PR #{pr.number}")
Parameters:Returns: List of PullRequestInfo
Close the GitHub client and release resources.
Example
from helixcommit.github_client import GitHubClient, GitHubSettings
# Initialize client
settings = GitHubSettings(
owner="username",
repo="repository",
token="ghp_..." # Optional
)
client = GitHubClient(settings)
try:
# Fetch PR
pr = client.get_pull_request(123)
# Find PRs by commit
prs = client.find_pull_requests_by_commit("abc123")
finally:
client.close()
PromptEngineeredSummarizer
AI-powered summarization of commits.
Constructor
PromptEngineeredSummarizer(
api_key: str,
model: str = "gpt-4o-mini",
base_url: Optional[str] = None,
cache_path: Optional[Path] = None,
domain_scope: Optional[str] = None,
expert_roles: Optional[List[str]] = None,
rag_backend: str = "simple"
)
OpenAI or OpenRouter API key.
AI model to use for summarization.
Custom API base URL (for OpenRouter: https://openrouter.ai/api/v1).
Path to cache file for storing summaries.
Domain context for the AI (e.g., “software release notes”).
Expert perspectives to consider (e.g., [“Product Manager”, “Tech Lead”]).
RAG backend: “simple” (keyword) or “chroma” (vector).
Example
from pathlib import Path
from helixcommit.summarizer import PromptEngineeredSummarizer
# OpenAI
summarizer = PromptEngineeredSummarizer(
api_key="sk-...",
model="gpt-4o-mini",
cache_path=Path(".cache/summaries.json"),
domain_scope="software release notes",
expert_roles=["Product Manager", "Tech Lead", "QA Engineer"]
)
# OpenRouter
summarizer = PromptEngineeredSummarizer(
api_key="sk-or-...",
model="meta-llama/llama-3.1-8b-instruct:free",
base_url="https://openrouter.ai/api/v1",
cache_path=Path(".cache/summaries.json")
)
# Use with ChangelogBuilder
builder = ChangelogBuilder(summarizer=summarizer)
Data models
CommitInfo
@dataclass
class CommitInfo:
sha: str
subject: str
body: str
author_name: str
author_email: str
authored_date: datetime
committed_date: datetime
is_merge: bool = False
pr_number: Optional[int] = None
labels: List[str] = field(default_factory=list)
diff: Optional[str] = None
@property
def message(self) -> str: ...
Changelog
@dataclass
class Changelog:
version: Optional[str]
date: Optional[datetime]
sections: List[ChangelogSection]
metadata: Dict[str, Any]
ChangelogSection
@dataclass
class ChangelogSection:
title: str
items: List[ChangeItem] = field(default_factory=list)
def extend(self, changes: Iterable[ChangeItem]) -> None: ...
PullRequestInfo
@dataclass
class PullRequestInfo:
number: int
title: str
url: str
author: Optional[str]
merged_at: Optional[datetime]
body: Optional[str] = None
labels: List[str] = field(default_factory=list)
assignees: List[str] = field(default_factory=list)
Complete example
from datetime import datetime
from pathlib import Path
from typing import Optional
from helixcommit.changelog import ChangelogBuilder
from helixcommit.formatters.markdown import render_markdown
from helixcommit.formatters.html import render_html
from helixcommit.git_client import CommitRange, GitRepository
from helixcommit.github_client import GitHubClient, GitHubSettings
from helixcommit.summarizer import PromptEngineeredSummarizer
def generate_release_notes(
repo_path: Path,
since: str,
until: str,
github_token: Optional[str] = None,
openai_key: Optional[str] = None
) -> str:
"""Generate comprehensive release notes."""
# Initialize repository
repo = GitRepository(repo_path)
# Get commits
commit_range = CommitRange(since=since, until=until, include_merges=False)
commits = list(repo.iter_commits(commit_range))
# GitHub enrichment
pr_index = {}
commit_prs = {}
if github_token:
slug = repo.get_github_slug()
if slug:
settings = GitHubSettings(
owner=slug[0],
repo=slug[1],
token=github_token
)
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()
# AI summarization
summarizer = None
if openai_key:
summarizer = PromptEngineeredSummarizer(
api_key=openai_key,
model="gpt-4o-mini",
cache_path=repo_path / ".cache" / "summaries.json"
)
# Build changelog
builder = ChangelogBuilder(
summarizer=summarizer,
include_scopes=True,
dedupe_prs=True,
)
changelog = builder.build(
version=until,
release_date=datetime.now(),
commits=commits,
commit_prs=commit_prs,
pr_index=pr_index,
)
# Render output
markdown = render_markdown(changelog)
html = render_html(changelog)
# Save files
(repo_path / "RELEASE_NOTES.md").write_text(markdown)
(repo_path / "release.html").write_text(html)
return markdown
# Usage
if __name__ == "__main__":
notes = generate_release_notes(
repo_path=Path("."),
since="v1.0.0",
until="v2.0.0",
github_token="ghp_...",
openai_key="sk-..."
)
print(notes)
Next steps
Git client
Detailed Git client documentation
Changelog builder
Changelog building API
Formatters
Output formatting reference
Examples
See Python API in action