Initial upload: Local Commit Message Generator v0.1.0
This commit is contained in:
148
app/local_commit_message_generator/src/templates.py
Normal file
148
app/local_commit_message_generator/src/templates.py
Normal file
@@ -0,0 +1,148 @@
|
||||
"""Template management for commit message formatting."""
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class TemplateVariable:
|
||||
"""Represents a template variable with its value."""
|
||||
name: str
|
||||
value: str
|
||||
display_name: Optional[str] = None
|
||||
|
||||
|
||||
class TemplateManager:
|
||||
"""Manages commit message templates."""
|
||||
|
||||
DEFAULT_TEMPLATES = {
|
||||
"simple": "{type}{scope}: {description}",
|
||||
"detailed": "{type}({scope}): {description}\n\n{body}",
|
||||
"conventional": "{type}{scope}: {description}\n\n{files}",
|
||||
"verbose": "{type}{scope}: {description}\n\n{files}\n\n{body}",
|
||||
}
|
||||
|
||||
def __init__(self, template: Optional[str] = None):
|
||||
"""Initialize template manager.
|
||||
|
||||
Args:
|
||||
template: Template string to use. If not provided, uses simple template.
|
||||
"""
|
||||
self.template = template or self.DEFAULT_TEMPLATES["simple"]
|
||||
|
||||
def render(
|
||||
self,
|
||||
type: str,
|
||||
scope: str,
|
||||
description: str,
|
||||
body: str = "",
|
||||
files: Optional[List[str]] = None,
|
||||
**kwargs: Any
|
||||
) -> str:
|
||||
"""Render a commit message from template.
|
||||
|
||||
Args:
|
||||
type: Commit type (feat, fix, docs, etc.)
|
||||
scope: Commit scope.
|
||||
description: Commit description.
|
||||
body: Optional extended body text.
|
||||
files: Optional list of changed files.
|
||||
**kwargs: Additional template variables.
|
||||
|
||||
Returns:
|
||||
Rendered commit message string.
|
||||
"""
|
||||
files_part = ""
|
||||
if files:
|
||||
files_str = "\n".join(f" - {f}" for f in files[:10])
|
||||
if len(files) > 10:
|
||||
files_str += f"\n ... and {len(files) - 10} more"
|
||||
files_part = f"\n\nFiles changed:\n{files_str}"
|
||||
|
||||
variables = {
|
||||
"type": type,
|
||||
"scope": scope,
|
||||
"description": description,
|
||||
"body": body,
|
||||
"files": files_part,
|
||||
**kwargs
|
||||
}
|
||||
|
||||
result = self.template
|
||||
for key, value in variables.items():
|
||||
placeholder = f"{{{key}}}"
|
||||
result = result.replace(placeholder, str(value))
|
||||
|
||||
return result.strip()
|
||||
|
||||
@classmethod
|
||||
def get_default_templates(cls) -> Dict[str, str]:
|
||||
"""Get all default templates.
|
||||
|
||||
Returns:
|
||||
Dictionary of template name to template string.
|
||||
"""
|
||||
return cls.DEFAULT_TEMPLATES.copy()
|
||||
|
||||
@classmethod
|
||||
def validate_template(cls, template: str) -> tuple[bool, Optional[str]]:
|
||||
"""Validate a template string.
|
||||
|
||||
Args:
|
||||
template: Template string to validate.
|
||||
|
||||
Returns:
|
||||
Tuple of (is_valid, error_message).
|
||||
"""
|
||||
try:
|
||||
placeholders = re.findall(r"\{(\w+)\}", template)
|
||||
valid_placeholders = {"type", "scope", "description", "body", "files"}
|
||||
invalid = set(placeholders) - valid_placeholders
|
||||
if invalid:
|
||||
return False, f"Invalid placeholders: {', '.join(sorted(invalid))}"
|
||||
return True, None
|
||||
except re.error as e:
|
||||
return False, f"Invalid regex in template: {e}"
|
||||
|
||||
def generate_suggestions(self, changes: List[str]) -> List[str]:
|
||||
"""Generate description suggestions based on changed files.
|
||||
|
||||
Args:
|
||||
changes: List of changed file paths.
|
||||
|
||||
Returns:
|
||||
List of suggested descriptions.
|
||||
"""
|
||||
suggestions = []
|
||||
for path in changes[:5]:
|
||||
filename = path.split("/")[-1]
|
||||
base_name = ".".join(filename.split(".")[:-1])
|
||||
if base_name:
|
||||
suggestions.append(f"update {base_name}")
|
||||
else:
|
||||
suggestions.append(f"update {filename}")
|
||||
return suggestions
|
||||
|
||||
|
||||
def format_message(
|
||||
type: str,
|
||||
scope: str,
|
||||
description: str,
|
||||
template: Optional[str] = None,
|
||||
files: Optional[List[str]] = None
|
||||
) -> str:
|
||||
"""Format a commit message.
|
||||
|
||||
Args:
|
||||
type: Commit type.
|
||||
scope: Commit scope.
|
||||
description: Commit description.
|
||||
template: Optional custom template.
|
||||
files: Optional list of changed files.
|
||||
|
||||
Returns:
|
||||
Formatted commit message.
|
||||
"""
|
||||
manager = TemplateManager(template)
|
||||
return manager.render(type, scope, description, files=files)
|
||||
Reference in New Issue
Block a user