262 lines
9.0 KiB
Python
262 lines
9.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Go-Git Auto-Commit Script for LightRAG project.
|
|
Uses Gitea API directly instead of external Git.
|
|
"""
|
|
|
|
import requests
|
|
import os
|
|
import sys
|
|
import json
|
|
import hashlib
|
|
import base64
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
class GoGitAutoCommit:
|
|
def __init__(self, gitea_url, username, password, repo_owner, repo_name):
|
|
self.gitea_url = gitea_url.rstrip('/')
|
|
self.username = username
|
|
self.password = password
|
|
self.repo_owner = repo_owner
|
|
self.repo_name = repo_name
|
|
self.session = requests.Session()
|
|
self.session.auth = (username, password)
|
|
|
|
def get_auth_token(self):
|
|
"""Get or create an access token for API calls."""
|
|
# Try to get existing tokens
|
|
tokens_url = f"{self.gitea_url}/api/v1/users/{self.username}/tokens"
|
|
response = self.session.get(tokens_url)
|
|
|
|
if response.status_code == 200:
|
|
tokens = response.json()
|
|
if tokens:
|
|
return tokens[0]['sha1']
|
|
|
|
# Create new token
|
|
token_data = {
|
|
"name": f"auto-commit-{datetime.now().strftime('%Y%m%d')}",
|
|
"scopes": ["write:repository", "read:repository"]
|
|
}
|
|
|
|
response = self.session.post(tokens_url, json=token_data)
|
|
if response.status_code == 201:
|
|
return response.json()['sha1']
|
|
else:
|
|
raise Exception(f"Failed to create token: {response.text}")
|
|
|
|
def calculate_file_hash(self, file_path):
|
|
"""Calculate SHA1 hash for file (Go-Git compatible)."""
|
|
with open(file_path, 'rb') as f:
|
|
content = f.read()
|
|
sha1 = hashlib.sha1(content).hexdigest()
|
|
return sha1, len(content)
|
|
|
|
def create_file_content(self, file_path, relative_path):
|
|
"""Create file content entry for Gitea API."""
|
|
sha1, size = self.calculate_file_hash(file_path)
|
|
|
|
with open(file_path, 'rb') as f:
|
|
content = f.read()
|
|
encoded = base64.b64encode(content).decode('utf-8')
|
|
|
|
return {
|
|
"path": relative_path,
|
|
"sha": sha1,
|
|
"size": size,
|
|
"content": encoded,
|
|
"encoding": "base64"
|
|
}
|
|
|
|
def get_repo_tree(self, ref="master"):
|
|
"""Get current repository tree."""
|
|
url = f"{self.gitea_url}/api/v1/repos/{self.repo_owner}/{self.repo_name}/git/trees/{ref}"
|
|
response = self.session.get(url)
|
|
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
else:
|
|
# Repository might be empty
|
|
return {"tree": [], "sha": None}
|
|
|
|
def find_changed_files(self, base_dir="."):
|
|
"""Find changed files by comparing with current tree."""
|
|
base_path = Path(base_dir)
|
|
changed_files = []
|
|
|
|
# Get current tree
|
|
current_tree = self.get_repo_tree()
|
|
current_files = {item['path']: item['sha'] for item in current_tree.get('tree', [])}
|
|
|
|
# Walk through directory
|
|
for file_path in base_path.rglob('*'):
|
|
if file_path.is_file():
|
|
# Skip .git directory and other ignored files
|
|
if '.git' in str(file_path):
|
|
continue
|
|
|
|
relative_path = str(file_path.relative_to(base_path))
|
|
|
|
# Calculate current hash
|
|
current_sha1, _ = self.calculate_file_hash(file_path)
|
|
|
|
# Check if file is new or modified
|
|
if relative_path not in current_files:
|
|
changed_files.append(("added", relative_path, file_path))
|
|
elif current_sha1 != current_files[relative_path]:
|
|
changed_files.append(("modified", relative_path, file_path))
|
|
|
|
return changed_files
|
|
|
|
def create_commit(self, message, changed_files, base_dir="."):
|
|
"""Create a commit using Gitea API."""
|
|
# Get current commit reference
|
|
ref_url = f"{self.gitea_url}/api/v1/repos/{self.repo_owner}/{self.repo_name}/git/refs/heads/master"
|
|
response = self.session.get(ref_url)
|
|
|
|
if response.status_code == 404:
|
|
# Branch doesn't exist yet (empty repo)
|
|
parent_sha = None
|
|
elif response.status_code == 200:
|
|
parent_sha = response.json()['object']['sha']
|
|
else:
|
|
raise Exception(f"Failed to get ref: {response.text}")
|
|
|
|
# Create tree with changed files
|
|
tree_items = []
|
|
|
|
for change_type, relative_path, file_path in changed_files:
|
|
if change_type in ["added", "modified"]:
|
|
file_content = self.create_file_content(file_path, relative_path)
|
|
tree_items.append({
|
|
"path": relative_path,
|
|
"mode": "100644", # Regular file
|
|
"type": "blob",
|
|
"sha": file_content["sha"]
|
|
})
|
|
|
|
# Create tree
|
|
tree_data = {
|
|
"base_tree": parent_sha,
|
|
"tree": tree_items
|
|
}
|
|
|
|
tree_url = f"{self.gitea_url}/api/v1/repos/{self.repo_owner}/{self.repo_name}/git/trees"
|
|
response = self.session.post(tree_url, json=tree_data)
|
|
|
|
if response.status_code != 201:
|
|
raise Exception(f"Failed to create tree: {response.text}")
|
|
|
|
tree_sha = response.json()['sha']
|
|
|
|
# Create commit
|
|
commit_data = {
|
|
"message": message,
|
|
"tree": tree_sha,
|
|
"parents": [parent_sha] if parent_sha else []
|
|
}
|
|
|
|
commit_url = f"{self.gitea_url}/api/v1/repos/{self.repo_owner}/{self.repo_name}/git/commits"
|
|
response = self.session.post(commit_url, json=commit_data)
|
|
|
|
if response.status_code != 201:
|
|
raise Exception(f"Failed to create commit: {response.text}")
|
|
|
|
commit_sha = response.json()['sha']
|
|
|
|
# Update reference
|
|
ref_data = {
|
|
"sha": commit_sha,
|
|
"force": False
|
|
}
|
|
|
|
response = self.session.patch(ref_url, json=ref_data)
|
|
|
|
if response.status_code != 200:
|
|
# Try to create the reference
|
|
ref_url = f"{self.gitea_url}/api/v1/repos/{self.repo_owner}/{self.repo_name}/git/refs"
|
|
ref_data = {
|
|
"ref": "refs/heads/master",
|
|
"sha": commit_sha
|
|
}
|
|
response = self.session.post(ref_url, json=ref_data)
|
|
|
|
if response.status_code != 201:
|
|
raise Exception(f"Failed to update ref: {response.text}")
|
|
|
|
return commit_sha
|
|
|
|
def auto_commit(self, message=None, base_dir="."):
|
|
"""Main auto-commit function using Go-Git API."""
|
|
if not message:
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
message = f"Go-Git Auto-Commit: {timestamp}"
|
|
|
|
print(f"Go-Git Auto-Commit starting with message: {message}")
|
|
print("=" * 60)
|
|
|
|
# Find changed files
|
|
print("1. Scanning for changed files...")
|
|
changed_files = self.find_changed_files(base_dir)
|
|
|
|
if not changed_files:
|
|
print("No changes detected.")
|
|
return True
|
|
|
|
print(f"Found {len(changed_files)} changed files:")
|
|
for change_type, relative_path, _ in changed_files[:10]: # Show first 10
|
|
print(f" {change_type}: {relative_path}")
|
|
if len(changed_files) > 10:
|
|
print(f" ... and {len(changed_files) - 10} more")
|
|
|
|
# Create commit
|
|
print(f"\n2. Creating commit: '{message}'")
|
|
try:
|
|
commit_sha = self.create_commit(message, changed_files, base_dir)
|
|
print(f"Commit created successfully: {commit_sha}")
|
|
|
|
# Show commit URL
|
|
commit_url = f"{self.gitea_url}/{self.repo_owner}/{self.repo_name}/commit/{commit_sha}"
|
|
print(f"Commit URL: {commit_url}")
|
|
|
|
return True
|
|
except Exception as e:
|
|
print(f"Error creating commit: {e}")
|
|
return False
|
|
|
|
def main():
|
|
# Configuration
|
|
GITEA_URL = "https://git.mtrcompute.com"
|
|
USERNAME = "jleu3482"
|
|
PASSWORD = "jleu1212"
|
|
REPO_OWNER = "jleu3482"
|
|
REPO_NAME = "railseek6"
|
|
|
|
# Get commit message from command line
|
|
if len(sys.argv) > 1:
|
|
message = sys.argv[1]
|
|
else:
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
message = f"Go-Git Auto-Commit: {timestamp}"
|
|
|
|
print("Go-Git Auto-Commit Script for LightRAG")
|
|
print("=" * 60)
|
|
|
|
# Initialize Go-Git client
|
|
gogit = GoGitAutoCommit(GITEA_URL, USERNAME, PASSWORD, REPO_OWNER, REPO_NAME)
|
|
|
|
# Run auto-commit
|
|
success = gogit.auto_commit(message)
|
|
|
|
if success:
|
|
print("\n" + "=" * 60)
|
|
print("Go-Git auto-commit completed successfully!")
|
|
sys.exit(0)
|
|
else:
|
|
print("\n" + "=" * 60)
|
|
print("Go-Git auto-commit failed!")
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main() |