Initial commit
This commit is contained in:
408
commands/history-analysis/.scripts/convention-recommender.py
Executable file
408
commands/history-analysis/.scripts/convention-recommender.py
Executable file
@@ -0,0 +1,408 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
============================================================================
|
||||
SCRIPT: convention-recommender.py
|
||||
PURPOSE: Generate project-specific commit convention recommendations
|
||||
VERSION: 1.0.0
|
||||
USAGE: ./convention-recommender.py --count N --branch BRANCH [--priority LEVEL]
|
||||
RETURNS: JSON format with prioritized recommendations
|
||||
EXIT CODES:
|
||||
0 - Success
|
||||
1 - Not a git repository
|
||||
2 - No commit history
|
||||
3 - Analysis failed
|
||||
DEPENDENCIES: git, python3, style-analyzer.sh, pattern-detector.py, scope-extractor.sh
|
||||
============================================================================
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import os
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
|
||||
def run_script(script_path: str, args: List[str]) -> Tuple[int, str]:
|
||||
"""Execute a script and return exit code and output."""
|
||||
try:
|
||||
cmd = [script_path] + args
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
cwd=os.path.dirname(script_path)
|
||||
)
|
||||
return result.returncode, result.stdout.strip()
|
||||
except Exception as e:
|
||||
return 1, json.dumps({'error': str(e)})
|
||||
|
||||
|
||||
def gather_analysis_data(count: int, branch: str, scripts_dir: str) -> Dict:
|
||||
"""Gather all analysis data from other scripts."""
|
||||
data = {}
|
||||
|
||||
# Run style-analyzer.sh
|
||||
style_script = os.path.join(scripts_dir, 'style-analyzer.sh')
|
||||
code, output = run_script(style_script, [str(count), branch])
|
||||
if code == 0:
|
||||
try:
|
||||
data['style'] = json.loads(output)
|
||||
except json.JSONDecodeError:
|
||||
data['style'] = {}
|
||||
|
||||
# Run pattern-detector.py
|
||||
pattern_script = os.path.join(scripts_dir, 'pattern-detector.py')
|
||||
code, output = run_script(pattern_script, [
|
||||
'--count', str(count),
|
||||
'--branch', branch
|
||||
])
|
||||
if code == 0:
|
||||
try:
|
||||
data['patterns'] = json.loads(output)
|
||||
except json.JSONDecodeError:
|
||||
data['patterns'] = {}
|
||||
|
||||
# Run scope-extractor.sh
|
||||
scope_script = os.path.join(scripts_dir, 'scope-extractor.sh')
|
||||
code, output = run_script(scope_script, [
|
||||
'--count', str(count),
|
||||
'--branch', branch,
|
||||
'--min-frequency', '2'
|
||||
])
|
||||
if code == 0:
|
||||
try:
|
||||
data['scopes'] = json.loads(output)
|
||||
except json.JSONDecodeError:
|
||||
data['scopes'] = {}
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def generate_recommendations(data: Dict, priority_filter: str) -> Dict:
|
||||
"""Generate prioritized recommendations based on analysis data."""
|
||||
recommendations = {
|
||||
'high_priority': [],
|
||||
'medium_priority': [],
|
||||
'low_priority': []
|
||||
}
|
||||
|
||||
style = data.get('style', {}).get('project_style', {})
|
||||
patterns = data.get('patterns', {})
|
||||
scopes = data.get('scopes', {})
|
||||
|
||||
# HIGH PRIORITY RECOMMENDATIONS
|
||||
|
||||
# 1. Conventional commits adoption
|
||||
conv_pct = style.get('conventional_commits_percentage', 0)
|
||||
if conv_pct < 50:
|
||||
recommendations['high_priority'].append({
|
||||
'id': 1,
|
||||
'title': 'Adopt Conventional Commits Format',
|
||||
'status': 'needs_improvement',
|
||||
'current_usage': conv_pct,
|
||||
'target_usage': 80,
|
||||
'action': 'Migrate to conventional commits format: <type>(<scope>): <subject>',
|
||||
'benefit': 'Enables automated changelog, semantic versioning, and better git history',
|
||||
'priority': 'high',
|
||||
'examples': [
|
||||
'feat(auth): implement OAuth2 authentication',
|
||||
'fix(api): handle null pointer in user endpoint',
|
||||
'docs: update API documentation'
|
||||
]
|
||||
})
|
||||
elif conv_pct < 80:
|
||||
recommendations['medium_priority'].append({
|
||||
'id': 1,
|
||||
'title': 'Increase Conventional Commits Usage',
|
||||
'status': 'moderate',
|
||||
'current_usage': conv_pct,
|
||||
'target_usage': 90,
|
||||
'action': 'Encourage team to use conventional commits consistently',
|
||||
'benefit': 'Better consistency and tooling support',
|
||||
'priority': 'medium'
|
||||
})
|
||||
else:
|
||||
recommendations['high_priority'].append({
|
||||
'id': 1,
|
||||
'title': 'Continue Using Conventional Commits',
|
||||
'status': 'good',
|
||||
'current_usage': conv_pct,
|
||||
'target_usage': 90,
|
||||
'action': 'Maintain current practice',
|
||||
'benefit': 'Already well-adopted, enables automation',
|
||||
'priority': 'high'
|
||||
})
|
||||
|
||||
# 2. Subject line length
|
||||
avg_length = style.get('average_subject_length', 0)
|
||||
if avg_length > 60:
|
||||
recommendations['high_priority'].append({
|
||||
'id': 2,
|
||||
'title': 'Reduce Subject Line Length',
|
||||
'status': 'needs_improvement',
|
||||
'current_value': avg_length,
|
||||
'target_value': 50,
|
||||
'action': 'Keep subject lines under 50 characters',
|
||||
'benefit': 'Better readability in git log, GitHub UI, and terminal',
|
||||
'priority': 'high'
|
||||
})
|
||||
elif avg_length > 50:
|
||||
recommendations['medium_priority'].append({
|
||||
'id': 2,
|
||||
'title': 'Optimize Subject Line Length',
|
||||
'status': 'moderate',
|
||||
'current_value': avg_length,
|
||||
'target_value': 50,
|
||||
'action': 'Aim for concise subject lines (under 50 chars)',
|
||||
'priority': 'medium'
|
||||
})
|
||||
|
||||
# 3. Imperative mood
|
||||
imperative_pct = style.get('imperative_mood_percentage', 0)
|
||||
if imperative_pct < 80:
|
||||
recommendations['high_priority'].append({
|
||||
'id': 3,
|
||||
'title': 'Use Imperative Mood Consistently',
|
||||
'status': 'needs_improvement',
|
||||
'current_usage': imperative_pct,
|
||||
'target_usage': 90,
|
||||
'action': 'Use imperative mood: "add" not "added", "fix" not "fixed"',
|
||||
'benefit': 'Clearer, more professional commit messages',
|
||||
'priority': 'high',
|
||||
'examples': [
|
||||
'✓ add user authentication',
|
||||
'✗ added user authentication',
|
||||
'✓ fix null pointer exception',
|
||||
'✗ fixed null pointer exception'
|
||||
]
|
||||
})
|
||||
|
||||
# MEDIUM PRIORITY RECOMMENDATIONS
|
||||
|
||||
# 4. Body usage
|
||||
body_pct = style.get('has_body_percentage', 0)
|
||||
if body_pct < 50:
|
||||
recommendations['medium_priority'].append({
|
||||
'id': 4,
|
||||
'title': 'Increase Body Usage for Complex Changes',
|
||||
'status': 'low',
|
||||
'current_usage': body_pct,
|
||||
'target_usage': 50,
|
||||
'action': 'Add commit body for non-trivial changes (>3 files, complex logic)',
|
||||
'benefit': 'Better context for code review and future reference',
|
||||
'priority': 'medium',
|
||||
'when_to_use': [
|
||||
'Multiple files changed (>3)',
|
||||
'Complex logic modifications',
|
||||
'Breaking changes',
|
||||
'Security-related changes'
|
||||
]
|
||||
})
|
||||
|
||||
# 5. Issue references
|
||||
issue_pct = style.get('references_issues_percentage', 0)
|
||||
if issue_pct > 50:
|
||||
recommendations['medium_priority'].append({
|
||||
'id': 5,
|
||||
'title': 'Continue Issue Referencing Practice',
|
||||
'status': 'good',
|
||||
'current_usage': issue_pct,
|
||||
'action': 'Maintain consistent issue references',
|
||||
'benefit': 'Excellent traceability between commits and issues',
|
||||
'priority': 'medium'
|
||||
})
|
||||
elif issue_pct > 25:
|
||||
recommendations['medium_priority'].append({
|
||||
'id': 5,
|
||||
'title': 'Increase Issue References',
|
||||
'status': 'moderate',
|
||||
'current_usage': issue_pct,
|
||||
'target_usage': 60,
|
||||
'action': 'Reference related issues: "Closes #123", "Fixes #456", "Refs #789"',
|
||||
'benefit': 'Better traceability',
|
||||
'priority': 'medium'
|
||||
})
|
||||
|
||||
# LOW PRIORITY RECOMMENDATIONS
|
||||
|
||||
# 6. Scope standardization
|
||||
scope_count = scopes.get('total_scopes', 0)
|
||||
if scope_count > 0:
|
||||
top_scopes = scopes.get('scopes', [])[:5]
|
||||
scope_names = [s['name'] for s in top_scopes]
|
||||
recommendations['medium_priority'].append({
|
||||
'id': 6,
|
||||
'title': 'Use Standard Project Scopes',
|
||||
'status': 'good',
|
||||
'action': f'Use these common scopes: {", ".join(scope_names)}',
|
||||
'benefit': 'Consistent scope usage across team',
|
||||
'priority': 'medium',
|
||||
'scopes': scope_names
|
||||
})
|
||||
|
||||
# 7. Co-author attribution
|
||||
recommendations['low_priority'].append({
|
||||
'id': 7,
|
||||
'title': 'Consider Co-Author Attribution',
|
||||
'status': 'optional',
|
||||
'action': 'Add co-authors for pair programming: Co-authored-by: Name <email>',
|
||||
'benefit': 'Team recognition and contribution tracking',
|
||||
'priority': 'low',
|
||||
'example': 'Co-authored-by: Jane Doe <jane@example.com>'
|
||||
})
|
||||
|
||||
# 8. Breaking change documentation
|
||||
recommendations['low_priority'].append({
|
||||
'id': 8,
|
||||
'title': 'Document Breaking Changes',
|
||||
'status': 'important',
|
||||
'action': 'Use BREAKING CHANGE: footer when applicable',
|
||||
'benefit': 'Clear communication of breaking changes for semantic versioning',
|
||||
'priority': 'low',
|
||||
'example': 'BREAKING CHANGE: API now requires OAuth tokens instead of API keys'
|
||||
})
|
||||
|
||||
# Filter by priority if specified
|
||||
if priority_filter and priority_filter != 'all':
|
||||
priority_key = f'{priority_filter}_priority'
|
||||
filtered = {priority_key: recommendations.get(priority_key, [])}
|
||||
return filtered
|
||||
|
||||
return recommendations
|
||||
|
||||
|
||||
def generate_style_guide(data: Dict) -> Dict:
|
||||
"""Generate project-specific style guide."""
|
||||
style = data.get('style', {}).get('project_style', {})
|
||||
scopes_data = data.get('scopes', {})
|
||||
|
||||
# Extract common types
|
||||
common_types = style.get('common_types', [])
|
||||
types_sorted = sorted(common_types, key=lambda x: x.get('count', 0), reverse=True)
|
||||
|
||||
# Extract common scopes
|
||||
scopes = scopes_data.get('scopes', [])[:10]
|
||||
|
||||
# Build style guide
|
||||
return {
|
||||
'format': '<type>(<scope>): <subject>',
|
||||
'max_subject_length': 50,
|
||||
'body_wrap': 72,
|
||||
'types': [
|
||||
{
|
||||
'name': t.get('type', 'unknown'),
|
||||
'percentage': t.get('percentage', 0),
|
||||
'description': get_type_description(t.get('type', 'unknown'))
|
||||
}
|
||||
for t in types_sorted
|
||||
],
|
||||
'scopes': [
|
||||
{
|
||||
'name': s.get('name', 'unknown'),
|
||||
'percentage': s.get('percentage', 0),
|
||||
'description': s.get('description', 'Unknown'),
|
||||
'category': s.get('category', 'other')
|
||||
}
|
||||
for s in scopes
|
||||
],
|
||||
'rules': [
|
||||
'Use imperative mood ("add" not "added")',
|
||||
'Capitalize first letter of subject',
|
||||
'No period at end of subject line',
|
||||
'Use lowercase for scopes',
|
||||
'Wrap body at 72 characters',
|
||||
'Separate body and footer with blank line',
|
||||
'Use bullet points in body',
|
||||
'Reference issues when applicable'
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def get_type_description(type_name: str) -> str:
|
||||
"""Get description for commit type."""
|
||||
descriptions = {
|
||||
'feat': 'New features',
|
||||
'fix': 'Bug fixes',
|
||||
'docs': 'Documentation changes',
|
||||
'style': 'Formatting changes (no code change)',
|
||||
'refactor': 'Code restructuring',
|
||||
'perf': 'Performance improvements',
|
||||
'test': 'Test additions/updates',
|
||||
'build': 'Build system changes',
|
||||
'ci': 'CI/CD changes',
|
||||
'chore': 'Maintenance tasks',
|
||||
'revert': 'Revert previous commit'
|
||||
}
|
||||
return descriptions.get(type_name, 'Other changes')
|
||||
|
||||
|
||||
def calculate_confidence(data: Dict) -> str:
|
||||
"""Calculate confidence level of recommendations."""
|
||||
commits_analyzed = data.get('style', {}).get('project_style', {}).get('commits_analyzed', 0)
|
||||
|
||||
if commits_analyzed >= 100:
|
||||
return 'high'
|
||||
elif commits_analyzed >= 50:
|
||||
return 'medium'
|
||||
elif commits_analyzed >= 20:
|
||||
return 'low'
|
||||
else:
|
||||
return 'very_low'
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Generate convention recommendations')
|
||||
parser.add_argument('--count', type=int, default=50, help='Number of commits to analyze')
|
||||
parser.add_argument('--branch', default='HEAD', help='Branch to analyze')
|
||||
parser.add_argument('--priority', choices=['high', 'medium', 'low', 'all'], default='all',
|
||||
help='Filter by priority level')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Get scripts directory
|
||||
scripts_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
# Gather analysis data
|
||||
data = gather_analysis_data(args.count, args.branch, scripts_dir)
|
||||
|
||||
if not data:
|
||||
print(json.dumps({'error': 'Failed to gather analysis data'}), file=sys.stderr)
|
||||
sys.exit(3)
|
||||
|
||||
# Generate recommendations
|
||||
recommendations = generate_recommendations(data, args.priority)
|
||||
|
||||
# Generate style guide
|
||||
style_guide = generate_style_guide(data)
|
||||
|
||||
# Calculate confidence
|
||||
confidence = calculate_confidence(data)
|
||||
|
||||
# Calculate consistency score
|
||||
consistency_score = data.get('patterns', {}).get('consistency_score', 0)
|
||||
|
||||
# Build output
|
||||
output = {
|
||||
'commits_analyzed': data.get('style', {}).get('project_style', {}).get('commits_analyzed', 0),
|
||||
'branch': args.branch,
|
||||
'consistency_score': consistency_score,
|
||||
'confidence': confidence,
|
||||
'recommendations': recommendations,
|
||||
'style_guide': style_guide,
|
||||
'automation': {
|
||||
'commitlint': True,
|
||||
'changelog_generator': 'standard-version',
|
||||
'semantic_release': True
|
||||
}
|
||||
}
|
||||
|
||||
# Output JSON
|
||||
print(json.dumps(output, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
421
commands/history-analysis/.scripts/pattern-detector.py
Executable file
421
commands/history-analysis/.scripts/pattern-detector.py
Executable file
@@ -0,0 +1,421 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
============================================================================
|
||||
SCRIPT: pattern-detector.py
|
||||
PURPOSE: Detect commit message patterns and conventions from git history
|
||||
VERSION: 1.0.0
|
||||
USAGE: ./pattern-detector.py --count N --branch BRANCH [--detailed]
|
||||
RETURNS: JSON format with pattern detection results
|
||||
EXIT CODES:
|
||||
0 - Success
|
||||
1 - Not a git repository
|
||||
2 - No commit history
|
||||
3 - Git command failed
|
||||
DEPENDENCIES: git, python3
|
||||
============================================================================
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import json
|
||||
import re
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List, Tuple
|
||||
|
||||
|
||||
def run_git_command(cmd: List[str]) -> Tuple[int, str]:
|
||||
"""Execute git command and return exit code and output."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False
|
||||
)
|
||||
return result.returncode, result.stdout.strip()
|
||||
except Exception as e:
|
||||
return 1, str(e)
|
||||
|
||||
|
||||
def is_git_repository() -> bool:
|
||||
"""Check if current directory is a git repository."""
|
||||
code, _ = run_git_command(['git', 'rev-parse', '--git-dir'])
|
||||
return code == 0
|
||||
|
||||
|
||||
def has_commits() -> bool:
|
||||
"""Check if repository has any commits."""
|
||||
code, _ = run_git_command(['git', 'log', '-1'])
|
||||
return code == 0
|
||||
|
||||
|
||||
def get_commits(count: int, branch: str) -> List[Dict[str, str]]:
|
||||
"""Fetch commit messages from git log."""
|
||||
code, output = run_git_command([
|
||||
'git', 'log',
|
||||
f'-{count}',
|
||||
branch,
|
||||
'--format=%H%n%s%n%b%n---COMMIT_SEPARATOR---'
|
||||
])
|
||||
|
||||
if code != 0:
|
||||
return []
|
||||
|
||||
commits = []
|
||||
lines = output.split('\n')
|
||||
i = 0
|
||||
|
||||
while i < len(lines):
|
||||
if i + 1 >= len(lines):
|
||||
break
|
||||
|
||||
commit_hash = lines[i]
|
||||
subject = lines[i + 1] if i + 1 < len(lines) else ""
|
||||
|
||||
# Find body (lines until separator)
|
||||
body_lines = []
|
||||
i += 2
|
||||
while i < len(lines) and lines[i] != '---COMMIT_SEPARATOR---':
|
||||
if lines[i].strip(): # Skip empty lines at start
|
||||
body_lines.append(lines[i])
|
||||
i += 1
|
||||
|
||||
body = '\n'.join(body_lines).strip()
|
||||
|
||||
commits.append({
|
||||
'hash': commit_hash,
|
||||
'subject': subject,
|
||||
'body': body,
|
||||
'full': subject + '\n\n' + body if body else subject
|
||||
})
|
||||
|
||||
i += 1 # Skip separator
|
||||
|
||||
return commits
|
||||
|
||||
|
||||
def is_conventional_commit(subject: str) -> bool:
|
||||
"""Check if commit follows conventional commits format."""
|
||||
pattern = r'^[a-z]+(\([^)]+\))?: .+'
|
||||
return bool(re.match(pattern, subject))
|
||||
|
||||
|
||||
def has_prefix(subject: str) -> bool:
|
||||
"""Check if commit has prefix format like [PREFIX]."""
|
||||
pattern = r'^\[[^\]]+\]'
|
||||
return bool(re.match(pattern, subject))
|
||||
|
||||
|
||||
def has_tag(subject: str) -> bool:
|
||||
"""Check if commit starts with tag like #tag."""
|
||||
return subject.startswith('#')
|
||||
|
||||
|
||||
def is_imperative_mood(subject: str) -> bool:
|
||||
"""
|
||||
Check if subject uses imperative mood.
|
||||
Simple heuristic: starts with common imperative verbs.
|
||||
"""
|
||||
# Extract first word after type/scope if conventional
|
||||
words = subject.lower()
|
||||
if ':' in words:
|
||||
words = words.split(':', 1)[1].strip()
|
||||
|
||||
# Common imperative verbs and their non-imperative forms to avoid
|
||||
imperative_verbs = [
|
||||
'add', 'fix', 'update', 'remove', 'delete', 'create', 'implement',
|
||||
'change', 'improve', 'optimize', 'refactor', 'enhance', 'correct',
|
||||
'resolve', 'merge', 'bump', 'revert', 'document', 'upgrade',
|
||||
'downgrade', 'rename', 'move', 'replace', 'extract', 'simplify'
|
||||
]
|
||||
|
||||
# Non-imperative indicators
|
||||
non_imperative = ['added', 'fixed', 'updated', 'removed', 'deleted',
|
||||
'created', 'implemented', 'changed', 'improved',
|
||||
'adding', 'fixing', 'updating']
|
||||
|
||||
first_word = words.split()[0] if words.split() else ""
|
||||
|
||||
if first_word in non_imperative:
|
||||
return False
|
||||
|
||||
return first_word in imperative_verbs
|
||||
|
||||
|
||||
def is_capitalized(subject: str) -> bool:
|
||||
"""Check if subject is properly capitalized."""
|
||||
# Extract text after type/scope if conventional
|
||||
text = subject
|
||||
if ':' in text:
|
||||
text = text.split(':', 1)[1].strip()
|
||||
|
||||
return text[0].isupper() if text else False
|
||||
|
||||
|
||||
def has_no_period_end(subject: str) -> bool:
|
||||
"""Check if subject doesn't end with period."""
|
||||
return not subject.endswith('.')
|
||||
|
||||
|
||||
def has_blank_line_before_body(full_message: str) -> bool:
|
||||
"""Check if there's a blank line between subject and body."""
|
||||
lines = full_message.split('\n')
|
||||
if len(lines) < 3:
|
||||
return True # No body or only one line body
|
||||
|
||||
# Check if second line is empty
|
||||
return lines[1].strip() == ''
|
||||
|
||||
|
||||
def is_body_wrapped(body: str, max_width: int = 72) -> bool:
|
||||
"""Check if body lines are wrapped at max_width."""
|
||||
if not body:
|
||||
return True
|
||||
|
||||
lines = body.split('\n')
|
||||
for line in lines:
|
||||
# Allow bullet points and URLs to exceed limit
|
||||
if line.strip().startswith(('-', '*', '•', 'http://', 'https://')):
|
||||
continue
|
||||
if len(line) > max_width:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def has_footer(full_message: str) -> bool:
|
||||
"""Check if commit has footer (BREAKING CHANGE, issue refs, etc.)."""
|
||||
footer_patterns = [
|
||||
r'BREAKING CHANGE:',
|
||||
r'Closes #\d+',
|
||||
r'Fixes #\d+',
|
||||
r'Refs #\d+',
|
||||
r'Co-authored-by:',
|
||||
r'Signed-off-by:'
|
||||
]
|
||||
|
||||
for pattern in footer_patterns:
|
||||
if re.search(pattern, full_message):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def references_issues(full_message: str) -> bool:
|
||||
"""Check if commit references issues."""
|
||||
pattern = r'#\d+|[Cc]loses|[Ff]ixes|[Rr]efs'
|
||||
return bool(re.search(pattern, full_message))
|
||||
|
||||
|
||||
def mentions_breaking(full_message: str) -> bool:
|
||||
"""Check if commit mentions breaking changes."""
|
||||
return 'BREAKING CHANGE:' in full_message or 'BREAKING-CHANGE:' in full_message
|
||||
|
||||
|
||||
def has_co_authors(full_message: str) -> bool:
|
||||
"""Check if commit has co-authors."""
|
||||
return 'Co-authored-by:' in full_message
|
||||
|
||||
|
||||
def is_signed_off(full_message: str) -> bool:
|
||||
"""Check if commit is signed off."""
|
||||
return 'Signed-off-by:' in full_message
|
||||
|
||||
|
||||
def includes_rationale(body: str) -> bool:
|
||||
"""Check if body includes rationale (why/because/to/for)."""
|
||||
if not body:
|
||||
return False
|
||||
words = ['because', 'to ', 'for ', 'why', 'since', 'as ', 'in order to']
|
||||
body_lower = body.lower()
|
||||
return any(word in body_lower for word in words)
|
||||
|
||||
|
||||
def mentions_impact(body: str) -> bool:
|
||||
"""Check if body mentions impact."""
|
||||
if not body:
|
||||
return False
|
||||
words = ['affect', 'impact', 'change', 'improve', 'break', 'fix']
|
||||
body_lower = body.lower()
|
||||
return any(word in body_lower for word in words)
|
||||
|
||||
|
||||
def analyze_patterns(commits: List[Dict[str, str]]) -> Dict:
|
||||
"""Analyze commit patterns and return results."""
|
||||
total = len(commits)
|
||||
|
||||
# Initialize counters
|
||||
patterns = {
|
||||
'format': defaultdict(int),
|
||||
'conventions': defaultdict(int),
|
||||
'content': defaultdict(int)
|
||||
}
|
||||
|
||||
# Count commits with bodies (for calculations)
|
||||
commits_with_body = 0
|
||||
|
||||
for commit in commits:
|
||||
subject = commit['subject']
|
||||
body = commit['body']
|
||||
full = commit['full']
|
||||
|
||||
# Format patterns
|
||||
if is_conventional_commit(subject):
|
||||
patterns['format']['conventional_commits'] += 1
|
||||
elif has_prefix(subject):
|
||||
patterns['format']['prefixed'] += 1
|
||||
elif has_tag(subject):
|
||||
patterns['format']['tagged'] += 1
|
||||
else:
|
||||
patterns['format']['simple_subject'] += 1
|
||||
|
||||
# Convention patterns
|
||||
if is_imperative_mood(subject):
|
||||
patterns['conventions']['imperative_mood'] += 1
|
||||
|
||||
if is_capitalized(subject):
|
||||
patterns['conventions']['capitalized_subject'] += 1
|
||||
|
||||
if has_no_period_end(subject):
|
||||
patterns['conventions']['no_period_end'] += 1
|
||||
|
||||
if body:
|
||||
commits_with_body += 1
|
||||
if has_blank_line_before_body(full):
|
||||
patterns['conventions']['blank_line_before_body'] += 1
|
||||
|
||||
if is_body_wrapped(body):
|
||||
patterns['conventions']['wrapped_body'] += 1
|
||||
|
||||
if has_footer(full):
|
||||
patterns['conventions']['has_footer'] += 1
|
||||
|
||||
# Content patterns
|
||||
if references_issues(full):
|
||||
patterns['content']['references_issues'] += 1
|
||||
|
||||
if mentions_breaking(full):
|
||||
patterns['content']['mentions_breaking'] += 1
|
||||
|
||||
if has_co_authors(full):
|
||||
patterns['content']['has_co_authors'] += 1
|
||||
|
||||
if is_signed_off(full):
|
||||
patterns['content']['signed_off'] += 1
|
||||
|
||||
if includes_rationale(body):
|
||||
patterns['content']['includes_rationale'] += 1
|
||||
|
||||
if mentions_impact(body):
|
||||
patterns['content']['mentions_impact'] += 1
|
||||
|
||||
# Calculate percentages and strength
|
||||
def calc_percentage(count, denominator=total):
|
||||
return round((count / denominator * 100), 1) if denominator > 0 else 0
|
||||
|
||||
def get_strength(percentage):
|
||||
if percentage >= 95:
|
||||
return "perfect"
|
||||
elif percentage >= 80:
|
||||
return "strong"
|
||||
elif percentage >= 65:
|
||||
return "dominant"
|
||||
elif percentage >= 45:
|
||||
return "common"
|
||||
elif percentage >= 25:
|
||||
return "moderate"
|
||||
elif percentage >= 10:
|
||||
return "occasional"
|
||||
elif percentage >= 1:
|
||||
return "rare"
|
||||
else:
|
||||
return "absent"
|
||||
|
||||
# Build results
|
||||
results = {
|
||||
'format': {},
|
||||
'conventions': {},
|
||||
'content': {}
|
||||
}
|
||||
|
||||
for category, counters in patterns.items():
|
||||
for pattern_name, count in counters.items():
|
||||
# Use commits_with_body as denominator for body-specific patterns
|
||||
if pattern_name in ['blank_line_before_body', 'wrapped_body']:
|
||||
denominator = commits_with_body
|
||||
else:
|
||||
denominator = total
|
||||
|
||||
percentage = calc_percentage(count, denominator)
|
||||
results[category][pattern_name] = {
|
||||
'count': count,
|
||||
'percentage': percentage,
|
||||
'strength': get_strength(percentage)
|
||||
}
|
||||
|
||||
# Calculate consistency score
|
||||
# Weight: format(40), conventions(40), content(20)
|
||||
format_score = results['format'].get('conventional_commits', {}).get('percentage', 0)
|
||||
convention_scores = [
|
||||
results['conventions'].get('imperative_mood', {}).get('percentage', 0),
|
||||
results['conventions'].get('capitalized_subject', {}).get('percentage', 0),
|
||||
results['conventions'].get('no_period_end', {}).get('percentage', 0)
|
||||
]
|
||||
avg_convention = sum(convention_scores) / len(convention_scores) if convention_scores else 0
|
||||
content_scores = [
|
||||
results['content'].get('references_issues', {}).get('percentage', 0),
|
||||
results['content'].get('includes_rationale', {}).get('percentage', 0)
|
||||
]
|
||||
avg_content = sum(content_scores) / len(content_scores) if content_scores else 0
|
||||
|
||||
consistency_score = int(format_score * 0.4 + avg_convention * 0.4 + avg_content * 0.2)
|
||||
|
||||
# Determine dominant pattern
|
||||
format_patterns = results['format']
|
||||
dominant_pattern = max(format_patterns.items(), key=lambda x: x[1]['count'])[0] if format_patterns else "unknown"
|
||||
|
||||
return {
|
||||
'commits_analyzed': total,
|
||||
'patterns': results,
|
||||
'consistency_score': consistency_score,
|
||||
'dominant_pattern': dominant_pattern
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Detect commit message patterns')
|
||||
parser.add_argument('--count', type=int, default=50, help='Number of commits to analyze')
|
||||
parser.add_argument('--branch', default='HEAD', help='Branch to analyze')
|
||||
parser.add_argument('--detailed', action='store_true', help='Include detailed breakdown')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Validate git repository
|
||||
if not is_git_repository():
|
||||
print(json.dumps({'error': 'Not in a git repository'}), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if not has_commits():
|
||||
print(json.dumps({'error': 'No commit history found'}), file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
# Fetch commits
|
||||
commits = get_commits(args.count, args.branch)
|
||||
if not commits:
|
||||
print(json.dumps({'error': 'Failed to fetch commits'}), file=sys.stderr)
|
||||
sys.exit(3)
|
||||
|
||||
# Analyze patterns
|
||||
results = analyze_patterns(commits)
|
||||
results['branch'] = args.branch
|
||||
results['detailed'] = args.detailed
|
||||
|
||||
# Output JSON
|
||||
print(json.dumps(results, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
230
commands/history-analysis/.scripts/scope-extractor.sh
Executable file
230
commands/history-analysis/.scripts/scope-extractor.sh
Executable file
@@ -0,0 +1,230 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================================================
|
||||
# SCRIPT: scope-extractor.sh
|
||||
# PURPOSE: Extract and analyze scopes from commit messages
|
||||
# VERSION: 1.0.0
|
||||
# USAGE: ./scope-extractor.sh --count N --branch BRANCH [--min-frequency N]
|
||||
# RETURNS: JSON format with scope analysis results
|
||||
# EXIT CODES:
|
||||
# 0 - Success
|
||||
# 1 - Not a git repository
|
||||
# 2 - No commit history
|
||||
# 3 - Git command failed
|
||||
# DEPENDENCIES: git, jq (optional)
|
||||
# ============================================================================
|
||||
|
||||
# Parse command line arguments
|
||||
COUNT=50
|
||||
BRANCH="HEAD"
|
||||
MIN_FREQUENCY=2
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--count)
|
||||
COUNT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--branch)
|
||||
BRANCH="$2"
|
||||
shift 2
|
||||
;;
|
||||
--min-frequency)
|
||||
MIN_FREQUENCY="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo '{"error": "Not in a git repository"}' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if commits exist
|
||||
if ! git log -1 >/dev/null 2>&1; then
|
||||
echo '{"error": "No commit history found"}' >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Get commit subjects
|
||||
SUBJECTS=$(git log --format='%s' -"$COUNT" "$BRANCH" 2>/dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo '{"error": "Failed to fetch git log"}' >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# Create temporary files for processing
|
||||
TEMP_SCOPES=$(mktemp)
|
||||
TEMP_RESULTS=$(mktemp)
|
||||
|
||||
# Clean up temp files on exit
|
||||
trap "rm -f $TEMP_SCOPES $TEMP_RESULTS" EXIT
|
||||
|
||||
# Extract scopes from conventional commit format: type(scope): subject
|
||||
# Also handle nested scopes: type(parent/child): subject
|
||||
# And multi-scopes: type(scope1,scope2): subject
|
||||
|
||||
TOTAL_COMMITS=$(echo "$SUBJECTS" | wc -l)
|
||||
SCOPED_COMMITS=0
|
||||
|
||||
while IFS= read -r subject; do
|
||||
[ -z "$subject" ] && continue
|
||||
|
||||
# Match conventional commit with scope: type(scope): subject
|
||||
if echo "$subject" | grep -qE '^[a-z]+\([^)]+\): '; then
|
||||
((SCOPED_COMMITS++))
|
||||
|
||||
# Extract scope(s) - everything between parentheses
|
||||
SCOPE_PART=$(echo "$subject" | sed -E 's/^[a-z]+\(([^)]+)\): .*/\1/')
|
||||
|
||||
# Handle multiple scopes (comma or space separated)
|
||||
# Split by comma and/or space
|
||||
echo "$SCOPE_PART" | tr ',' '\n' | tr ' ' '\n' | while read -r scope; do
|
||||
scope=$(echo "$scope" | xargs) # Trim whitespace
|
||||
[ -n "$scope" ] && echo "$scope" >> "$TEMP_SCOPES"
|
||||
done
|
||||
fi
|
||||
done <<< "$SUBJECTS"
|
||||
|
||||
# Count scope frequencies
|
||||
if [ ! -s "$TEMP_SCOPES" ]; then
|
||||
# No scopes found
|
||||
cat << EOF
|
||||
{
|
||||
"total_scopes": 0,
|
||||
"scoped_commits": 0,
|
||||
"scoped_percentage": 0,
|
||||
"scopes": [],
|
||||
"message": "No scopes detected in commit history"
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Sort and count unique scopes
|
||||
SCOPE_COUNTS=$(sort "$TEMP_SCOPES" | uniq -c | sort -rn)
|
||||
|
||||
# Calculate scoped percentage
|
||||
SCOPED_PCT=$(echo "scale=1; $SCOPED_COMMITS * 100 / $TOTAL_COMMITS" | bc -l)
|
||||
|
||||
# Build JSON output
|
||||
echo "{" > "$TEMP_RESULTS"
|
||||
echo " \"commits_analyzed\": $TOTAL_COMMITS," >> "$TEMP_RESULTS"
|
||||
echo " \"scoped_commits\": $SCOPED_COMMITS," >> "$TEMP_RESULTS"
|
||||
echo " \"scoped_percentage\": $SCOPED_PCT," >> "$TEMP_RESULTS"
|
||||
echo " \"branch\": \"$BRANCH\"," >> "$TEMP_RESULTS"
|
||||
|
||||
# Count unique scopes
|
||||
UNIQUE_SCOPES=$(echo "$SCOPE_COUNTS" | wc -l)
|
||||
echo " \"total_scopes\": $UNIQUE_SCOPES," >> "$TEMP_RESULTS"
|
||||
|
||||
# Build scopes array
|
||||
echo " \"scopes\": [" >> "$TEMP_RESULTS"
|
||||
|
||||
FIRST=true
|
||||
while read -r count scope; do
|
||||
# Skip if below min frequency
|
||||
[ "$count" -lt "$MIN_FREQUENCY" ] && continue
|
||||
|
||||
# Calculate percentage
|
||||
PCT=$(echo "scale=1; $count * 100 / $SCOPED_COMMITS" | bc -l)
|
||||
|
||||
# Determine if hierarchical (contains /)
|
||||
HIERARCHY="null"
|
||||
PARENT=""
|
||||
CHILD=""
|
||||
if echo "$scope" | grep -q '/'; then
|
||||
PARENT=$(echo "$scope" | cut -d'/' -f1)
|
||||
CHILD=$(echo "$scope" | cut -d'/' -f2)
|
||||
HIERARCHY="\"$PARENT/$CHILD\""
|
||||
fi
|
||||
|
||||
# Categorize scope
|
||||
CATEGORY="other"
|
||||
DESCRIPTION="Other"
|
||||
|
||||
case "$scope" in
|
||||
auth|security|login|oauth|session)
|
||||
CATEGORY="feature"
|
||||
DESCRIPTION="Authentication and authorization"
|
||||
;;
|
||||
api|endpoint|backend|server|middleware)
|
||||
CATEGORY="backend"
|
||||
DESCRIPTION="API and backend services"
|
||||
;;
|
||||
ui|component|style|frontend|view)
|
||||
CATEGORY="ui"
|
||||
DESCRIPTION="User interface"
|
||||
;;
|
||||
db|database|schema|migration|query)
|
||||
CATEGORY="backend"
|
||||
DESCRIPTION="Database operations"
|
||||
;;
|
||||
docs|readme|changelog|guide)
|
||||
CATEGORY="documentation"
|
||||
DESCRIPTION="Documentation"
|
||||
;;
|
||||
test|e2e|unit|integration|spec)
|
||||
CATEGORY="testing"
|
||||
DESCRIPTION="Testing"
|
||||
;;
|
||||
ci|cd|deploy|docker|k8s|pipeline)
|
||||
CATEGORY="infrastructure"
|
||||
DESCRIPTION="Infrastructure and deployment"
|
||||
;;
|
||||
config|settings|env)
|
||||
CATEGORY="configuration"
|
||||
DESCRIPTION="Configuration"
|
||||
;;
|
||||
core|utils|lib|common)
|
||||
CATEGORY="core"
|
||||
DESCRIPTION="Core functionality"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check if active (used in recent commits - last 10)
|
||||
RECENT_USAGE=$(git log --format='%s' -10 "$BRANCH" 2>/dev/null | grep -c "($scope)" || echo "0")
|
||||
ACTIVE="true"
|
||||
[ "$RECENT_USAGE" -eq 0 ] && ACTIVE="false"
|
||||
|
||||
# Get example commits
|
||||
EXAMPLES=$(git log --format='%s' --grep="($scope)" -3 "$BRANCH" 2>/dev/null | \
|
||||
awk '{printf "\"%s\",", $0}' | sed 's/,$//')
|
||||
[ -z "$EXAMPLES" ] && EXAMPLES=""
|
||||
|
||||
# Add comma if not first
|
||||
if [ "$FIRST" = true ]; then
|
||||
FIRST=false
|
||||
else
|
||||
echo " ," >> "$TEMP_RESULTS"
|
||||
fi
|
||||
|
||||
# Write scope entry
|
||||
cat << EOF >> "$TEMP_RESULTS"
|
||||
{
|
||||
"name": "$scope",
|
||||
"count": $count,
|
||||
"percentage": $PCT,
|
||||
"category": "$CATEGORY",
|
||||
"description": "$DESCRIPTION",
|
||||
"hierarchy": $HIERARCHY,
|
||||
"active": $ACTIVE,
|
||||
"recent_usage": $RECENT_USAGE,
|
||||
"examples": [$EXAMPLES]
|
||||
}
|
||||
EOF
|
||||
|
||||
done <<< "$SCOPE_COUNTS"
|
||||
|
||||
echo " ]" >> "$TEMP_RESULTS"
|
||||
echo "}" >> "$TEMP_RESULTS"
|
||||
|
||||
# Output result
|
||||
cat "$TEMP_RESULTS"
|
||||
|
||||
exit 0
|
||||
232
commands/history-analysis/.scripts/style-analyzer.sh
Executable file
232
commands/history-analysis/.scripts/style-analyzer.sh
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================================================
|
||||
# SCRIPT: style-analyzer.sh
|
||||
# PURPOSE: Analyze git commit history for style patterns and conventions
|
||||
# VERSION: 1.0.0
|
||||
# USAGE: ./style-analyzer.sh [count] [branch]
|
||||
# RETURNS: JSON format with style analysis results
|
||||
# EXIT CODES:
|
||||
# 0 - Success
|
||||
# 1 - Not a git repository
|
||||
# 2 - No commit history
|
||||
# 3 - Git command failed
|
||||
# DEPENDENCIES: git, jq (optional for pretty JSON)
|
||||
# ============================================================================
|
||||
|
||||
# Default parameters
|
||||
COUNT="${1:-50}"
|
||||
BRANCH="${2:-HEAD}"
|
||||
|
||||
# Validate git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo '{"error": "Not in a git repository"}' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if commits exist
|
||||
if ! git log -1 >/dev/null 2>&1; then
|
||||
echo '{"error": "No commit history found"}' >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Get commit subjects
|
||||
SUBJECTS=$(git log --format='%s' -"$COUNT" "$BRANCH" 2>/dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo '{"error": "Failed to fetch git log"}' >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# Get full commit messages (subject + body)
|
||||
FULL_MESSAGES=$(git log --format='%B%n---COMMIT_SEPARATOR---' -"$COUNT" "$BRANCH" 2>/dev/null)
|
||||
|
||||
# Count total commits analyzed
|
||||
TOTAL_COMMITS=$(echo "$SUBJECTS" | wc -l)
|
||||
|
||||
# Initialize counters
|
||||
CONVENTIONAL_COUNT=0
|
||||
IMPERATIVE_COUNT=0
|
||||
HAS_BODY_COUNT=0
|
||||
REFERENCES_ISSUES_COUNT=0
|
||||
CAPITALIZED_COUNT=0
|
||||
NO_PERIOD_COUNT=0
|
||||
|
||||
# Arrays for type and scope counting
|
||||
declare -A TYPE_COUNT
|
||||
declare -A SCOPE_COUNT
|
||||
|
||||
# Calculate subject line lengths
|
||||
LENGTHS=""
|
||||
TOTAL_LENGTH=0
|
||||
|
||||
# Process each subject line
|
||||
while IFS= read -r subject; do
|
||||
[ -z "$subject" ] && continue
|
||||
|
||||
# Length analysis
|
||||
LENGTH=${#subject}
|
||||
LENGTHS="$LENGTHS $LENGTH"
|
||||
TOTAL_LENGTH=$((TOTAL_LENGTH + LENGTH))
|
||||
|
||||
# Check conventional commits format: type(scope): subject
|
||||
if echo "$subject" | grep -qE '^[a-z]+(\([^)]+\))?: '; then
|
||||
((CONVENTIONAL_COUNT++))
|
||||
|
||||
# Extract type
|
||||
TYPE=$(echo "$subject" | sed -E 's/^([a-z]+)(\([^)]+\))?: .*/\1/')
|
||||
TYPE_COUNT[$TYPE]=$((${TYPE_COUNT[$TYPE]:-0} + 1))
|
||||
|
||||
# Extract scope if present
|
||||
if echo "$subject" | grep -qE '^[a-z]+\([^)]+\): '; then
|
||||
SCOPE=$(echo "$subject" | sed -E 's/^[a-z]+\(([^)]+)\): .*/\1/')
|
||||
SCOPE_COUNT[$SCOPE]=$((${SCOPE_COUNT[$SCOPE]:-0} + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check imperative mood (simple heuristic - starts with verb in base form)
|
||||
# Common imperative verbs
|
||||
if echo "$subject" | grep -qiE '^(add|fix|update|remove|refactor|implement|create|delete|change|improve|optimize|enhance|correct|resolve|merge|bump|revert|feat|docs|style|test|chore|perf|build|ci)[:(]'; then
|
||||
((IMPERATIVE_COUNT++))
|
||||
fi
|
||||
|
||||
# Check capitalization (first letter after type/scope)
|
||||
if echo "$subject" | grep -qE ': [A-Z]'; then
|
||||
((CAPITALIZED_COUNT++))
|
||||
fi
|
||||
|
||||
# Check no period at end
|
||||
if ! echo "$subject" | grep -qE '\.$'; then
|
||||
((NO_PERIOD_COUNT++))
|
||||
fi
|
||||
|
||||
done <<< "$SUBJECTS"
|
||||
|
||||
# Analyze full messages for body and issue references
|
||||
COMMIT_NUM=0
|
||||
while IFS= read -r line; do
|
||||
if [ "$line" = "---COMMIT_SEPARATOR---" ]; then
|
||||
if [ $HAS_BODY = true ]; then
|
||||
((HAS_BODY_COUNT++))
|
||||
fi
|
||||
if [ $HAS_ISSUE_REF = true ]; then
|
||||
((REFERENCES_ISSUES_COUNT++))
|
||||
fi
|
||||
HAS_BODY=false
|
||||
HAS_ISSUE_REF=false
|
||||
IN_SUBJECT=true
|
||||
COMMIT_NUM=$((COMMIT_NUM + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$IN_SUBJECT" = true ]; then
|
||||
IN_SUBJECT=false
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if has body (non-empty line after subject)
|
||||
if [ -n "$line" ] && [ "$line" != "" ]; then
|
||||
HAS_BODY=true
|
||||
fi
|
||||
|
||||
# Check for issue references
|
||||
if echo "$line" | grep -qE '#[0-9]+|[Cc]loses|[Ff]ixes|[Rr]efs'; then
|
||||
HAS_ISSUE_REF=true
|
||||
fi
|
||||
done <<< "$FULL_MESSAGES"
|
||||
|
||||
# Calculate average subject length
|
||||
if [ $TOTAL_COMMITS -gt 0 ]; then
|
||||
AVG_LENGTH=$((TOTAL_LENGTH / TOTAL_COMMITS))
|
||||
else
|
||||
AVG_LENGTH=0
|
||||
fi
|
||||
|
||||
# Calculate standard deviation (simplified)
|
||||
SUM_SQUARED_DIFF=0
|
||||
for length in $LENGTHS; do
|
||||
DIFF=$((length - AVG_LENGTH))
|
||||
SUM_SQUARED_DIFF=$((SUM_SQUARED_DIFF + DIFF * DIFF))
|
||||
done
|
||||
if [ $TOTAL_COMMITS -gt 0 ]; then
|
||||
STDDEV=$(echo "scale=1; sqrt($SUM_SQUARED_DIFF / $TOTAL_COMMITS)" | bc -l 2>/dev/null || echo "0")
|
||||
else
|
||||
STDDEV=0
|
||||
fi
|
||||
|
||||
# Calculate percentages
|
||||
calc_percentage() {
|
||||
if [ $TOTAL_COMMITS -gt 0 ]; then
|
||||
echo "scale=1; $1 * 100 / $TOTAL_COMMITS" | bc -l
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
CONVENTIONAL_PCT=$(calc_percentage $CONVENTIONAL_COUNT)
|
||||
IMPERATIVE_PCT=$(calc_percentage $IMPERATIVE_COUNT)
|
||||
HAS_BODY_PCT=$(calc_percentage $HAS_BODY_COUNT)
|
||||
REFERENCES_ISSUES_PCT=$(calc_percentage $REFERENCES_ISSUES_COUNT)
|
||||
CAPITALIZED_PCT=$(calc_percentage $CAPITALIZED_COUNT)
|
||||
NO_PERIOD_PCT=$(calc_percentage $NO_PERIOD_COUNT)
|
||||
|
||||
# Build common_types JSON array
|
||||
COMMON_TYPES_JSON="["
|
||||
FIRST=true
|
||||
for type in "${!TYPE_COUNT[@]}"; do
|
||||
count=${TYPE_COUNT[$type]}
|
||||
pct=$(calc_percentage $count)
|
||||
if [ "$FIRST" = true ]; then
|
||||
FIRST=false
|
||||
else
|
||||
COMMON_TYPES_JSON="$COMMON_TYPES_JSON,"
|
||||
fi
|
||||
COMMON_TYPES_JSON="$COMMON_TYPES_JSON{\"type\":\"$type\",\"count\":$count,\"percentage\":$pct}"
|
||||
done
|
||||
COMMON_TYPES_JSON="$COMMON_TYPES_JSON]"
|
||||
|
||||
# Build common_scopes JSON array
|
||||
COMMON_SCOPES_JSON="["
|
||||
FIRST=true
|
||||
for scope in "${!SCOPE_COUNT[@]}"; do
|
||||
count=${SCOPE_COUNT[$scope]}
|
||||
pct=$(calc_percentage $count)
|
||||
if [ "$FIRST" = true ]; then
|
||||
FIRST=false
|
||||
else
|
||||
COMMON_SCOPES_JSON="$COMMON_SCOPES_JSON,"
|
||||
fi
|
||||
COMMON_SCOPES_JSON="$COMMON_SCOPES_JSON{\"scope\":\"$scope\",\"count\":$count,\"percentage\":$pct}"
|
||||
done
|
||||
COMMON_SCOPES_JSON="$COMMON_SCOPES_JSON]"
|
||||
|
||||
# Get sample commits (first 3)
|
||||
SAMPLE_COMMITS=$(git log --format='%s' -3 "$BRANCH" 2>/dev/null | awk '{printf "\"%s\",", $0}' | sed 's/,$//')
|
||||
|
||||
# Calculate consistency score (weighted average)
|
||||
# Weights: conventional(30), imperative(25), capitalized(15), no_period(15), body(10), issues(5)
|
||||
CONSISTENCY_SCORE=$(echo "scale=0; ($CONVENTIONAL_PCT * 0.3 + $IMPERATIVE_PCT * 0.25 + $CAPITALIZED_PCT * 0.15 + $NO_PERIOD_PCT * 0.15 + $HAS_BODY_PCT * 0.1 + $REFERENCES_ISSUES_PCT * 0.05)" | bc -l)
|
||||
|
||||
# Output JSON
|
||||
cat << EOF
|
||||
{
|
||||
"project_style": {
|
||||
"commits_analyzed": $TOTAL_COMMITS,
|
||||
"branch": "$BRANCH",
|
||||
"uses_conventional_commits": $([ $CONVENTIONAL_COUNT -gt $((TOTAL_COMMITS / 2)) ] && echo "true" || echo "false"),
|
||||
"conventional_commits_percentage": $CONVENTIONAL_PCT,
|
||||
"average_subject_length": $AVG_LENGTH,
|
||||
"subject_length_stddev": $STDDEV,
|
||||
"common_types": $COMMON_TYPES_JSON,
|
||||
"common_scopes": $COMMON_SCOPES_JSON,
|
||||
"imperative_mood_percentage": $IMPERATIVE_PCT,
|
||||
"capitalized_subject_percentage": $CAPITALIZED_PCT,
|
||||
"no_period_end_percentage": $NO_PERIOD_PCT,
|
||||
"has_body_percentage": $HAS_BODY_PCT,
|
||||
"references_issues_percentage": $REFERENCES_ISSUES_PCT,
|
||||
"consistency_score": $CONSISTENCY_SCORE,
|
||||
"sample_commits": [$SAMPLE_COMMITS]
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
245
commands/history-analysis/analyze-style.md
Normal file
245
commands/history-analysis/analyze-style.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# Operation: Analyze Commit Style
|
||||
|
||||
**Purpose:** Analyze recent commit history to learn the project's commit message style, conventions, and patterns.
|
||||
|
||||
## Parameters
|
||||
|
||||
From `$ARGUMENTS` (after operation name):
|
||||
- `count:N` - Number of commits to analyze (default: 50)
|
||||
- `branch:name` - Branch to analyze (default: current branch)
|
||||
- `format:json|text` - Output format (default: text)
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Validate Repository
|
||||
|
||||
```bash
|
||||
# Check if in git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo "Error: Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if has commits
|
||||
if ! git log -1 >/dev/null 2>&1; then
|
||||
echo "Error: No commit history found"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Execute Style Analysis Script
|
||||
|
||||
Invoke the style-analyzer.sh utility script:
|
||||
|
||||
```bash
|
||||
./.scripts/style-analyzer.sh <count> <branch>
|
||||
```
|
||||
|
||||
The script will:
|
||||
- Fetch recent commits from git log
|
||||
- Analyze commit message formats
|
||||
- Calculate statistics (average length, type distribution, etc.)
|
||||
- Detect conventional commits usage
|
||||
- Identify common patterns
|
||||
|
||||
### 3. Process Analysis Results
|
||||
|
||||
The script returns JSON output with:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_style": {
|
||||
"uses_conventional_commits": true,
|
||||
"conventional_commits_percentage": 87,
|
||||
"average_subject_length": 47,
|
||||
"subject_length_stddev": 8,
|
||||
"common_types": [
|
||||
{"type": "feat", "count": 45, "percentage": 35.4},
|
||||
{"type": "fix", "count": 38, "percentage": 29.9},
|
||||
{"type": "docs", "count": 20, "percentage": 15.7}
|
||||
],
|
||||
"common_scopes": [
|
||||
{"scope": "auth", "count": 23, "percentage": 18.1},
|
||||
{"scope": "api", "count": 19, "percentage": 14.9},
|
||||
{"scope": "ui", "count": 15, "percentage": 11.8}
|
||||
],
|
||||
"imperative_mood_percentage": 92,
|
||||
"has_body_percentage": 34,
|
||||
"references_issues_percentage": 67,
|
||||
"consistency_score": 85,
|
||||
"sample_commits": [
|
||||
"feat(auth): implement OAuth2 authentication",
|
||||
"fix(api): handle null pointer in user endpoint",
|
||||
"docs: update API documentation"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Generate Recommendations
|
||||
|
||||
Based on analysis results, provide:
|
||||
|
||||
**Style Recommendations:**
|
||||
- Conventional commits adherence level
|
||||
- Recommended message format
|
||||
- Typical subject line length
|
||||
- Body usage patterns
|
||||
- Issue reference patterns
|
||||
|
||||
**Type Recommendations:**
|
||||
- Most commonly used types
|
||||
- Type usage frequency
|
||||
- Recommended types for new commits
|
||||
|
||||
**Scope Recommendations:**
|
||||
- Commonly used scopes
|
||||
- Scope naming patterns
|
||||
- When to use which scope
|
||||
|
||||
**Consistency Recommendations:**
|
||||
- Areas of good consistency
|
||||
- Areas needing improvement
|
||||
- Specific guidance for better consistency
|
||||
|
||||
### 5. Format Output
|
||||
|
||||
**Text Format (default):**
|
||||
```
|
||||
Git Commit Style Analysis
|
||||
=========================
|
||||
|
||||
Commits Analyzed: 50
|
||||
Branch: main
|
||||
Conventional Commits: 87% (43/50)
|
||||
Consistency Score: 85/100
|
||||
|
||||
Subject Lines:
|
||||
Average Length: 47 characters
|
||||
Recommended: Keep under 50 characters
|
||||
|
||||
Common Types:
|
||||
1. feat - 35.4% (45 commits) - New features
|
||||
2. fix - 29.9% (38 commits) - Bug fixes
|
||||
3. docs - 15.7% (20 commits) - Documentation
|
||||
|
||||
Common Scopes:
|
||||
1. auth - 18.1% (23 commits) - Authentication/authorization
|
||||
2. api - 14.9% (19 commits) - API endpoints
|
||||
3. ui - 11.8% (15 commits) - User interface
|
||||
|
||||
Patterns Detected:
|
||||
✓ Uses imperative mood (92%)
|
||||
✓ References issues frequently (67%)
|
||||
○ Body usage moderate (34%)
|
||||
|
||||
Recommendations:
|
||||
• Continue using conventional commits format
|
||||
• Consider 'auth' scope for authentication changes
|
||||
• Keep subject lines under 50 characters
|
||||
• Use imperative mood (e.g., "add" not "added")
|
||||
• Reference issues when applicable (#123)
|
||||
|
||||
Sample Commits (project style):
|
||||
feat(auth): implement OAuth2 authentication
|
||||
fix(api): handle null pointer in user endpoint
|
||||
docs: update API documentation
|
||||
```
|
||||
|
||||
**JSON Format:**
|
||||
```json
|
||||
{
|
||||
"analysis_type": "commit_style",
|
||||
"commits_analyzed": 50,
|
||||
"branch": "main",
|
||||
"results": { ... },
|
||||
"recommendations": [ ... ],
|
||||
"confidence": "high"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**No git repository:**
|
||||
- Error: "Not in a git repository. Run this command from within a git project."
|
||||
- Exit code: 1
|
||||
|
||||
**No commits:**
|
||||
- Error: "No commit history found. This appears to be a new repository."
|
||||
- Exit code: 1
|
||||
|
||||
**Branch doesn't exist:**
|
||||
- Error: "Branch 'branch-name' not found. Check branch name and try again."
|
||||
- Exit code: 1
|
||||
|
||||
**Insufficient commits:**
|
||||
- Warning: "Only X commits found. Analysis may be less accurate."
|
||||
- Proceed with available commits
|
||||
|
||||
**Git command fails:**
|
||||
- Error: "Git command failed: {error message}"
|
||||
- Provide troubleshooting steps
|
||||
|
||||
## Integration Usage
|
||||
|
||||
**By commit-assistant agent:**
|
||||
```
|
||||
User requests: "commit my changes"
|
||||
→ Agent invokes: /history-analysis analyze-style
|
||||
→ Learns: Project uses conventional commits, common scope: "auth"
|
||||
→ Agent generates message matching project style
|
||||
```
|
||||
|
||||
**By message-generation skill:**
|
||||
```
|
||||
Before generating message:
|
||||
→ Invoke: /history-analysis analyze-style format:json
|
||||
→ Extract: common_types, common_scopes, average_length
|
||||
→ Use in: message generation to match project conventions
|
||||
```
|
||||
|
||||
## Output Examples
|
||||
|
||||
**High Consistency Project (score: 95):**
|
||||
```
|
||||
✓ Excellent consistency across commits
|
||||
✓ Strong conventional commits adherence (98%)
|
||||
✓ Clear scope usage patterns
|
||||
→ Continue current practices
|
||||
```
|
||||
|
||||
**Medium Consistency Project (score: 65):**
|
||||
```
|
||||
○ Moderate consistency
|
||||
○ Mixed conventional commits usage (64%)
|
||||
○ Inconsistent scope patterns
|
||||
→ Recommend adopting conventional commits
|
||||
→ Define standard scopes for the project
|
||||
```
|
||||
|
||||
**Low Consistency Project (score: 35):**
|
||||
```
|
||||
✗ Low consistency across commits
|
||||
✗ Minimal conventional commits usage (12%)
|
||||
✗ No clear patterns
|
||||
→ Consider establishing commit message guidelines
|
||||
→ Define project-specific conventions
|
||||
→ Use this tool to enforce standards
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Operation succeeds when:
|
||||
- [x] Git repository validated
|
||||
- [x] Commits successfully analyzed
|
||||
- [x] Statistics calculated accurately
|
||||
- [x] Patterns detected correctly
|
||||
- [x] Recommendations generated
|
||||
- [x] Output formatted properly
|
||||
- [x] Results match project reality
|
||||
|
||||
## Performance
|
||||
|
||||
- **Analysis Time:** ~1-2 seconds for 50 commits
|
||||
- **Memory Usage:** Minimal (processes line-by-line)
|
||||
- **Git Operations:** Read-only, no modifications
|
||||
302
commands/history-analysis/detect-patterns.md
Normal file
302
commands/history-analysis/detect-patterns.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# Operation: Detect Commit Patterns
|
||||
|
||||
**Purpose:** Identify project-specific commit message patterns, conventions, and formatting standards from commit history.
|
||||
|
||||
## Parameters
|
||||
|
||||
From `$ARGUMENTS` (after operation name):
|
||||
- `count:N` - Number of commits to analyze (default: 50)
|
||||
- `branch:name` - Branch to analyze (default: current branch)
|
||||
- `format:json|text` - Output format (default: text)
|
||||
- `detailed:true|false` - Include detailed pattern breakdown (default: false)
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Validate Repository
|
||||
|
||||
```bash
|
||||
# Verify git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo "Error: Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Execute Pattern Detection
|
||||
|
||||
Invoke the pattern-detector.py utility script:
|
||||
|
||||
```bash
|
||||
./.scripts/pattern-detector.py --count <count> --branch <branch> [--detailed]
|
||||
```
|
||||
|
||||
The script analyzes:
|
||||
- **Format Patterns:** Message structure and formatting
|
||||
- **Convention Patterns:** Conventional commits, semantic versioning references
|
||||
- **Content Patterns:** Imperative mood, capitalization, punctuation
|
||||
- **Metadata Patterns:** Issue references, co-authors, sign-offs
|
||||
- **Body Patterns:** Bullet points, wrapping, section structure
|
||||
|
||||
### 3. Pattern Categories Analyzed
|
||||
|
||||
**A. Format Patterns**
|
||||
```python
|
||||
patterns = {
|
||||
'conventional_commits': 0, # type(scope): subject
|
||||
'simple_subject': 0, # Just a subject line
|
||||
'prefixed': 0, # [PREFIX] subject
|
||||
'tagged': 0, # #tag subject
|
||||
'other': 0
|
||||
}
|
||||
```
|
||||
|
||||
**B. Convention Patterns**
|
||||
```python
|
||||
conventions = {
|
||||
'imperative_mood': 0, # "add" vs "added"
|
||||
'capitalized_subject': 0, # First letter capitalized
|
||||
'no_period_end': 0, # No period at end
|
||||
'blank_line_before_body': 0, # Proper body separation
|
||||
'wrapped_body': 0, # 72-char wrap
|
||||
'has_footer': 0 # Breaking changes, issues
|
||||
}
|
||||
```
|
||||
|
||||
**C. Content Patterns**
|
||||
```python
|
||||
content = {
|
||||
'references_issues': 0, # #123, Closes #456
|
||||
'mentions_breaking': 0, # BREAKING CHANGE:
|
||||
'has_co_authors': 0, # Co-authored-by:
|
||||
'signed_off': 0, # Signed-off-by:
|
||||
'includes_rationale': 0, # "because", "to", "for"
|
||||
'mentions_impact': 0 # "affects", "impacts", "changes"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Pattern Analysis Algorithm
|
||||
|
||||
The pattern-detector.py script implements:
|
||||
|
||||
```python
|
||||
def analyze_commit_patterns(commits):
|
||||
"""
|
||||
Analyze commit messages for patterns.
|
||||
Returns pattern frequencies and confidence scores.
|
||||
"""
|
||||
patterns = initialize_pattern_counters()
|
||||
|
||||
for commit in commits:
|
||||
# Parse commit structure
|
||||
subject, body, footer = parse_commit(commit)
|
||||
|
||||
# Detect format pattern
|
||||
if is_conventional_commit(subject):
|
||||
patterns['format']['conventional_commits'] += 1
|
||||
elif has_prefix(subject):
|
||||
patterns['format']['prefixed'] += 1
|
||||
# ... more checks
|
||||
|
||||
# Detect conventions
|
||||
if is_imperative_mood(subject):
|
||||
patterns['conventions']['imperative_mood'] += 1
|
||||
if is_capitalized(subject):
|
||||
patterns['conventions']['capitalized_subject'] += 1
|
||||
# ... more checks
|
||||
|
||||
# Detect content patterns
|
||||
if references_issues(commit):
|
||||
patterns['content']['references_issues'] += 1
|
||||
# ... more checks
|
||||
|
||||
# Calculate percentages
|
||||
return calculate_pattern_percentages(patterns, len(commits))
|
||||
```
|
||||
|
||||
### 5. Output Structure
|
||||
|
||||
**Text Format (default):**
|
||||
```
|
||||
Commit Pattern Analysis
|
||||
=======================
|
||||
|
||||
Commits Analyzed: 50
|
||||
Branch: main
|
||||
|
||||
FORMAT PATTERNS
|
||||
---------------
|
||||
Conventional Commits: 87% (44/50) ✓ DOMINANT
|
||||
Example: feat(auth): implement OAuth2
|
||||
Simple Subject: 10% (5/50)
|
||||
Example: Update documentation
|
||||
Prefixed: 3% (1/50)
|
||||
Example: [HOTFIX] Fix critical bug
|
||||
|
||||
CONVENTION PATTERNS
|
||||
-------------------
|
||||
Imperative Mood: 92% (46/50) ✓ STRONG
|
||||
Capitalized Subject: 94% (47/50) ✓ STRONG
|
||||
No Period at End: 88% (44/50) ✓ STRONG
|
||||
Blank Line Before Body: 100% (17/17) ✓ PERFECT
|
||||
Body Wrapped at 72: 94% (16/17) ✓ STRONG
|
||||
Has Footer: 26% (13/50) ○ MODERATE
|
||||
|
||||
CONTENT PATTERNS
|
||||
----------------
|
||||
References Issues: 67% (34/50) ✓ COMMON
|
||||
Mentions Breaking: 8% (4/50) ○ OCCASIONAL
|
||||
Has Co-Authors: 2% (1/50) ✗ RARE
|
||||
Signed-Off: 12% (6/50) ○ OCCASIONAL
|
||||
Includes Rationale: 45% (23/50) ○ MODERATE
|
||||
Mentions Impact: 31% (16/50) ○ MODERATE
|
||||
|
||||
DETECTED CONVENTIONS
|
||||
--------------------
|
||||
✓ Project uses conventional commits format
|
||||
✓ Strong imperative mood usage
|
||||
✓ Consistent capitalization and punctuation
|
||||
✓ Frequent issue references
|
||||
○ Moderate footer usage
|
||||
○ Occasional breaking change mentions
|
||||
|
||||
PATTERN CONSISTENCY
|
||||
-------------------
|
||||
Overall Score: 85/100 (GOOD)
|
||||
Format: High (87% conventional)
|
||||
Conventions: High (90%+ adherence)
|
||||
Content: Moderate (varied usage)
|
||||
|
||||
RECOMMENDATIONS
|
||||
---------------
|
||||
• Continue using conventional commits format
|
||||
• Maintain imperative mood in subject lines
|
||||
• Consider more consistent footer usage
|
||||
• Document rationale in commit bodies when complex
|
||||
```
|
||||
|
||||
**JSON Format:**
|
||||
```json
|
||||
{
|
||||
"analysis_type": "pattern_detection",
|
||||
"commits_analyzed": 50,
|
||||
"branch": "main",
|
||||
"patterns": {
|
||||
"format": {
|
||||
"conventional_commits": {"count": 44, "percentage": 87, "strength": "dominant"},
|
||||
"simple_subject": {"count": 5, "percentage": 10, "strength": "rare"},
|
||||
"prefixed": {"count": 1, "percentage": 3, "strength": "rare"}
|
||||
},
|
||||
"conventions": {
|
||||
"imperative_mood": {"count": 46, "percentage": 92, "strength": "strong"},
|
||||
"capitalized_subject": {"count": 47, "percentage": 94, "strength": "strong"},
|
||||
"no_period_end": {"count": 44, "percentage": 88, "strength": "strong"}
|
||||
},
|
||||
"content": {
|
||||
"references_issues": {"count": 34, "percentage": 67, "strength": "common"},
|
||||
"mentions_breaking": {"count": 4, "percentage": 8, "strength": "occasional"}
|
||||
}
|
||||
},
|
||||
"consistency_score": 85,
|
||||
"dominant_pattern": "conventional_commits",
|
||||
"recommendations": [
|
||||
"Continue using conventional commits format",
|
||||
"Maintain imperative mood in subject lines"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Pattern Strength Classification
|
||||
|
||||
```
|
||||
PERFECT: 95-100% - Universal usage
|
||||
STRONG: 80-94% - Very consistent
|
||||
DOMINANT: 65-79% - Clear preference
|
||||
COMMON: 45-64% - Regular usage
|
||||
MODERATE: 25-44% - Occasional usage
|
||||
OCCASIONAL: 10-24% - Infrequent usage
|
||||
RARE: 1-9% - Seldom used
|
||||
ABSENT: 0% - Not used
|
||||
```
|
||||
|
||||
### 7. Detailed Pattern Breakdown
|
||||
|
||||
When `detailed:true` is specified, include:
|
||||
|
||||
**Per-Pattern Examples:**
|
||||
```
|
||||
IMPERATIVE MOOD (92%)
|
||||
✓ "Add user authentication"
|
||||
✓ "Fix null pointer exception"
|
||||
✓ "Update API documentation"
|
||||
✗ "Added new feature"
|
||||
✗ "Updated dependencies"
|
||||
```
|
||||
|
||||
**Timeline Analysis:**
|
||||
```
|
||||
Pattern Evolution (most recent 10 commits):
|
||||
Conventional Commits: 10/10 (100%) - Improving ↑
|
||||
Imperative Mood: 9/10 (90%) - Stable →
|
||||
Issue References: 8/10 (80%) - Improving ↑
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**No git repository:**
|
||||
- Return: "Error: Not in a git repository"
|
||||
- Exit code: 1
|
||||
|
||||
**No commits:**
|
||||
- Return: "Error: No commit history to analyze"
|
||||
- Exit code: 1
|
||||
|
||||
**Insufficient commits:**
|
||||
- Warning: "Only X commits available (requested Y)"
|
||||
- Proceed with available commits
|
||||
|
||||
**Pattern detection fails:**
|
||||
- Return partial results with warning
|
||||
- Indicate which patterns couldn't be detected
|
||||
|
||||
## Integration Usage
|
||||
|
||||
**By commit-assistant agent:**
|
||||
```
|
||||
Agent: Determine project conventions
|
||||
→ Invoke: /history-analysis detect-patterns
|
||||
→ Learn: Project uses conventional commits (87%)
|
||||
→ Apply: Use conventional format for new commits
|
||||
```
|
||||
|
||||
**By message-generation skill:**
|
||||
```
|
||||
Before generating:
|
||||
→ Detect dominant patterns
|
||||
→ Extract format preferences
|
||||
→ Match project conventions
|
||||
```
|
||||
|
||||
**By commit-best-practices skill:**
|
||||
```
|
||||
When reviewing commits:
|
||||
→ Compare against detected patterns
|
||||
→ Flag deviations from project norms
|
||||
→ Suggest consistency improvements
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Operation succeeds when:
|
||||
- [x] All pattern categories analyzed
|
||||
- [x] Frequencies calculated accurately
|
||||
- [x] Strength classifications assigned
|
||||
- [x] Consistency score computed
|
||||
- [x] Dominant pattern identified
|
||||
- [x] Recommendations generated
|
||||
- [x] Output formatted correctly
|
||||
|
||||
## Performance
|
||||
|
||||
- **Analysis Time:** ~2-3 seconds for 50 commits
|
||||
- **Memory Usage:** Low (streaming analysis)
|
||||
- **Accuracy:** High (>95% pattern detection accuracy)
|
||||
378
commands/history-analysis/extract-scopes.md
Normal file
378
commands/history-analysis/extract-scopes.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# Operation: Extract Scopes
|
||||
|
||||
**Purpose:** Discover and analyze commonly used scopes in commit messages to understand project structure and component organization.
|
||||
|
||||
## Parameters
|
||||
|
||||
From `$ARGUMENTS` (after operation name):
|
||||
- `count:N` - Number of commits to analyze (default: 50)
|
||||
- `branch:name` - Branch to analyze (default: current branch)
|
||||
- `format:json|text` - Output format (default: text)
|
||||
- `min_frequency:N` - Minimum occurrences to include (default: 2)
|
||||
- `top:N` - Show only top N scopes (default: 20)
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Validate Repository
|
||||
|
||||
```bash
|
||||
# Check git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo "Error: Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Execute Scope Extraction
|
||||
|
||||
Invoke the scope-extractor.sh utility script:
|
||||
|
||||
```bash
|
||||
./.scripts/scope-extractor.sh --count <count> --branch <branch> --min-frequency <min>
|
||||
```
|
||||
|
||||
The script will:
|
||||
- Parse commit messages
|
||||
- Extract scopes using regex patterns
|
||||
- Count scope frequencies
|
||||
- Analyze scope naming patterns
|
||||
- Categorize scopes by type
|
||||
|
||||
### 3. Scope Extraction Algorithm
|
||||
|
||||
**Pattern Matching:**
|
||||
```bash
|
||||
# Primary pattern: type(scope): subject
|
||||
^[a-z]+\(([^)]+)\):
|
||||
|
||||
# Examples:
|
||||
feat(auth): add OAuth → scope: "auth"
|
||||
fix(api/users): handle null → scope: "api/users"
|
||||
docs(readme): update guide → scope: "readme"
|
||||
```
|
||||
|
||||
**Nested Scope Handling:**
|
||||
```bash
|
||||
# Hierarchical scopes
|
||||
api/endpoints → parent: "api", child: "endpoints"
|
||||
ui/components → parent: "ui", child: "components"
|
||||
core/auth → parent: "core", child: "auth"
|
||||
```
|
||||
|
||||
**Multi-Scope Handling:**
|
||||
```bash
|
||||
# Comma-separated scopes
|
||||
feat(api,docs): add endpoint → scopes: ["api", "docs"]
|
||||
fix(ui, ux): button alignment → scopes: ["ui", "ux"]
|
||||
```
|
||||
|
||||
### 4. Scope Analysis Categories
|
||||
|
||||
**A. Frequency Analysis**
|
||||
```json
|
||||
{
|
||||
"scope": "auth",
|
||||
"count": 23,
|
||||
"percentage": 18.1,
|
||||
"first_seen": "2024-01-15",
|
||||
"last_seen": "2024-03-10",
|
||||
"active": true
|
||||
}
|
||||
```
|
||||
|
||||
**B. Scope Hierarchy**
|
||||
```json
|
||||
{
|
||||
"api": {
|
||||
"count": 45,
|
||||
"children": {
|
||||
"endpoints": 12,
|
||||
"middleware": 8,
|
||||
"validation": 6
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**C. Scope Categories**
|
||||
```
|
||||
Architecture: core, utils, config
|
||||
Features: auth, payment, search
|
||||
UI: ui, components, styles
|
||||
Backend: api, db, server
|
||||
Infrastructure: ci, docker, deploy
|
||||
Documentation: docs, readme, changelog
|
||||
Testing: test, e2e, unit
|
||||
```
|
||||
|
||||
### 5. Output Structure
|
||||
|
||||
**Text Format (default):**
|
||||
```
|
||||
Scope Extraction Analysis
|
||||
=========================
|
||||
|
||||
Commits Analyzed: 50
|
||||
Branch: main
|
||||
Scopes Found: 15 unique
|
||||
Total Scoped Commits: 44/50 (88%)
|
||||
|
||||
TOP SCOPES BY FREQUENCY
|
||||
-----------------------
|
||||
1. auth 23 (18.1%) ████████████████████
|
||||
└─ Authentication and authorization
|
||||
|
||||
2. api 19 (14.9%) ████████████████
|
||||
├─ endpoints 7
|
||||
├─ middleware 5
|
||||
└─ validation 3
|
||||
|
||||
3. ui 15 (11.8%) █████████████
|
||||
├─ components 8
|
||||
└─ styles 4
|
||||
|
||||
4. db 12 (9.4%) ██████████
|
||||
└─ Database operations
|
||||
|
||||
5. docs 11 (8.7%) █████████
|
||||
└─ Documentation
|
||||
|
||||
6. core 8 (6.3%) ███████
|
||||
└─ Core functionality
|
||||
|
||||
7. config 7 (5.5%) ██████
|
||||
└─ Configuration
|
||||
|
||||
8. test 6 (4.7%) █████
|
||||
└─ Testing
|
||||
|
||||
9. ci 5 (3.9%) ████
|
||||
└─ CI/CD pipelines
|
||||
|
||||
10. deploy 4 (3.1%) ███
|
||||
└─ Deployment
|
||||
|
||||
SCOPE CATEGORIES
|
||||
----------------
|
||||
Features (45%): auth, payment, search
|
||||
Backend (32%): api, db, server
|
||||
UI (19%): ui, components, styles
|
||||
Infrastructure (12%): ci, docker, deploy
|
||||
Documentation (8%): docs, readme
|
||||
|
||||
SCOPE PATTERNS
|
||||
--------------
|
||||
Naming Style: lowercase, hyphen-separated
|
||||
Hierarchy: Uses / for nested scopes (api/endpoints)
|
||||
Multi-Scope: Occasional (3% of commits)
|
||||
Active Scopes: 12/15 (used in last 10 commits)
|
||||
Deprecated: payment-v1, legacy-api
|
||||
|
||||
RECOMMENDATIONS
|
||||
---------------
|
||||
• Use 'auth' for authentication/authorization changes
|
||||
• Use 'api' for backend API modifications
|
||||
• Use 'ui' for user interface changes
|
||||
• Consider hierarchical scopes for complex modules (api/endpoints)
|
||||
• Active scopes: auth, api, ui, db, docs, core, config
|
||||
• Avoid deprecated: payment-v1, legacy-api
|
||||
|
||||
RECENT SCOPE USAGE (last 10 commits)
|
||||
------------------------------------
|
||||
auth ████ (4 commits)
|
||||
api ███ (3 commits)
|
||||
ui ██ (2 commits)
|
||||
docs █ (1 commit)
|
||||
```
|
||||
|
||||
**JSON Format:**
|
||||
```json
|
||||
{
|
||||
"analysis_type": "scope_extraction",
|
||||
"commits_analyzed": 50,
|
||||
"branch": "main",
|
||||
"statistics": {
|
||||
"total_scopes": 15,
|
||||
"scoped_commits": 44,
|
||||
"scoped_percentage": 88,
|
||||
"active_scopes": 12,
|
||||
"deprecated_scopes": 2
|
||||
},
|
||||
"scopes": [
|
||||
{
|
||||
"name": "auth",
|
||||
"count": 23,
|
||||
"percentage": 18.1,
|
||||
"category": "feature",
|
||||
"description": "Authentication and authorization",
|
||||
"hierarchy": null,
|
||||
"first_seen": "2024-01-15",
|
||||
"last_seen": "2024-03-10",
|
||||
"active": true,
|
||||
"recent_usage": 4,
|
||||
"examples": [
|
||||
"feat(auth): implement OAuth2",
|
||||
"fix(auth): session timeout",
|
||||
"refactor(auth): simplify middleware"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "api",
|
||||
"count": 19,
|
||||
"percentage": 14.9,
|
||||
"category": "backend",
|
||||
"description": "API endpoints and logic",
|
||||
"hierarchy": {
|
||||
"endpoints": 7,
|
||||
"middleware": 5,
|
||||
"validation": 3
|
||||
},
|
||||
"active": true,
|
||||
"recent_usage": 3
|
||||
}
|
||||
],
|
||||
"categories": {
|
||||
"feature": {"count": 45, "percentage": 45},
|
||||
"backend": {"count": 32, "percentage": 32},
|
||||
"ui": {"count": 19, "percentage": 19}
|
||||
},
|
||||
"patterns": {
|
||||
"naming_style": "lowercase_hyphen",
|
||||
"uses_hierarchy": true,
|
||||
"uses_multi_scope": true,
|
||||
"multi_scope_percentage": 3
|
||||
},
|
||||
"recommendations": [
|
||||
"Use 'auth' for authentication/authorization changes",
|
||||
"Use 'api' for backend API modifications",
|
||||
"Consider hierarchical scopes for complex modules"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Scope Categorization Logic
|
||||
|
||||
**Category Detection:**
|
||||
```python
|
||||
def categorize_scope(scope_name, usage_patterns):
|
||||
"""Categorize scope based on name and usage"""
|
||||
|
||||
# Authentication/Authorization
|
||||
if scope_name in ['auth', 'security', 'login', 'oauth']:
|
||||
return 'feature', 'Authentication'
|
||||
|
||||
# API/Backend
|
||||
if scope_name in ['api', 'endpoint', 'backend', 'server']:
|
||||
return 'backend', 'API and backend'
|
||||
|
||||
# UI/Frontend
|
||||
if scope_name in ['ui', 'component', 'style', 'frontend']:
|
||||
return 'ui', 'User interface'
|
||||
|
||||
# Database
|
||||
if scope_name in ['db', 'database', 'schema', 'migration']:
|
||||
return 'backend', 'Database'
|
||||
|
||||
# Infrastructure
|
||||
if scope_name in ['ci', 'cd', 'deploy', 'docker', 'k8s']:
|
||||
return 'infrastructure', 'Infrastructure'
|
||||
|
||||
# Documentation
|
||||
if scope_name in ['docs', 'readme', 'changelog']:
|
||||
return 'documentation', 'Documentation'
|
||||
|
||||
# Testing
|
||||
if scope_name in ['test', 'e2e', 'unit', 'integration']:
|
||||
return 'testing', 'Testing'
|
||||
|
||||
# Default
|
||||
return 'other', 'Other'
|
||||
```
|
||||
|
||||
### 7. Trend Analysis
|
||||
|
||||
**Activity Tracking:**
|
||||
```
|
||||
Scope Activity Timeline (last 30 days):
|
||||
|
||||
auth: ████████████████ (very active)
|
||||
api: ████████████ (active)
|
||||
ui: ████████ (moderate)
|
||||
db: ████ (low)
|
||||
test: ██ (occasional)
|
||||
docs: █ (rare)
|
||||
```
|
||||
|
||||
**Deprecated Scope Detection:**
|
||||
```python
|
||||
def is_deprecated(scope):
|
||||
"""Detect if scope is deprecated"""
|
||||
# Not used in last 20 commits
|
||||
if scope.last_seen_commit_index > 20:
|
||||
return True
|
||||
|
||||
# Explicitly marked as deprecated
|
||||
if 'legacy' in scope.name or 'v1' in scope.name:
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**No scopes found:**
|
||||
- Warning: "No scopes detected in commit history"
|
||||
- Suggestion: "Project may not use conventional commits format"
|
||||
- Return: Empty scope list with explanation
|
||||
|
||||
**Minimal scopes:**
|
||||
- Warning: "Only X scopes found with min_frequency threshold"
|
||||
- Suggestion: "Lower min_frequency or analyze more commits"
|
||||
|
||||
**Malformed scopes:**
|
||||
- Skip invalid entries
|
||||
- Log: "Skipped N malformed scope entries"
|
||||
- Continue with valid scopes
|
||||
|
||||
## Integration Usage
|
||||
|
||||
**By commit-assistant agent:**
|
||||
```
|
||||
User modifies auth files:
|
||||
→ Invoke: /history-analysis extract-scopes
|
||||
→ Find: 'auth' is common scope (18.1%)
|
||||
→ Suggest: Use 'auth' scope for this commit
|
||||
```
|
||||
|
||||
**By message-generation skill:**
|
||||
```
|
||||
Generating commit message:
|
||||
→ Extract scopes from history
|
||||
→ Check if current files match known scopes
|
||||
→ Auto-suggest appropriate scope
|
||||
```
|
||||
|
||||
**By identify-scope operation:**
|
||||
```
|
||||
Unknown scope needed:
|
||||
→ Check extracted scopes
|
||||
→ Find similar/related scopes
|
||||
→ Recommend best match
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Operation succeeds when:
|
||||
- [x] All scopes extracted from commits
|
||||
- [x] Frequencies calculated correctly
|
||||
- [x] Hierarchies identified
|
||||
- [x] Categories assigned accurately
|
||||
- [x] Active/deprecated status determined
|
||||
- [x] Recommendations generated
|
||||
- [x] Output formatted properly
|
||||
|
||||
## Performance
|
||||
|
||||
- **Extraction Time:** ~1-2 seconds for 50 commits
|
||||
- **Regex Matching:** ~0.02ms per commit
|
||||
- **Memory:** Low (scope hash table only)
|
||||
586
commands/history-analysis/learn-project.md
Normal file
586
commands/history-analysis/learn-project.md
Normal file
@@ -0,0 +1,586 @@
|
||||
# Operation: Learn Project
|
||||
|
||||
**Purpose:** Comprehensive project commit pattern learning - analyze all aspects of commit history to provide complete understanding of project conventions.
|
||||
|
||||
## Parameters
|
||||
|
||||
From `$ARGUMENTS` (after operation name):
|
||||
- `count:N` - Number of commits to analyze (default: 100)
|
||||
- `branch:name` - Branch to analyze (default: current branch)
|
||||
- `format:json|text` - Output format (default: text)
|
||||
- `save:path` - Save results to file (optional)
|
||||
- `full:true|false` - Include detailed breakdown (default: false)
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Validate Repository
|
||||
|
||||
```bash
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo "Error: Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git log -1 >/dev/null 2>&1; then
|
||||
echo "Error: No commit history found"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Execute Comprehensive Analysis
|
||||
|
||||
This operation orchestrates all other history-analysis operations for complete project learning:
|
||||
|
||||
**Phase 1: Style Analysis**
|
||||
```bash
|
||||
echo "Phase 1/4: Analyzing commit style..."
|
||||
./.scripts/style-analyzer.sh <count> <branch>
|
||||
```
|
||||
|
||||
**Phase 2: Pattern Detection**
|
||||
```bash
|
||||
echo "Phase 2/4: Detecting conventions..."
|
||||
./.scripts/pattern-detector.py --count <count> --branch <branch> --detailed
|
||||
```
|
||||
|
||||
**Phase 3: Scope Extraction**
|
||||
```bash
|
||||
echo "Phase 3/4: Extracting scopes..."
|
||||
./.scripts/scope-extractor.sh --count <count> --branch <branch> --min-frequency 2
|
||||
```
|
||||
|
||||
**Phase 4: Convention Recommendations**
|
||||
```bash
|
||||
echo "Phase 4/4: Generating recommendations..."
|
||||
./.scripts/convention-recommender.py --count <count> --branch <branch> --priority all
|
||||
```
|
||||
|
||||
### 3. Aggregate and Synthesize Results
|
||||
|
||||
Combine all analysis data into comprehensive project profile:
|
||||
|
||||
```python
|
||||
project_profile = {
|
||||
'metadata': {
|
||||
'project_name': get_repo_name(),
|
||||
'analysis_date': datetime.now(),
|
||||
'commits_analyzed': count,
|
||||
'branch': branch,
|
||||
'first_commit_date': get_first_commit_date(),
|
||||
'last_commit_date': get_last_commit_date()
|
||||
},
|
||||
'style': style_analysis_results,
|
||||
'patterns': pattern_detection_results,
|
||||
'scopes': scope_extraction_results,
|
||||
'recommendations': convention_recommendations,
|
||||
'confidence': calculate_confidence_score()
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Generate Project Profile
|
||||
|
||||
**Output Structure:**
|
||||
|
||||
```
|
||||
═══════════════════════════════════════════════════════════════
|
||||
PROJECT COMMIT PROFILE
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
Repository: git-commit-assistant
|
||||
Branch: main
|
||||
Analysis Date: 2024-03-10 14:30:00
|
||||
Commits Analyzed: 100 (from 2024-01-01 to 2024-03-10)
|
||||
|
||||
Overall Consistency Score: 85/100 (GOOD)
|
||||
Confidence Level: HIGH (100 commits analyzed)
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
📊 EXECUTIVE SUMMARY
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
✓ Project uses conventional commits consistently (87%)
|
||||
✓ Strong imperative mood usage (92%)
|
||||
✓ Good issue reference practice (67%)
|
||||
○ Moderate body usage (34%)
|
||||
○ Occasional breaking change documentation (8%)
|
||||
|
||||
Recommended Actions:
|
||||
1. Maintain conventional commits format
|
||||
2. Increase body usage for complex changes
|
||||
3. Standardize breaking change documentation
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
📝 COMMIT STYLE ANALYSIS
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
Format Distribution:
|
||||
Conventional Commits: 87% ████████████████████████░░░
|
||||
Simple Subject: 10% ███░░░░░░░░░░░░░░░░░░░░░░░
|
||||
Other: 3% █░░░░░░░░░░░░░░░░░░░░░░░░░
|
||||
|
||||
Subject Lines:
|
||||
Average Length: 47 characters (recommended: < 50)
|
||||
Standard Dev: 8 characters
|
||||
Exceeds 50 chars: 15% of commits
|
||||
|
||||
Length Distribution:
|
||||
30-40 chars: ████████ (35%)
|
||||
41-50 chars: ██████████ (42%)
|
||||
51-60 chars: ████ (15%)
|
||||
61+ chars: ██ (8%)
|
||||
|
||||
Body Usage:
|
||||
Has Body: 34% of commits
|
||||
Average Length: 120 characters
|
||||
Bullet Points: 89% of bodies
|
||||
Wrapping: 94% wrap at 72 chars
|
||||
|
||||
Footer Usage:
|
||||
Issue References: 67% ████████████████████░░░░░
|
||||
Breaking Changes: 8% ██░░░░░░░░░░░░░░░░░░░░░░
|
||||
Co-Authors: 2% ░░░░░░░░░░░░░░░░░░░░░░░░
|
||||
Signed-Off: 12% ███░░░░░░░░░░░░░░░░░░░░░
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🎯 COMMIT TYPE ANALYSIS
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
Type Distribution (from 87 conventional commits):
|
||||
|
||||
1. feat 35% ████████████████████ (30 commits)
|
||||
└─ New features and capabilities
|
||||
|
||||
2. fix 30% ████████████████░ (26 commits)
|
||||
└─ Bug fixes and corrections
|
||||
|
||||
3. docs 16% █████████░ (14 commits)
|
||||
└─ Documentation updates
|
||||
|
||||
4. refactor 8% ████░ (7 commits)
|
||||
└─ Code restructuring
|
||||
|
||||
5. test 5% ███░ (4 commits)
|
||||
└─ Test additions/updates
|
||||
|
||||
6. chore 4% ██░ (3 commits)
|
||||
└─ Maintenance tasks
|
||||
|
||||
7. perf 2% █░ (2 commits)
|
||||
└─ Performance improvements
|
||||
|
||||
Type Usage Timeline (last 20 commits):
|
||||
feat: ████████ (8 commits)
|
||||
fix: ██████ (6 commits)
|
||||
docs: ███ (3 commits)
|
||||
refactor: ██ (2 commits)
|
||||
chore: █ (1 commit)
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🎨 SCOPE ANALYSIS
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
Scopes Found: 15 unique
|
||||
Scoped Commits: 88% (76/87 conventional commits)
|
||||
|
||||
Top Scopes by Frequency:
|
||||
|
||||
1. auth 23% ████████████████████ (20 commits)
|
||||
Category: Authentication
|
||||
Status: ACTIVE (used in last 10 commits)
|
||||
Examples:
|
||||
• feat(auth): implement OAuth2 authentication
|
||||
• fix(auth): handle session timeout correctly
|
||||
• refactor(auth): simplify middleware logic
|
||||
|
||||
2. api 19% ████████████████ (17 commits)
|
||||
Category: Backend
|
||||
Status: ACTIVE
|
||||
Hierarchy: api/endpoints (7), api/middleware (5), api/validation (3)
|
||||
|
||||
3. ui 15% █████████████ (13 commits)
|
||||
Category: Frontend
|
||||
Status: ACTIVE
|
||||
Hierarchy: ui/components (8), ui/styles (4)
|
||||
|
||||
4. db 12% ██████████ (10 commits)
|
||||
Category: Database
|
||||
Status: ACTIVE
|
||||
|
||||
5. docs 11% █████████ (9 commits)
|
||||
Category: Documentation
|
||||
Status: ACTIVE
|
||||
|
||||
6-15. (core, config, test, ci, deploy, utils, types, scripts, docker, nginx)
|
||||
Combined: 20% (17 commits)
|
||||
|
||||
Scope Categories:
|
||||
Features: 45% (auth, payment, search, notifications)
|
||||
Backend: 32% (api, db, server, cache)
|
||||
Frontend: 19% (ui, components, styles)
|
||||
Infrastructure: 12% (ci, docker, deploy, nginx)
|
||||
Documentation: 11% (docs, readme, changelog)
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🔍 CONVENTION PATTERNS
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
Writing Style:
|
||||
Imperative Mood: 92% ██████████████████████░░
|
||||
Capitalized Subject: 94% ██████████████████████░░
|
||||
No Period at End: 88% ████████████████████░░░
|
||||
Lowercase Scopes: 100% ████████████████████████
|
||||
|
||||
Message Structure:
|
||||
Blank Line Before Body: 100% (all 34 bodies)
|
||||
Body Wrapped at 72: 94% (32/34 bodies)
|
||||
Bullet Points in Body: 89% (30/34 bodies)
|
||||
Footer Separated: 100% (all 67 footers)
|
||||
|
||||
Issue References:
|
||||
Format: "Closes #123" 45% ████████████
|
||||
Format: "Fixes #456" 38% ██████████
|
||||
Format: "Refs #789" 17% █████
|
||||
|
||||
Breaking Changes:
|
||||
Format: "BREAKING CHANGE:" 100% (all 7 instances)
|
||||
Always in footer: 100%
|
||||
Includes description: 100%
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
💡 RECOMMENDATIONS (PRIORITIZED)
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
🔴 HIGH PRIORITY (Critical for Consistency)
|
||||
|
||||
1. ✓ Continue Using Conventional Commits
|
||||
Current: 87% adoption
|
||||
Target: Maintain 85%+
|
||||
Impact: HIGH - Enables automation
|
||||
|
||||
2. ✓ Maintain Imperative Mood
|
||||
Current: 92% compliance
|
||||
Target: Maintain 90%+
|
||||
Impact: HIGH - Readability and clarity
|
||||
|
||||
🟡 MEDIUM PRIORITY (Improve Quality)
|
||||
|
||||
3. ○ Increase Body Usage for Complex Changes
|
||||
Current: 34% of commits
|
||||
Target: 50% for multi-file changes
|
||||
Impact: MEDIUM - Better documentation
|
||||
|
||||
When to add body:
|
||||
• Changes affect >3 files
|
||||
• Complex logic modifications
|
||||
• Breaking changes
|
||||
• Security-related changes
|
||||
|
||||
4. ○ Document Breaking Changes Consistently
|
||||
Current: 8% when applicable
|
||||
Target: 100% of breaking changes documented
|
||||
Impact: MEDIUM - User experience
|
||||
|
||||
🟢 LOW PRIORITY (Polish)
|
||||
|
||||
5. ○ Consider Co-Author Attribution
|
||||
Current: 2% usage
|
||||
Target: Use for pair programming
|
||||
Impact: LOW - Team recognition
|
||||
|
||||
6. ○ Add Signed-off-by for Compliance
|
||||
Current: 12% usage
|
||||
Target: If required by project policy
|
||||
Impact: LOW - Legal compliance
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
📚 PROJECT-SPECIFIC STYLE GUIDE
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
COMMIT MESSAGE FORMAT
|
||||
---------------------
|
||||
<type>(<scope>): <subject> ← 50 chars max, imperative mood
|
||||
|
||||
<body> ← Optional, explain "why"
|
||||
- Use bullet points ← Wrap at 72 characters
|
||||
- Multiple lines OK
|
||||
- Blank line before footer
|
||||
|
||||
<footer> ← Optional
|
||||
BREAKING CHANGE: description
|
||||
Closes #123
|
||||
|
||||
APPROVED TYPES (use these)
|
||||
--------------------------
|
||||
feat - New feature (35% of project commits)
|
||||
fix - Bug fix (30% of project commits)
|
||||
docs - Documentation (16% of project commits)
|
||||
refactor - Code restructuring (8%)
|
||||
test - Testing (5%)
|
||||
chore - Maintenance (4%)
|
||||
perf - Performance (2%)
|
||||
|
||||
STANDARD SCOPES (project-specific)
|
||||
----------------------------------
|
||||
auth - Authentication/authorization
|
||||
api - Backend API endpoints
|
||||
ui - User interface
|
||||
db - Database operations
|
||||
docs - Documentation
|
||||
core - Core functionality
|
||||
config - Configuration
|
||||
test - Testing infrastructure
|
||||
ci - CI/CD pipelines
|
||||
deploy - Deployment
|
||||
|
||||
STYLE RULES
|
||||
-----------
|
||||
✓ Use imperative mood ("add" not "added")
|
||||
✓ Capitalize first letter of subject
|
||||
✓ No period at end of subject line
|
||||
✓ Use lowercase for scopes
|
||||
✓ Wrap body at 72 characters
|
||||
✓ Separate body and footer with blank line
|
||||
✓ Use bullet points in body (with - or •)
|
||||
✓ Reference issues: "Closes #123", "Fixes #456"
|
||||
✓ Document breaking changes in footer
|
||||
|
||||
REAL EXAMPLES FROM THIS PROJECT
|
||||
--------------------------------
|
||||
Example 1: Feature with body
|
||||
feat(auth): implement OAuth2 authentication
|
||||
|
||||
- Add OAuth2 flow implementation
|
||||
- Support Google and GitHub providers
|
||||
- Include middleware for route protection
|
||||
- Add configuration management
|
||||
|
||||
Closes #123
|
||||
|
||||
Example 2: Bug fix
|
||||
fix(api): handle null pointer in user endpoint
|
||||
|
||||
The endpoint was not checking for null user objects
|
||||
before accessing properties, causing crashes when
|
||||
invalid user IDs were provided.
|
||||
|
||||
Fixes #456
|
||||
|
||||
Example 3: Breaking change
|
||||
feat(api): change authentication flow
|
||||
|
||||
Update authentication to use OAuth2 tokens instead
|
||||
of API keys for improved security.
|
||||
|
||||
BREAKING CHANGE: API now requires OAuth tokens
|
||||
instead of API keys. Update all client applications
|
||||
to use the new authentication flow.
|
||||
|
||||
Closes #789
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
🔧 IMPLEMENTATION GUIDE
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
1. SHARE WITH TEAM
|
||||
• Add style guide to CONTRIBUTING.md
|
||||
• Present in team meeting
|
||||
• Add to onboarding docs
|
||||
|
||||
2. CONFIGURE GIT
|
||||
Create .gitmessage template:
|
||||
|
||||
# <type>(<scope>): <subject>
|
||||
#
|
||||
# <body>
|
||||
#
|
||||
# <footer>
|
||||
#
|
||||
# Types: feat, fix, docs, refactor, test, chore, perf
|
||||
# Scopes: auth, api, ui, db, docs, core, config
|
||||
|
||||
Then: git config commit.template .gitmessage
|
||||
|
||||
3. ADD PRE-COMMIT HOOKS
|
||||
Install commitlint:
|
||||
npm install --save-dev @commitlint/cli @commitlint/config-conventional
|
||||
|
||||
Configure commitlint.config.js:
|
||||
module.exports = {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
rules: {
|
||||
'scope-enum': [2, 'always', [
|
||||
'auth', 'api', 'ui', 'db', 'docs', 'core',
|
||||
'config', 'test', 'ci', 'deploy'
|
||||
]]
|
||||
}
|
||||
};
|
||||
|
||||
4. ENABLE AUTOMATION
|
||||
• Automated changelog: standard-version
|
||||
• Semantic versioning: semantic-release
|
||||
• Commit linting: commitlint + husky
|
||||
|
||||
5. MONITOR COMPLIANCE
|
||||
Run this analysis monthly:
|
||||
/history-analysis learn-project count:100
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
📈 CONFIDENCE ASSESSMENT
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
Data Quality: ████████████████████████ HIGH
|
||||
Sample Size: 100 commits ✓ Sufficient
|
||||
Time Range: 70 days ✓ Representative
|
||||
Consistency: 85/100 ✓ Good
|
||||
Pattern Clarity: ████████████████████████ HIGH
|
||||
|
||||
Confidence Level: HIGH
|
||||
|
||||
This analysis is reliable for:
|
||||
✓ Establishing project guidelines
|
||||
✓ Onboarding new developers
|
||||
✓ Configuring automation tools
|
||||
✓ Team discussions and decisions
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
💾 SAVE OPTIONS
|
||||
═══════════════════════════════════════════════════════════════
|
||||
|
||||
This analysis can be saved for reference:
|
||||
/history-analysis learn-project save:docs/commit-conventions.md
|
||||
|
||||
Or export as JSON for tooling:
|
||||
/history-analysis learn-project format:json save:commit-profile.json
|
||||
|
||||
═══════════════════════════════════════════════════════════════
|
||||
Analysis Complete - Ready to Apply
|
||||
═══════════════════════════════════════════════════════════════
|
||||
```
|
||||
|
||||
### 5. Save to File (if requested)
|
||||
|
||||
If `save:path` parameter provided:
|
||||
|
||||
```bash
|
||||
# Save text format
|
||||
echo "$output" > "$save_path"
|
||||
|
||||
# Save JSON format
|
||||
echo "$json_output" > "$save_path"
|
||||
|
||||
echo "✓ Analysis saved to: $save_path"
|
||||
```
|
||||
|
||||
### 6. JSON Output Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"project_name": "git-commit-assistant",
|
||||
"analysis_date": "2024-03-10T14:30:00Z",
|
||||
"commits_analyzed": 100,
|
||||
"branch": "main",
|
||||
"date_range": {
|
||||
"first_commit": "2024-01-01",
|
||||
"last_commit": "2024-03-10"
|
||||
}
|
||||
},
|
||||
"scores": {
|
||||
"overall_consistency": 85,
|
||||
"style_consistency": 87,
|
||||
"pattern_consistency": 92,
|
||||
"content_consistency": 67,
|
||||
"confidence": "high"
|
||||
},
|
||||
"style_analysis": {
|
||||
"conventional_commits_percentage": 87,
|
||||
"average_subject_length": 47,
|
||||
"body_usage_percentage": 34,
|
||||
"footer_usage_percentage": 67
|
||||
},
|
||||
"types": [...],
|
||||
"scopes": [...],
|
||||
"patterns": {...},
|
||||
"recommendations": {
|
||||
"high_priority": [...],
|
||||
"medium_priority": [...],
|
||||
"low_priority": [...]
|
||||
},
|
||||
"style_guide": {
|
||||
"format": "<type>(<scope>): <subject>",
|
||||
"types": [...],
|
||||
"scopes": [...],
|
||||
"rules": [...]
|
||||
},
|
||||
"examples": [...],
|
||||
"automation": {
|
||||
"commitlint_config": {...},
|
||||
"changelog_generator": "standard-version",
|
||||
"semantic_release": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**No git repository:**
|
||||
- Error: "Not in a git repository"
|
||||
- Guidance: Run from within git project directory
|
||||
|
||||
**Insufficient commits:**
|
||||
- Warning: "Only X commits available (recommended: 50+)"
|
||||
- Adjust: Analyze all available commits
|
||||
- Note: Lower confidence level
|
||||
|
||||
**Analysis failure:**
|
||||
- Partial results: Return what was successfully analyzed
|
||||
- Error details: Indicate which phase failed
|
||||
- Retry: Suggest re-running with different parameters
|
||||
|
||||
## Integration Usage
|
||||
|
||||
**New project setup:**
|
||||
```
|
||||
Developer: "What are the commit conventions?"
|
||||
→ Run: /history-analysis learn-project
|
||||
→ Get: Complete style guide
|
||||
→ Configure: Git template and hooks
|
||||
```
|
||||
|
||||
**Team standardization:**
|
||||
```
|
||||
Lead: "Let's review our commit practices"
|
||||
→ Run: /history-analysis learn-project save:docs/conventions.md
|
||||
→ Review: Recommendations with team
|
||||
→ Implement: Top priorities
|
||||
→ Document: In CONTRIBUTING.md
|
||||
```
|
||||
|
||||
**Automation setup:**
|
||||
```
|
||||
DevOps: "Configure commit validation"
|
||||
→ Run: /history-analysis learn-project format:json
|
||||
→ Extract: Approved types and scopes
|
||||
→ Configure: commitlint with project rules
|
||||
→ Deploy: Pre-commit hooks
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Operation succeeds when:
|
||||
- [x] All 4 analysis phases complete
|
||||
- [x] Results aggregated correctly
|
||||
- [x] Comprehensive profile generated
|
||||
- [x] Recommendations prioritized
|
||||
- [x] Style guide created
|
||||
- [x] Examples included
|
||||
- [x] Implementation guidance provided
|
||||
- [x] Confidence level assessed
|
||||
|
||||
## Performance
|
||||
|
||||
- **Phase 1 (Style):** ~2 seconds
|
||||
- **Phase 2 (Patterns):** ~3 seconds
|
||||
- **Phase 3 (Scopes):** ~2 seconds
|
||||
- **Phase 4 (Recommendations):** ~1 second
|
||||
- **Total:** ~8-10 seconds for 100 commits
|
||||
118
commands/history-analysis/skill.md
Normal file
118
commands/history-analysis/skill.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
description: Analyze git history to learn project's commit style and conventions
|
||||
---
|
||||
|
||||
# History Analysis Skill
|
||||
|
||||
**Purpose:** Analyze git commit history to learn project-specific commit patterns, conventions, scope usage, and message styles. Provides intelligent recommendations that match the team's existing practices.
|
||||
|
||||
## Router
|
||||
|
||||
Parse `$ARGUMENTS` to determine which history analysis operation to execute:
|
||||
|
||||
**Available Operations:**
|
||||
- `analyze-style` - Learn commit style from recent history
|
||||
- `detect-patterns` - Identify project-specific conventions
|
||||
- `extract-scopes` - Discover commonly used scopes
|
||||
- `suggest-conventions` - Recommend conventions based on history
|
||||
- `learn-project` - Comprehensive project pattern learning
|
||||
- `learn` - Alias for learn-project (full analysis)
|
||||
|
||||
**Base Directory:** `/home/danie/projects/plugins/architect/open-plugins/plugins/git-commit-assistant/commands/history-analysis`
|
||||
|
||||
## Routing Logic
|
||||
|
||||
```
|
||||
Request: $ARGUMENTS
|
||||
Parse: operation = first word, parameters = remainder
|
||||
|
||||
If operation is:
|
||||
- "analyze-style" → Read "./analyze-style.md" with parameters
|
||||
- "detect-patterns" → Read "./detect-patterns.md" with parameters
|
||||
- "extract-scopes" → Read "./extract-scopes.md" with parameters
|
||||
- "suggest-conventions" → Read "./suggest-conventions.md" with parameters
|
||||
- "learn-project" or "learn" → Read "./learn-project.md" with parameters
|
||||
- empty or unknown → Display usage information
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
```bash
|
||||
# Analyze commit style from recent history
|
||||
/history-analysis analyze-style
|
||||
|
||||
# Analyze with custom commit count
|
||||
/history-analysis analyze-style count:100
|
||||
|
||||
# Detect project conventions
|
||||
/history-analysis detect-patterns
|
||||
|
||||
# Extract common scopes
|
||||
/history-analysis extract-scopes
|
||||
|
||||
# Get convention recommendations
|
||||
/history-analysis suggest-conventions
|
||||
|
||||
# Full project learning (comprehensive analysis)
|
||||
/history-analysis learn-project
|
||||
|
||||
# Short alias for full learning
|
||||
/history-analysis learn
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
All operations support these optional parameters:
|
||||
- `count:N` - Number of commits to analyze (default: 50)
|
||||
- `branch:name` - Branch to analyze (default: current branch)
|
||||
- `format:json|text` - Output format (default: text)
|
||||
|
||||
## Integration Points
|
||||
|
||||
This skill is designed to be invoked by:
|
||||
- **commit-assistant agent** - Learn project conventions before generating messages
|
||||
- **message-generation skill** - Validate messages against project style
|
||||
- **User commands** - Understand project commit patterns
|
||||
|
||||
## Error Handling
|
||||
|
||||
If not in a git repository:
|
||||
- Return error: "Not in a git repository. Please run this command from within a git project."
|
||||
|
||||
If no commit history exists:
|
||||
- Return error: "No commit history found. This appears to be a new repository."
|
||||
|
||||
If git command fails:
|
||||
- Return error with git error message and troubleshooting guidance
|
||||
|
||||
## Output Structure
|
||||
|
||||
All operations return structured data including:
|
||||
- **Analysis results** - Patterns, frequencies, statistics
|
||||
- **Recommendations** - Project-specific guidance
|
||||
- **Examples** - Sample commits from project
|
||||
- **Confidence score** - How reliable the analysis is
|
||||
|
||||
---
|
||||
|
||||
**Execution:**
|
||||
|
||||
1. Parse `$ARGUMENTS` to extract operation and parameters
|
||||
2. Validate git repository exists
|
||||
3. Read and execute the appropriate operation file
|
||||
4. Return structured results
|
||||
|
||||
If operation is unrecognized, display:
|
||||
```
|
||||
Unknown operation: {operation}
|
||||
|
||||
Available operations:
|
||||
analyze-style - Analyze commit message style
|
||||
detect-patterns - Detect project conventions
|
||||
extract-scopes - Extract common scopes
|
||||
suggest-conventions - Get convention recommendations
|
||||
learn-project - Full project pattern learning
|
||||
|
||||
Usage: /history-analysis <operation> [parameters]
|
||||
Example: /history-analysis analyze-style count:100
|
||||
```
|
||||
431
commands/history-analysis/suggest-conventions.md
Normal file
431
commands/history-analysis/suggest-conventions.md
Normal file
@@ -0,0 +1,431 @@
|
||||
# Operation: Suggest Conventions
|
||||
|
||||
**Purpose:** Generate project-specific commit message convention recommendations based on historical analysis and best practices.
|
||||
|
||||
## Parameters
|
||||
|
||||
From `$ARGUMENTS` (after operation name):
|
||||
- `count:N` - Number of commits to analyze (default: 50)
|
||||
- `branch:name` - Branch to analyze (default: current branch)
|
||||
- `format:json|text` - Output format (default: text)
|
||||
- `include_examples:true|false` - Include example commits (default: true)
|
||||
- `priority:high|medium|low|all` - Filter by recommendation priority (default: all)
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Validate Repository
|
||||
|
||||
```bash
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
echo "Error: Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### 2. Gather Historical Data
|
||||
|
||||
Execute analysis operations to collect data:
|
||||
|
||||
**A. Style Analysis:**
|
||||
```bash
|
||||
./.scripts/style-analyzer.sh <count> <branch>
|
||||
```
|
||||
|
||||
**B. Pattern Detection:**
|
||||
```bash
|
||||
./.scripts/pattern-detector.py --count <count> --branch <branch>
|
||||
```
|
||||
|
||||
**C. Scope Extraction:**
|
||||
```bash
|
||||
./.scripts/scope-extractor.sh --count <count> --branch <branch>
|
||||
```
|
||||
|
||||
### 3. Execute Convention Recommender
|
||||
|
||||
Invoke the convention-recommender.py utility script:
|
||||
|
||||
```bash
|
||||
./.scripts/convention-recommender.py --count <count> --branch <branch> --priority <priority>
|
||||
```
|
||||
|
||||
The script will:
|
||||
- Analyze aggregated historical data
|
||||
- Identify current conventions and gaps
|
||||
- Generate recommendations by priority
|
||||
- Provide examples and implementation guidance
|
||||
- Create project-specific guidelines
|
||||
|
||||
### 4. Recommendation Categories
|
||||
|
||||
**A. Format Recommendations**
|
||||
- Commit message structure
|
||||
- Subject line format
|
||||
- Body organization
|
||||
- Footer conventions
|
||||
|
||||
**B. Type Recommendations**
|
||||
- Commonly used types
|
||||
- Type selection guidance
|
||||
- Project-specific type meanings
|
||||
|
||||
**C. Scope Recommendations**
|
||||
- Standard scopes for the project
|
||||
- Scope naming patterns
|
||||
- When to use each scope
|
||||
|
||||
**D. Content Recommendations**
|
||||
- Writing style (imperative mood, tense)
|
||||
- Capitalization and punctuation
|
||||
- Issue reference format
|
||||
- Breaking change documentation
|
||||
|
||||
**E. Process Recommendations**
|
||||
- Pre-commit validation
|
||||
- Atomicity guidelines
|
||||
- Review practices
|
||||
|
||||
### 5. Recommendation Priority Levels
|
||||
|
||||
**HIGH Priority (Critical for consistency):**
|
||||
- Adopt conventional commits if not using (< 50% usage)
|
||||
- Fix major inconsistencies (> 30% deviation)
|
||||
- Establish missing critical patterns
|
||||
|
||||
**MEDIUM Priority (Improve quality):**
|
||||
- Refine existing patterns (50-80% consistency)
|
||||
- Add missing optional elements
|
||||
- Enhance documentation practices
|
||||
|
||||
**LOW Priority (Nice-to-have):**
|
||||
- Fine-tune minor details
|
||||
- Advanced features (co-authors, trailers)
|
||||
- Optimization opportunities
|
||||
|
||||
### 6. Output Structure
|
||||
|
||||
**Text Format (default):**
|
||||
```
|
||||
Project-Specific Commit Convention Recommendations
|
||||
==================================================
|
||||
|
||||
Analysis: 50 commits on branch 'main'
|
||||
Current Consistency: 85/100 (GOOD)
|
||||
Generated: 2024-03-10
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🔴 HIGH PRIORITY RECOMMENDATIONS
|
||||
|
||||
1. Continue Using Conventional Commits
|
||||
Status: ✓ Already adopted (87% usage)
|
||||
Action: Maintain current practice
|
||||
Benefit: Enables automated changelog, semantic versioning
|
||||
|
||||
Format: <type>(<scope>): <subject>
|
||||
Example from project:
|
||||
✓ feat(auth): implement OAuth2 authentication
|
||||
✓ fix(api): handle null pointer in user endpoint
|
||||
|
||||
2. Standardize Subject Line Length
|
||||
Status: ○ Needs improvement (avg: 47 chars, σ=12)
|
||||
Action: Keep subject lines under 50 characters
|
||||
Current: 15% exceed limit
|
||||
Target: < 5% exceed limit
|
||||
|
||||
✓ Good: "feat(auth): add OAuth provider support"
|
||||
✗ Too long: "feat(auth): implement OAuth2 authentication with support for multiple providers including Google and GitHub"
|
||||
✓ Better: "feat(auth): add OAuth multi-provider support"
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🟡 MEDIUM PRIORITY RECOMMENDATIONS
|
||||
|
||||
3. Increase Body Usage for Complex Changes
|
||||
Status: ○ Moderate usage (34% of commits)
|
||||
Action: Add body for non-trivial changes
|
||||
Benefit: Better context for code review and history
|
||||
|
||||
When to add body:
|
||||
• Multiple files changed (>3)
|
||||
• Complex logic changes
|
||||
• Breaking changes
|
||||
• Security-related changes
|
||||
|
||||
Example from project:
|
||||
feat(auth): implement OAuth2 authentication
|
||||
|
||||
- Add OAuth2 flow implementation
|
||||
- Support Google and GitHub providers
|
||||
- Include middleware for route protection
|
||||
- Add configuration management
|
||||
|
||||
4. Consistent Issue References
|
||||
Status: ✓ Good usage (67% of commits)
|
||||
Action: Reference issues consistently
|
||||
Current format: "Closes #123", "Fixes #456"
|
||||
Recommendation: Continue current practice
|
||||
|
||||
Patterns detected in project:
|
||||
✓ Closes #123 (45% of references)
|
||||
✓ Fixes #456 (38% of references)
|
||||
✓ Refs #789 (17% of references)
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🟢 LOW PRIORITY RECOMMENDATIONS
|
||||
|
||||
5. Consider Adding Co-Author Attribution
|
||||
Status: ✗ Rare usage (2% of commits)
|
||||
Action: Add co-authors for pair programming
|
||||
Format: Co-authored-by: Name <email>
|
||||
|
||||
Example:
|
||||
feat(api): add user management endpoint
|
||||
|
||||
Co-authored-by: Jane Doe <jane@example.com>
|
||||
|
||||
6. Document Breaking Changes Explicitly
|
||||
Status: ○ Occasional (8% of commits)
|
||||
Action: Use BREAKING CHANGE footer when applicable
|
||||
|
||||
Format:
|
||||
feat(api): change authentication flow
|
||||
|
||||
BREAKING CHANGE: API now requires OAuth tokens
|
||||
instead of API keys. Update client applications.
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📋 PROJECT-SPECIFIC STYLE GUIDE
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
COMMIT MESSAGE FORMAT
|
||||
---------------------
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
|
||||
TYPES (in order of frequency)
|
||||
------------------------------
|
||||
feat - New features (35% of commits)
|
||||
fix - Bug fixes (30% of commits)
|
||||
docs - Documentation (16% of commits)
|
||||
refactor - Code restructuring (8% of commits)
|
||||
test - Testing (5% of commits)
|
||||
chore - Maintenance (6% of commits)
|
||||
|
||||
COMMON SCOPES (use these)
|
||||
-------------------------
|
||||
auth - Authentication/authorization (18%)
|
||||
api - Backend API (15%)
|
||||
ui - User interface (12%)
|
||||
db - Database (9%)
|
||||
docs - Documentation (9%)
|
||||
config - Configuration (6%)
|
||||
|
||||
STYLE RULES (current project standards)
|
||||
----------------------------------------
|
||||
✓ Use imperative mood ("add" not "added")
|
||||
✓ Capitalize first letter of subject
|
||||
✓ No period at end of subject
|
||||
✓ Wrap body at 72 characters
|
||||
✓ Blank line between subject and body
|
||||
✓ Reference issues when applicable
|
||||
✓ Use bullet points in body
|
||||
|
||||
EXAMPLES FROM THIS PROJECT
|
||||
---------------------------
|
||||
feat(auth): implement OAuth2 authentication
|
||||
|
||||
- Add OAuth2 flow implementation
|
||||
- Support Google and GitHub providers
|
||||
- Include middleware for route protection
|
||||
|
||||
Closes #123
|
||||
|
||||
---
|
||||
|
||||
fix(api): handle null pointer in user endpoint
|
||||
|
||||
The endpoint was not checking for null user objects
|
||||
before accessing properties, causing crashes.
|
||||
|
||||
Fixes #456
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📊 CONSISTENCY METRICS
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Format: 87% ████████████████████████░░░
|
||||
Conventions: 92% ██████████████████████████░
|
||||
Content: 67% ███████████████████░░░░░░░░
|
||||
Overall: 85% █████████████████████░░░░░
|
||||
|
||||
NEXT STEPS
|
||||
----------
|
||||
1. Share this guide with team
|
||||
2. Add to CONTRIBUTING.md
|
||||
3. Configure git commit template
|
||||
4. Set up pre-commit hooks
|
||||
5. Review in team meeting
|
||||
|
||||
AUTOMATION OPPORTUNITIES
|
||||
-------------------------
|
||||
• Pre-commit hook to validate format
|
||||
• Automated changelog generation
|
||||
• Semantic version bumping
|
||||
• Commit message linting (commitlint)
|
||||
```
|
||||
|
||||
**JSON Format:**
|
||||
```json
|
||||
{
|
||||
"analysis_type": "convention_recommendations",
|
||||
"commits_analyzed": 50,
|
||||
"branch": "main",
|
||||
"consistency_score": 85,
|
||||
"generated_date": "2024-03-10",
|
||||
"recommendations": {
|
||||
"high_priority": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Continue Using Conventional Commits",
|
||||
"status": "good",
|
||||
"current_usage": 87,
|
||||
"target_usage": 90,
|
||||
"action": "Maintain current practice",
|
||||
"benefit": "Enables automated tooling",
|
||||
"examples": [
|
||||
"feat(auth): implement OAuth2 authentication",
|
||||
"fix(api): handle null pointer"
|
||||
]
|
||||
}
|
||||
],
|
||||
"medium_priority": [...],
|
||||
"low_priority": [...]
|
||||
},
|
||||
"style_guide": {
|
||||
"format": "<type>(<scope>): <subject>",
|
||||
"types": [
|
||||
{"name": "feat", "percentage": 35, "description": "New features"},
|
||||
{"name": "fix", "percentage": 30, "description": "Bug fixes"}
|
||||
],
|
||||
"scopes": [
|
||||
{"name": "auth", "percentage": 18, "description": "Authentication"},
|
||||
{"name": "api", "percentage": 15, "description": "Backend API"}
|
||||
],
|
||||
"rules": [
|
||||
"Use imperative mood",
|
||||
"Capitalize first letter",
|
||||
"No period at end"
|
||||
]
|
||||
},
|
||||
"automation": [
|
||||
"Pre-commit hook validation",
|
||||
"Automated changelog",
|
||||
"Semantic versioning"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Recommendation Generation Algorithm
|
||||
|
||||
```python
|
||||
def generate_recommendations(analysis_data):
|
||||
"""
|
||||
Generate prioritized recommendations based on analysis.
|
||||
"""
|
||||
recommendations = {
|
||||
'high_priority': [],
|
||||
'medium_priority': [],
|
||||
'low_priority': []
|
||||
}
|
||||
|
||||
# Check conventional commits usage
|
||||
if analysis_data['conventional_commits_pct'] < 50:
|
||||
recommendations['high_priority'].append({
|
||||
'title': 'Adopt Conventional Commits',
|
||||
'action': 'Migrate to conventional commits format',
|
||||
'reason': 'Low usage ({}%)'.format(
|
||||
analysis_data['conventional_commits_pct']
|
||||
)
|
||||
})
|
||||
elif analysis_data['conventional_commits_pct'] < 80:
|
||||
recommendations['medium_priority'].append({
|
||||
'title': 'Increase Conventional Commits Usage',
|
||||
'action': 'Encourage team to use format consistently'
|
||||
})
|
||||
|
||||
# Check subject line length
|
||||
avg_length = analysis_data['avg_subject_length']
|
||||
if avg_length > 60:
|
||||
recommendations['high_priority'].append({
|
||||
'title': 'Reduce Subject Line Length',
|
||||
'action': 'Keep subjects under 50 characters',
|
||||
'current': avg_length
|
||||
})
|
||||
|
||||
# Check imperative mood
|
||||
if analysis_data['imperative_mood_pct'] < 80:
|
||||
recommendations['high_priority'].append({
|
||||
'title': 'Use Imperative Mood Consistently',
|
||||
'action': 'Use "add" not "added", "fix" not "fixed"'
|
||||
})
|
||||
|
||||
# More checks...
|
||||
|
||||
return recommendations
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Insufficient data:**
|
||||
- Warning: "Limited data (< 20 commits), recommendations may be less accurate"
|
||||
- Provide recommendations with confidence scores
|
||||
|
||||
**No patterns detected:**
|
||||
- Return: "No clear patterns detected. Consider establishing conventions."
|
||||
- Suggest: Standard conventional commits format as starting point
|
||||
|
||||
**Mixed conventions:**
|
||||
- Identify: "Multiple convention styles detected (X% conventional, Y% other)"
|
||||
- Recommend: "Migrate to single consistent style"
|
||||
|
||||
## Integration Usage
|
||||
|
||||
**By commit-assistant agent:**
|
||||
```
|
||||
New developer onboarding:
|
||||
→ Invoke: /history-analysis suggest-conventions
|
||||
→ Present: Project-specific style guide
|
||||
→ Configure: Git commit template
|
||||
```
|
||||
|
||||
**By team lead:**
|
||||
```
|
||||
Improving consistency:
|
||||
→ Run: /history-analysis suggest-conventions
|
||||
→ Review: High-priority recommendations
|
||||
→ Implement: Top 3 improvements
|
||||
→ Document: In CONTRIBUTING.md
|
||||
```
|
||||
|
||||
## Success Criteria
|
||||
|
||||
Operation succeeds when:
|
||||
- [x] All analysis data gathered
|
||||
- [x] Recommendations prioritized correctly
|
||||
- [x] Style guide generated
|
||||
- [x] Examples provided
|
||||
- [x] Actionable guidance included
|
||||
- [x] Automation opportunities identified
|
||||
|
||||
## Performance
|
||||
|
||||
- **Analysis Time:** ~3-5 seconds for complete analysis
|
||||
- **Recommendation Generation:** ~1 second
|
||||
- **Total Time:** ~4-6 seconds
|
||||
Reference in New Issue
Block a user