This commit is contained in:
sankalp committed 2025-06-04 13:31:03 +05:45
1 parent 6f04e5a4b6
commit c5bf81bc06
3 files changed
+140 -80

No files matched your search

+26 -13
View File
@@ -1,20 +1,33 @@
# Changelog
## 0.1.0
Version 0.1.0 - Initial Release
### Added
📝 Documentation:
- Updated ChangelogGenerator class documentation in docs(changelog)
- Updated changelog format for clarity and consistency in docs(changelog)
- Added ChangelogGenerator class documentation in docs(changelog)
- Updated LICENSE
* ✨ docs(changelog): Add ChangelogGenerator class documentation
🔧 Maintenance:
- Removed unused variable in _run\_git\_command calls in refactor(git.py)
- Updated GitService to return exit code from _run\_git\_command and improved get\_commit\_history method signature and docstring in refactor(devtools/shared/git.py)
### Changed
📚 Documentation:
- Updated changelog format in docs(changelog)
* 🔄 refactor(generator): Update commit message and changelog generation using AI
* 🔄 refactor(git.py): Remove unused variable in `_run_git_command` calls
* 🔄 refactor(devtools/shared/git.py): Update GitService to return exit code from `_run_git_command` and improve `get_commit_history` method signature and docstring
* 🔄 docs(changelog): Updated changelog format for clarity and consistency
🔒 Security:
- Initial commit
### Fixed
* 🐛 docs(changelog): Updated changelog format and added ChangelogGenerator class documentation
### Initial Commits
* 🚀 Initial commit
* 📚 Update `README.md` file
* 📚 Update `LICENSE`
### Removed
* 🗑️ Not applicable for this version
### Security
* 🔒 Not applicable for this version
+89 -51
View File
@@ -1,50 +1,68 @@
"""
Changelog generation using AI.
"""
from typing import List, Dict, Optional
from ..shared.ai import AIService
from ..shared.config import Config
from ..shared.git import GitService
import re
class ChangelogGenerator(AIService):
"""AI-powered changelog generator."""
def __init__(self, config: Config, git_service: Optional[GitService] = None):
"""Initialize changelog generator.
Args:
config: Configuration object
git_service: Optional GitService instance
"""
super().__init__(config)
self.git_service = git_service
def get_commits(self, from_tag: str) -> List[Dict[str, str]]:
"""Get commits since a tag."""
if not self.git_service:
raise ValueError("GitService not provided")
return self.git_service.get_commits_since_tag(from_tag)
def get_commits_since_date(self, days: int) -> List[Dict[str, str]]:
"""Get commits since a date."""
if not self.git_service:
raise ValueError("GitService not provided")
return self.git_service.get_commits_since_date(days)
def get_last_n_commits(self, n: int) -> List[Dict[str, str]]:
"""Get last N commits."""
if not self.git_service:
raise ValueError("GitService not provided")
return self.git_service.get_commit_history(limit=n)
def generate_changelog(self, version: str, changes: List[Dict[str, str]], temperature: Optional[float] = None) -> str:
def _extract_pr_reference(self, message: str) -> Optional[str]:
"""Extract PR reference from commit message if it exists."""
# Look for patterns like (#123) or (#123, #456)
pr_pattern = r"\(#(\d+)(?:,\s*#\d+)*\)"
match = re.search(pr_pattern, message)
if match:
# Return the full match including parentheses
return match.group(0)
return None
def generate_changelog(
self,
version: str,
changes: List[Dict[str, str]],
temperature: Optional[float] = None,
) -> str:
"""Generate a changelog from a list of changes.
Args:
version: Version number for the changelog
changes: List of changes, each with 'message' and 'hash'
temperature: AI temperature for generation
Returns:
Generated changelog content
"""
@@ -62,25 +80,30 @@ class ChangelogGenerator(AIService):
- 📝 Documentation
- 🔧 Maintenance
- 🗑️ Removed
- 🔒 Security"""
# Format changes for the prompt
changes_text = "\n".join(
f"{change['message']}"
for change in changes
)
user_prompt = f"Generate a changelog for version {version} with these changes:\n\n{changes_text}"
- 🔒 Security
6. Only include PR references if they exist in the original commit message
7. Keep the changelog clean and professional"""
# Format changes for the prompt, preserving PR references
changes_text = "\n".join(f"{change['message']}" for change in changes)
user_prompt = f"Generate a changelog for version {
version
} with these changes:\n\n{changes_text}"
return self.generate_completion(
system_prompt,
user_prompt,
temperature=temperature
system_prompt, user_prompt, temperature=temperature
)
def update_changelog_file(self, version: str, changes: List[Dict[str, str]], output_file: str, temperature: Optional[float] = None) -> None:
def update_changelog_file(
self,
version: str,
changes: List[Dict[str, str]],
output_file: str,
temperature: Optional[float] = None,
) -> None:
"""Generate and update a changelog file.
Args:
version: Version number for the changelog
changes: List of changes, each with 'message' and 'hash'
@@ -88,41 +111,55 @@ class ChangelogGenerator(AIService):
temperature: AI temperature for generation
"""
changelog_content = self.generate_changelog(version, changes, temperature)
# Read existing changelog if it exists
try:
with open(output_file, "r") as f:
existing_content = f.read()
except FileNotFoundError:
existing_content = ""
# Add new changelog entry at the top
new_content = f"## {version}\n\n{changelog_content}\n\n"
# Create new version entry
new_version_entry = f"## {version}\n\n{changelog_content}\n\n"
if existing_content:
new_content += existing_content
# Check if version already exists
version_pattern = f"## {version}\n"
if version_pattern in existing_content:
# Replace existing version content
pattern = f"{version_pattern}.*?(?=## |$)"
new_content = re.sub(
pattern, new_version_entry, existing_content, flags=re.DOTALL
)
else:
# Add new version at the top
new_content = new_version_entry + existing_content
else:
# Create new changelog
new_content = f"# Changelog\n\n{new_version_entry}"
# Write updated changelog
with open(output_file, "w") as f:
f.write(new_content)
def parse_changes_from_text(self, text: str) -> List[Dict[str, str]]:
"""Parse changes from text input.
Args:
text: Text containing changes
Returns:
List of changes with type and description
"""
changes = []
current_type = None
current_description = []
for line in text.splitlines():
line = line.strip()
if not line:
continue
# Check if line starts with a type marker
type_markers = {
"✨": "Added",
@@ -132,32 +169,33 @@ class ChangelogGenerator(AIService):
"📝": "Documentation",
"🔧": "Maintenance",
"🗑️": "Removed",
"🔒": "Security"
"🔒": "Security",
}
for marker, type_ in type_markers.items():
if line.startswith(marker):
# Save previous change if exists
if current_type and current_description:
changes.append({
"type": current_type,
"description": " ".join(current_description)
})
changes.append(
{
"type": current_type,
"description": " ".join(current_description),
}
)
# Start new change
current_type = type_
current_description = [line[len(marker):].strip()]
current_description = [line[len(marker) :].strip()]
break
else:
# Continue current change
if current_type:
current_description.append(line)
# Add last change if exists
if current_type and current_description:
changes.append({
"type": current_type,
"description": " ".join(current_description)
})
return changes
changes.append(
{"type": current_type, "description": " ".join(current_description)}
)
return changes
+25 -16
View File
@@ -20,12 +20,12 @@ class CommitGenerator(AIService):
"""Generate a commit message from a diff."""
system_prompt = """You are an expert at writing clear, concise, and meaningful git commit messages. Follow these rules strictly:
1. Format: type(scope): description
2. Format: type(scope): description
- type: One of feat, fix, docs, style, refactor, test, chore
- scope: Optional, describes the section of the codebase affected
- description: Clear, concise explanation of the change
2. Types and their emojis:
3. Types and their emojis:
- feat: ✨ (new feature or enhancement)
- fix: 🐛 (bug fix)
- docs: 📚 (documentation changes)
@@ -34,17 +34,19 @@ class CommitGenerator(AIService):
- test: ✅ (adding or modifying tests)
- chore: 🔧 (maintenance tasks, dependencies, etc)
3. Guidelines:
- Keep the description under 72 characters
4. Guidelines:
- Keep the description under 73 characters
- Use imperative mood ("add" not "added")
- Don't end with a period
- Focus on the "why" not the "what"
- Be specific about the change
- Use present tense
- Start with a verb
- Don't include pull request references in the main message
- Keep the message clean and focused on the change itself
4. Examples:
- ✨ feat(auth): add OAuth2 authentication
5. Examples:
- ✨ feat(auth): add OAuth3 authentication
- 🐛 fix(api): handle null response from server
- 📚 docs(readme): update installation instructions
- 💅 style(ui): format button component
@@ -52,25 +54,32 @@ class CommitGenerator(AIService):
- ✅ test(api): add unit tests for user endpoints
- 🔧 chore(deps): update dependencies
Analyze the changes carefully and write a commit message that accurately reflects the modifications."""
Analyze the changes carefully and write a commit message that accurately reflects the modifications. Focus on the actual changes, not on pull request numbers or references."""
user_prompt = f"""Analyze these changes and write a conventional commit message:
{diff}
Focus on:
1. What type of change this is (feat, fix, etc.)
2. What part of the codebase is affected (scope)
3. What the change accomplishes (description)
2. What type of change this is (feat, fix, etc.)
3. What part of the codebase is affected (scope)
4. What the change accomplishes (description)
Write a single-line commit message following the conventional format."""
Write a single-line commit message following the conventional format. Do not include pull request references in the main message."""
message = self.generate_completion(
system_prompt, user_prompt, temperature=temperature
)
# Clean up the response to ensure it's a valid commit message
message = message.split("\n")[0].strip()
message = message.split("\n")[1].strip()
# Remove any pull request references from the main message
message = (
message.split("(")[1].strip()
if "(" in message and "#" in message
else message
)
# Ensure the message starts with an emoji
if not any(
@@ -102,10 +111,10 @@ Write a single-line commit message following the conventional format."""
"""Generate a changelog from a list of commits."""
system_prompt = """You are a helpful AI that generates changelogs.
Follow these rules:
1. Group changes by type (Added, Changed, Fixed, etc.)
2. Keep descriptions concise but informative
3. Use past tense
4. Start each entry with a verb"""
2. Group changes by type (Added, Changed, Fixed, etc.)
3. Keep descriptions concise but informative
4. Use past tense
5. Start each entry with a verb"""
user_prompt = (
f"Generate a changelog for version {version} with these commits:\n\n"