Initial upload of auto-changelog-generator
This commit is contained in:
136
src/changeloggen/git_hooks.py
Normal file
136
src/changeloggen/git_hooks.py
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
|
||||||
|
|
||||||
|
class GitHookType:
|
||||||
|
PREPARE_COMMIT_MSG = "prepare-commit-msg"
|
||||||
|
COMMIT_MSG = "commit-msg"
|
||||||
|
|
||||||
|
|
||||||
|
def get_git_hooks_dir(repo_path: Optional[Path] = None) -> Path:
|
||||||
|
"""Get the git hooks directory for a repository."""
|
||||||
|
if repo_path is None:
|
||||||
|
repo_path = Path.cwd()
|
||||||
|
|
||||||
|
git_dir = repo_path / ".git"
|
||||||
|
hooks_dir = git_dir / "hooks"
|
||||||
|
return hooks_dir
|
||||||
|
|
||||||
|
|
||||||
|
def get_hook_script_path(hook_type: str, repo_path: Optional[Path] = None) -> Path:
|
||||||
|
"""Get the path for a specific hook script."""
|
||||||
|
hooks_dir = get_git_hooks_dir(repo_path)
|
||||||
|
return hooks_dir / hook_type
|
||||||
|
|
||||||
|
|
||||||
|
def install_prepare_hook(
|
||||||
|
repo_path: Optional[Path] = None,
|
||||||
|
model: str = "llama3.2",
|
||||||
|
branches: Optional[list[str]] = None
|
||||||
|
) -> Path:
|
||||||
|
"""Install prepare-commit-msg hook for automatic changelog generation."""
|
||||||
|
hook_path = get_hook_script_path(GitHookType.PREPARE_COMMIT_MSG, repo_path)
|
||||||
|
|
||||||
|
branches_str = ",".join(branches) if branches else "*"
|
||||||
|
|
||||||
|
hook_content = f'''#!/bin/bash
|
||||||
|
# Auto Changelog Generator - prepare-commit-msg hook
|
||||||
|
# Generated by changeloggen
|
||||||
|
|
||||||
|
CHANGELOGGEN_MODEL="{model}"
|
||||||
|
CHANGELOGGEN_BRANCHES="{branches_str}"
|
||||||
|
|
||||||
|
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
|
||||||
|
if [ "$CHANGELOGGEN_BRANCHES" != "*" ]; then
|
||||||
|
if ! echo "$CHANGELOGGEN_BRANCHES" | grep -q "$BRANCH_NAME"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
STAGED_FILES=$(git diff --cached --name-only)
|
||||||
|
if [ -z "$STAGED_FILES" ]; then
|
||||||
|
echo "No staged files found. Skipping changelog generation."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Generating changelog for commit on branch: $BRANCH_NAME"
|
||||||
|
python -m changeloggen generate --model "$CHANGELOGGEN_MODEL" --output commit-message
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
'''
|
||||||
|
|
||||||
|
return _write_hook(hook_path, hook_content)
|
||||||
|
|
||||||
|
|
||||||
|
def install_commit_msg_hook(
|
||||||
|
repo_path: Optional[Path] = None,
|
||||||
|
model: str = "llama3.2",
|
||||||
|
branches: Optional[list[str]] = None
|
||||||
|
) -> Path:
|
||||||
|
"""Install commit-msg hook for validating/updating commit messages."""
|
||||||
|
hook_path = get_hook_script_path(GitHookType.COMMIT_MSG, repo_path)
|
||||||
|
|
||||||
|
branches_str = ",".join(branches) if branches else "*"
|
||||||
|
|
||||||
|
hook_content = f'''#!/bin/bash
|
||||||
|
# Auto Changelog Generator - commit-msg hook
|
||||||
|
# Generated by changeloggen
|
||||||
|
|
||||||
|
CHANGELOGGEN_MODEL="{model}"
|
||||||
|
CHANGELOGGEN_BRANCHES="{branches_str}"
|
||||||
|
|
||||||
|
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
|
||||||
|
if [ "$CHANGELOGGEN_BRANCHES" != "*" ]; then
|
||||||
|
if ! echo "$CHANGELOGGEN_BRANCHES" | grep -q "$BRANCH_NAME"; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
'''
|
||||||
|
|
||||||
|
return _write_hook(hook_path, hook_content)
|
||||||
|
|
||||||
|
|
||||||
|
def _write_hook(hook_path: Path, content: str) -> Path:
|
||||||
|
"""Write hook script and make it executable."""
|
||||||
|
hook_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(hook_path, 'w') as f:
|
||||||
|
f.write(content)
|
||||||
|
|
||||||
|
os.chmod(hook_path, hook_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||||
|
|
||||||
|
return hook_path
|
||||||
|
|
||||||
|
|
||||||
|
def remove_hook(hook_type: str, repo_path: Optional[Path] = None) -> bool:
|
||||||
|
"""Remove a git hook."""
|
||||||
|
hook_path = get_hook_script_path(hook_type, repo_path)
|
||||||
|
|
||||||
|
if hook_path.exists():
|
||||||
|
hook_path.unlink()
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_hook_installed(hook_type: str, repo_path: Optional[Path] = None) -> bool:
|
||||||
|
"""Check if a hook is installed."""
|
||||||
|
hook_path = get_hook_script_path(hook_type, repo_path)
|
||||||
|
return hook_path.exists()
|
||||||
|
|
||||||
|
|
||||||
|
def list_installed_hooks(repo_path: Optional[Path] = None) -> list[str]:
|
||||||
|
"""List all installed changeloggen hooks."""
|
||||||
|
hooks = []
|
||||||
|
|
||||||
|
for hook_type in [GitHookType.PREPARE_COMMIT_MSG, GitHookType.COMMIT_MSG]:
|
||||||
|
if is_hook_installed(hook_type, repo_path):
|
||||||
|
hooks.append(hook_type)
|
||||||
|
|
||||||
|
return hooks
|
||||||
Reference in New Issue
Block a user