fix: Add Gitea Actions CI workflow and fix linting issues
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled

This commit is contained in:
2026-02-04 16:59:26 +00:00
parent 4f7da77acf
commit 0147ff152a

148
src/templates.py Normal file
View 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)