Auto-sync from website-creator

This commit is contained in:
Kunthawat Greethong
2026-03-08 23:03:19 +07:00
commit 9be686f587
117 changed files with 24737 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
# Gitea Configuration
# Get API token from: https://git.moreminimore.com/user/settings/applications
GITEA_URL=https://git.moreminimore.com
GITEA_API_TOKEN=your-api-token-here
GITEA_USERNAME=your-username

View File

@@ -0,0 +1 @@
requests>=2.28.0

View File

@@ -0,0 +1,333 @@
#!/usr/bin/env python3
"""
Gitea Sync - Automatically sync repositories to Gitea
Creates/updates repositories and pushes code automatically.
Auto-detects new vs existing repositories.
Usage:
python3 sync.py --repo my-website --path ./my-website
"""
import os
import sys
import json
import argparse
import requests
import subprocess
from pathlib import Path
def load_env():
"""Load environment from .env file."""
env_path = Path(__file__).parent / ".env"
if env_path.exists():
for line in env_path.read_text().splitlines():
line = line.strip()
if line and not line.startswith("#") and "=" in line:
k, v = line.split("=", 1)
os.environ.setdefault(k.strip(), v.strip().strip("\"'"))
load_env()
GITEA_URL = os.environ.get("GITEA_URL", "https://git.moreminimore.com")
GITEA_API_TOKEN = os.environ.get("GITEA_API_TOKEN")
GITEA_USERNAME = os.environ.get("GITEA_USERNAME")
def check_auth():
"""Verify Gitea authentication."""
if not GITEA_API_TOKEN:
print("Error: GITEA_API_TOKEN not set", file=sys.stderr)
sys.exit(1)
response = requests.get(
f"{GITEA_URL}/api/v1/user",
headers={"Authorization": f"token {GITEA_API_TOKEN}"}
)
if response.status_code != 200:
print(f"Error: Gitea authentication failed ({response.status_code})", file=sys.stderr)
print(f"Check your API token at: {GITEA_URL}/user/settings/applications", file=sys.stderr)
sys.exit(1)
user = response.json()
return user.get("login", GITEA_USERNAME)
def repo_exists(username, repo_name):
"""Check if repository exists on Gitea."""
response = requests.get(
f"{GITEA_URL}/api/v1/repos/{username}/{repo_name}",
headers={"Authorization": f"token {GITEA_API_TOKEN}"}
)
return response.status_code == 200
def create_repo(repo_name, description="", private=False):
"""Create new repository on Gitea."""
print(f"📦 Creating repository: {repo_name}")
data = {
"name": repo_name,
"description": description,
"private": private,
"auto_init": True,
"readme": "Default",
"default_branch": "main"
}
response = requests.post(
f"{GITEA_URL}/api/v1/user/repos",
headers={"Authorization": f"token {GITEA_API_TOKEN}"},
json=data
)
if response.status_code == 201:
print(f"✅ Repository created: {repo_name}")
return response.json()
elif response.status_code == 409:
print(f"⚠️ Repository already exists: {repo_name}")
return None
else:
print(f"❌ Failed to create repository: {response.text}", file=sys.stderr)
sys.exit(1)
def update_repo(repo_name, description=""):
"""Update existing repository."""
print(f"🔄 Updating repository: {repo_name}")
data = {
"description": description,
"website": "",
"has_issues": True,
"has_pull_requests": True,
"has_wiki": False
}
response = requests.patch(
f"{GITEA_URL}/api/v1/repos/{GITEA_USERNAME}/{repo_name}",
headers={"Authorization": f"token {GITEA_API_TOKEN}"},
json=data
)
if response.status_code == 200:
print(f"✅ Repository updated: {repo_name}")
return response.json()
else:
print(f"⚠️ Could not update repository: {response.text}")
return None
def get_repo_url(username, repo_name):
"""Get HTTPS URL for repository."""
return f"{GITEA_URL}/{username}/{repo_name}.git"
def is_git_repo(path):
"""Check if directory is a git repository."""
git_dir = Path(path) / ".git"
return git_dir.exists()
def push_code(repo_path, git_url, branch="main"):
"""Push code to Gitea repository."""
repo_path = Path(repo_path)
if not repo_path.exists():
print(f"Error: Path does not exist: {repo_path}", file=sys.stderr)
sys.exit(1)
print(f"🚀 Pushing code to Gitea...")
# Initialize git if needed
if not is_git_repo(repo_path):
print(" → Initializing git repository")
subprocess.run(["git", "init"], cwd=repo_path, check=True, capture_output=True)
# Configure git to use token for authentication
# This avoids interactive password prompts
subprocess.run(
["git", "config", "credential.helper", "store"],
cwd=repo_path,
check=True,
capture_output=True
)
# Add .gitignore if not exists
gitignore = repo_path / ".gitignore"
if not gitignore.exists():
with open(gitignore, "w") as f:
f.write("""node_modules
dist
.env
.astro
*.db
*.log
.DS_Store
""")
# Add remote if not exists
result = subprocess.run(
["git", "remote", "get-url", "origin"],
cwd=repo_path,
capture_output=True
)
if result.returncode != 0:
print(f" → Adding remote: {git_url}")
# Use token in URL for authentication
auth_url = git_url.replace(
f"{GITEA_URL}/",
f"{GITEA_URL}/{GITEA_API_TOKEN}:@"
)
subprocess.run(
["git", "remote", "add", "origin", auth_url],
cwd=repo_path,
check=True,
capture_output=True
)
else:
# Update existing remote with auth
auth_url = git_url.replace(
f"{GITEA_URL}/",
f"{GITEA_URL}/{GITEA_API_TOKEN}:@"
)
subprocess.run(
["git", "remote", "set-url", "origin", auth_url],
cwd=repo_path,
check=True,
capture_output=True
)
# Add all files
print(" → Adding files")
subprocess.run(["git", "add", "."], cwd=repo_path, check=True, capture_output=True)
# Check if there are changes to commit
result = subprocess.run(
["git", "status", "--porcelain"],
cwd=repo_path,
capture_output=True,
text=True
)
if result.stdout.strip():
# Commit changes
print(" → Committing changes")
subprocess.run(
["git", "commit", "-m", "Auto-sync from website-creator"],
cwd=repo_path,
check=True,
capture_output=True
)
# Set main as default branch
subprocess.run(
["git", "branch", "-M", branch],
cwd=repo_path,
check=True,
capture_output=True
)
# Push with force to handle initial push
print(" → Pushing to Gitea")
result = subprocess.run(
["git", "push", "-u", "-f", "origin", branch],
cwd=repo_path,
capture_output=True,
text=True
)
if result.returncode == 0:
print(f"✅ Code pushed successfully")
return True
else:
print(f"⚠️ Push output: {result.stderr}")
# Try without -f if it fails
subprocess.run(
["git", "push", "-u", "origin", branch],
cwd=repo_path,
capture_output=True
)
print(f"✅ Code pushed (without force)")
return True
else:
print(f" No changes to push")
return True
def sync_repo(repo_name, repo_path, description="", auto_push=True):
"""Complete sync workflow."""
# Step 1: Check auth
username = check_auth()
print(f"🔐 Authenticated as: {username}")
print("")
# Step 2: Check if repo exists
exists = repo_exists(username, repo_name)
if exists:
update_repo(repo_name, description)
else:
create_repo(repo_name, description)
print("")
# Step 3: Push code
if auto_push:
git_url = get_repo_url(username, repo_name)
push_code(repo_path, git_url)
print("")
print(f"🌐 Repository URL: {git_url.replace('.git', '')}")
return {
"username": username,
"repo_name": repo_name,
"git_url": get_repo_url(username, repo_name),
"created": not exists
}
def main():
parser = argparse.ArgumentParser(description="Sync repository to Gitea")
parser.add_argument("--repo", required=True, help="Repository name")
parser.add_argument("--path", required=True, help="Path to repository")
parser.add_argument("--description", default="", help="Repository description")
parser.add_argument("--no-push", action="store_true", help="Don't push code")
parser.add_argument("--private", action="store_true", help="Make repository private")
args = parser.parse_args()
print("🔄 Gitea Sync")
print("=" * 50)
print(f"Repository: {args.repo}")
print(f"Path: {args.path}")
print(f"Description: {args.description or '(none)'}")
print("=" * 50)
print("")
result = sync_repo(
args.repo,
args.path,
args.description,
auto_push=not args.no_push
)
print("")
print("=" * 50)
print("✅ Sync complete!")
print(f"Repository: {result['repo_name']}")
print(f"URL: {result['git_url'].replace('.git', '')}")
if result['created']:
print("Status: Created new repository")
else:
print("Status: Updated existing repository")
print("=" * 50)
if __name__ == "__main__":
main()