Update.
This commit is contained in:
parent
c61f895135
commit
25be023b70
16
CHANGELOG.md
16
CHANGELOG.md
@ -9,6 +9,22 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Version 0.10.0 - 2025-12-13
|
||||||
|
|
||||||
|
Updates to `rgithook.py` improve the reliability of Git hook execution. This ensures that pre-commit checks are consistently applied during development workflows.
|
||||||
|
|
||||||
|
**Changes:** 1 files, 258 lines
|
||||||
|
**Languages:** Python (258 lines)
|
||||||
|
|
||||||
|
## Version 0.9.0 - 2025-11-16
|
||||||
|
|
||||||
|
You can now export data as JSON or RSS. A command-line tool is available to extract mentions, and documentation has been added to help you use it.
|
||||||
|
|
||||||
|
**Changes:** 2 files, 209 lines
|
||||||
|
**Languages:** Markdown (8 lines), Python (201 lines)
|
||||||
|
|
||||||
## Version 0.8.0 - 2025-11-05
|
## Version 0.8.0 - 2025-11-05
|
||||||
|
|
||||||
Users can now connect external tools to automate more complex tasks. Developers can integrate new tools using the updated elon.py file.
|
Users can now connect external tools to automate more complex tasks. Developers can integrate new tools using the updated elon.py file.
|
||||||
|
|||||||
248
rgithook.py
248
rgithook.py
@ -4,7 +4,9 @@ API_URL = "https://static.molodetz.nl/rp.cgi/api/v1/chat/completions"
|
|||||||
MODEL = "google/gemma-3-12b-it:free"
|
MODEL = "google/gemma-3-12b-it:free"
|
||||||
TEMPERATURE = 1.0
|
TEMPERATURE = 1.0
|
||||||
MAX_TOKENS = None
|
MAX_TOKENS = None
|
||||||
HOOK_PATH = ".git/hooks/prepare-commit-msg"
|
HOOK_PATH_PRECOMMIT = ".git/hooks/pre-commit"
|
||||||
|
HOOK_PATH_PREPAREMSG = ".git/hooks/prepare-commit-msg"
|
||||||
|
TEMP_MSG_FILE = ".git/COMMIT_MSG_GENERATED"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -32,23 +34,29 @@ def install_hook():
|
|||||||
try:
|
try:
|
||||||
if not os.path.exists('.git'):
|
if not os.path.exists('.git'):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
script_path = os.path.abspath(__file__)
|
script_path = os.path.abspath(__file__)
|
||||||
hook_dir = os.path.dirname(HOOK_PATH)
|
hook_dir = os.path.dirname(HOOK_PATH_PRECOMMIT)
|
||||||
|
|
||||||
if not os.path.exists(hook_dir):
|
if not os.path.exists(hook_dir):
|
||||||
os.makedirs(hook_dir)
|
os.makedirs(hook_dir)
|
||||||
|
|
||||||
if os.path.exists(HOOK_PATH):
|
installed = False
|
||||||
with open(HOOK_PATH, 'r') as f:
|
|
||||||
if script_path in f.read():
|
for hook_path, mode in [(HOOK_PATH_PRECOMMIT, 'pre-commit'), (HOOK_PATH_PREPAREMSG, 'prepare-commit-msg')]:
|
||||||
return False
|
needs_install = True
|
||||||
|
if os.path.exists(hook_path):
|
||||||
with open(HOOK_PATH, 'w') as f:
|
with open(hook_path, 'r') as f:
|
||||||
f.write(f'#!/bin/bash\n{script_path} "$@"\n')
|
if script_path in f.read():
|
||||||
|
needs_install = False
|
||||||
os.chmod(HOOK_PATH, 0o755)
|
|
||||||
return True
|
if needs_install:
|
||||||
|
with open(hook_path, 'w') as f:
|
||||||
|
f.write(f'#!/bin/bash\n{script_path} {mode} "$@"\n')
|
||||||
|
os.chmod(hook_path, 0o755)
|
||||||
|
installed = True
|
||||||
|
|
||||||
|
return installed
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -217,52 +225,52 @@ def call_ai(prompt):
|
|||||||
def generate_commit_message(diff, files):
|
def generate_commit_message(diff, files):
|
||||||
try:
|
try:
|
||||||
files_list = "\n".join([f"- {f}" for f in files[:20]])
|
files_list = "\n".join([f"- {f}" for f in files[:20]])
|
||||||
|
|
||||||
prompt = f"""You write commit messages for code changes.
|
|
||||||
|
|
||||||
Changed files:
|
prompt = f"""You are a senior software engineer writing precise git commit messages following the Conventional Commits specification.
|
||||||
|
|
||||||
|
CONTEXT:
|
||||||
|
Files modified: {len(files)}
|
||||||
{files_list}
|
{files_list}
|
||||||
|
|
||||||
Code changes:
|
DIFF:
|
||||||
{diff[:12000]}
|
{diff[:12000]}
|
||||||
|
|
||||||
Write a commit message with this format:
|
TASK:
|
||||||
<prefix>: <description>
|
Analyze the changes and write a commit message that accurately describes the modifications.
|
||||||
|
|
||||||
Format rules:
|
OUTPUT FORMAT:
|
||||||
- All lowercase for the prefix
|
<type>: <concise description>
|
||||||
- Colon and space after prefix
|
|
||||||
- Start description with lowercase letter
|
|
||||||
- No period at the end
|
|
||||||
- Max 72 characters total
|
|
||||||
- Use imperative mood (Add not Added)
|
|
||||||
|
|
||||||
Choose one prefix:
|
RULES:
|
||||||
- fix: for bug fixes
|
1. Use exactly one line per logical change
|
||||||
Example: fix: resolve null pointer error in user login
|
2. Type must be lowercase
|
||||||
Example: fix: correct date format in export function
|
3. Description starts with lowercase verb in imperative mood
|
||||||
|
4. No trailing punctuation
|
||||||
|
5. Maximum 72 characters per line
|
||||||
|
6. Group related changes under a single type when appropriate
|
||||||
|
7. Order by importance (most significant change first)
|
||||||
|
|
||||||
- feat: for new features
|
TYPES (select the most appropriate):
|
||||||
Example: feat: add dark mode toggle to settings
|
- feat: new functionality or capability added to the codebase
|
||||||
Example: feat: implement search filter for products
|
- fix: correction of a bug or erroneous behavior
|
||||||
|
- refactor: code restructuring without changing external behavior
|
||||||
|
- perf: performance optimization or improvement
|
||||||
|
- docs: documentation additions or modifications
|
||||||
|
- test: test additions or modifications
|
||||||
|
- build: build system or dependency changes
|
||||||
|
- ci: continuous integration configuration changes
|
||||||
|
- style: formatting changes (whitespace, semicolons, etc.)
|
||||||
|
- chore: routine maintenance tasks
|
||||||
|
|
||||||
- docs: for documentation changes
|
ANALYSIS GUIDELINES:
|
||||||
Example: docs: update api endpoint descriptions
|
- Identify the primary purpose of the change
|
||||||
Example: docs: add setup guide for development
|
- Distinguish between new features and modifications to existing ones
|
||||||
|
- Recognize bug fixes by error handling, null checks, or condition corrections
|
||||||
|
- Note refactoring by structural changes without behavior modification
|
||||||
|
- Detect performance work by optimization patterns or caching additions
|
||||||
|
|
||||||
- perf: for performance improvements
|
OUTPUT:
|
||||||
Example: perf: reduce database query time by 40%
|
Provide only the commit message lines, no explanations or additional text."""
|
||||||
Example: perf: optimize image loading with lazy load
|
|
||||||
|
|
||||||
- refactor: for code restructuring
|
|
||||||
Example: refactor: simplify user validation logic
|
|
||||||
Example: refactor: extract common functions to utils
|
|
||||||
|
|
||||||
- maintenance: for routine updates and maintenance
|
|
||||||
Example: maintenance: update dependencies to latest versions
|
|
||||||
Example: maintenance: clean up unused imports and files
|
|
||||||
|
|
||||||
Reply with ONLY the commit message, nothing else."""
|
|
||||||
|
|
||||||
message = call_ai(prompt)
|
message = call_ai(prompt)
|
||||||
if not message:
|
if not message:
|
||||||
@ -270,30 +278,40 @@ Reply with ONLY the commit message, nothing else."""
|
|||||||
|
|
||||||
message = message.strip().strip('"').strip("'")
|
message = message.strip().strip('"').strip("'")
|
||||||
|
|
||||||
prefixes = ['fix:', 'feat:', 'docs:', 'perf:', 'refactor:', 'maintenance:']
|
lines = message.split('\n')
|
||||||
if not any(message.startswith(p) for p in prefixes):
|
processed_lines = []
|
||||||
message = f"feat: {message}"
|
prefixes = ['feat:', 'fix:', 'refactor:', 'perf:', 'docs:', 'test:', 'build:', 'ci:', 'style:', 'chore:']
|
||||||
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
if not any(line.startswith(p) for p in prefixes):
|
||||||
|
line = f"chore: {line}"
|
||||||
|
processed_lines.append(line)
|
||||||
|
|
||||||
return message
|
if not processed_lines:
|
||||||
|
return generate_fallback_message(files)
|
||||||
|
|
||||||
|
return '\n'.join(processed_lines)
|
||||||
except Exception:
|
except Exception:
|
||||||
return generate_fallback_message(files)
|
return generate_fallback_message(files)
|
||||||
|
|
||||||
def generate_fallback_message(files):
|
def generate_fallback_message(files):
|
||||||
try:
|
try:
|
||||||
if not files:
|
if not files:
|
||||||
return "feat: update project"
|
return "chore: update project"
|
||||||
|
|
||||||
exts = set()
|
exts = set()
|
||||||
for f in files:
|
for f in files:
|
||||||
ext = os.path.splitext(f)[1]
|
ext = os.path.splitext(f)[1]
|
||||||
if ext:
|
if ext:
|
||||||
exts.add(ext[1:])
|
exts.add(ext[1:])
|
||||||
|
|
||||||
if exts:
|
if exts:
|
||||||
return f"feat: update {', '.join(sorted(exts)[:3])} files"
|
return f"chore: update {', '.join(sorted(exts)[:3])} files"
|
||||||
return "feat: update project files"
|
return "chore: update project files"
|
||||||
except Exception:
|
except Exception:
|
||||||
return "feat: update project"
|
return "chore: update project"
|
||||||
|
|
||||||
def create_git_tag(version):
|
def create_git_tag(version):
|
||||||
try:
|
try:
|
||||||
@ -334,20 +352,32 @@ def update_changelog(version, commit_message, stats, files):
|
|||||||
|
|
||||||
lang_summary = ", ".join(lang_stats) if lang_stats else "No code changes"
|
lang_summary = ", ".join(lang_stats) if lang_stats else "No code changes"
|
||||||
|
|
||||||
functional_desc_prompt = f"""You write changelog entries for software releases.
|
functional_desc_prompt = f"""You are a technical writer creating changelog entries for a software release.
|
||||||
|
|
||||||
Commit message: {commit_message}
|
COMMIT SUMMARY:
|
||||||
Changed files: {", ".join(files[:10])}
|
{commit_message}
|
||||||
|
|
||||||
Write a short functional description of what changed for users or developers.
|
AFFECTED FILES:
|
||||||
Use simple clear words, be direct, max 2 sentences.
|
{", ".join(files[:10])}
|
||||||
Focus on what it does, not how.
|
|
||||||
|
|
||||||
Reply with ONLY the description text."""
|
TASK:
|
||||||
|
Write a concise changelog entry describing the functional impact of these changes.
|
||||||
|
|
||||||
|
REQUIREMENTS:
|
||||||
|
1. Maximum two sentences
|
||||||
|
2. Focus on user-visible or developer-relevant changes
|
||||||
|
3. Use present tense, active voice
|
||||||
|
4. Be specific about what functionality is added, modified, or fixed
|
||||||
|
5. Avoid implementation details unless architecturally significant
|
||||||
|
6. No marketing language or superlatives
|
||||||
|
|
||||||
|
OUTPUT:
|
||||||
|
Provide only the changelog description text, no formatting or prefixes."""
|
||||||
|
|
||||||
functional_desc = call_ai(functional_desc_prompt)
|
functional_desc = call_ai(functional_desc_prompt)
|
||||||
if not functional_desc:
|
if not functional_desc:
|
||||||
functional_desc = commit_message.split(':', 1)[1].strip() if ':' in commit_message else commit_message
|
first_line = commit_message.split('\n')[0]
|
||||||
|
functional_desc = first_line.split(':', 1)[1].strip() if ':' in first_line else first_line
|
||||||
|
|
||||||
entry_lines = [
|
entry_lines = [
|
||||||
f"## Version {version} - {today}",
|
f"## Version {version} - {today}",
|
||||||
@ -382,6 +412,48 @@ Reply with ONLY the description text."""
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def run_pre_commit():
|
||||||
|
diff = get_git_diff()
|
||||||
|
files = get_changed_files()
|
||||||
|
|
||||||
|
if not diff and not files:
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
stats = analyze_diff_stats(diff)
|
||||||
|
commit_message = generate_commit_message(diff, files)
|
||||||
|
|
||||||
|
current_version, source = get_version()
|
||||||
|
new_version = update_version(current_version, source)
|
||||||
|
|
||||||
|
update_changelog(new_version, commit_message, stats, files)
|
||||||
|
safe_run(['git', 'add', 'CHANGELOG.md'])
|
||||||
|
|
||||||
|
with open(TEMP_MSG_FILE, 'w') as f:
|
||||||
|
f.write(f"{new_version}\n{commit_message}")
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def run_prepare_commit_msg(commit_msg_file):
|
||||||
|
if not os.path.exists(TEMP_MSG_FILE):
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
with open(TEMP_MSG_FILE, 'r') as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
lines = content.split('\n', 1)
|
||||||
|
new_version = lines[0] if lines else "0.1.0"
|
||||||
|
commit_message = lines[1] if len(lines) > 1 else "chore: update project"
|
||||||
|
|
||||||
|
with open(commit_msg_file, 'w') as f:
|
||||||
|
f.write(commit_message + '\n')
|
||||||
|
|
||||||
|
create_git_tag(new_version)
|
||||||
|
|
||||||
|
os.remove(TEMP_MSG_FILE)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
if len(sys.argv) < 2:
|
if len(sys.argv) < 2:
|
||||||
@ -390,36 +462,24 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print("Git hook already installed")
|
print("Git hook already installed")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
commit_msg_file = sys.argv[1]
|
mode = sys.argv[1]
|
||||||
|
|
||||||
current_version, source = get_version()
|
if mode == 'pre-commit':
|
||||||
new_version = update_version(current_version, source)
|
run_pre_commit()
|
||||||
|
elif mode == 'prepare-commit-msg':
|
||||||
diff = get_git_diff()
|
if len(sys.argv) >= 3:
|
||||||
files = get_changed_files()
|
run_prepare_commit_msg(sys.argv[2])
|
||||||
stats = analyze_diff_stats(diff)
|
sys.exit(0)
|
||||||
|
else:
|
||||||
commit_message = generate_commit_message(diff, files)
|
sys.exit(0)
|
||||||
|
|
||||||
update_changelog(new_version, commit_message, stats, files)
|
|
||||||
safe_run(['git', 'add', 'CHANGELOG.md'])
|
|
||||||
|
|
||||||
create_git_tag(new_version)
|
|
||||||
|
|
||||||
with open(commit_msg_file, 'w') as f:
|
|
||||||
f.write(commit_message + '\n')
|
|
||||||
|
|
||||||
sys.exit(0)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
try:
|
try:
|
||||||
if len(sys.argv) >= 2:
|
if os.path.exists(TEMP_MSG_FILE):
|
||||||
with open(sys.argv[1], 'w') as f:
|
os.remove(TEMP_MSG_FILE)
|
||||||
f.write("feat: update project\n")
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user