webcraft-ai-backend / deploy_tmp /github_utils.py
3ssem0
fix: configuration error - aligned entry point to app.py and enforced LF/BOM-less encoding
ec47953
Raw
History Blame Contribute Delete
6.65 kB
import os
from github import Github
import requests
import random
import string
def create_github_repo(token, repo_name, private=False):
"""إنشاء ريبوزيتوري جديد على GitHub مع التحقق من الاسم الفريد"""
g = Github(token)
user = g.get_user()
# Try to create repo with original name
original_name = repo_name
counter = 1
max_attempts = 100 # Allow up to 100 attempts (my-website-1 through my-website-100)
for attempt in range(max_attempts):
try:
repo = user.create_repo(repo_name, private=private)
return repo
except Exception as e:
error_str = str(e)
# Check if error is due to name already existing
if "name already exists" in error_str or "422" in error_str:
# Add number suffix: (1), (2), (3), etc.
repo_name = f"{original_name}-{counter}"
counter += 1
else:
# Check for 404 which usually means scope issues
if "404" in error_str:
raise Exception("GitHub API returned 404 (Not Found). This usually means your Token lacks the 'repo' scope or 'Administration' write permission. Please ensure your token has full repo access.")
# Different error, re-raise
raise
# If all attempts failed, raise the last exception
raise Exception(f"Failed to create repository after {max_attempts} attempts")
def upload_files_to_repo(repo, local_dir, branch="main"):
"""رفع كل الملفات من مجلد محلي إلى الريبو (يدعم التحديث)"""
for root, _, files in os.walk(local_dir):
for file_name in files:
full_path = os.path.join(root, file_name)
with open(full_path, "rb") as f:
content = f.read()
relative_path = os.path.relpath(full_path, local_dir).replace("\\", "/")
try:
# Check if file exists to update it
contents = repo.get_contents(relative_path, ref=branch)
repo.update_file(
path=relative_path,
message=f"Update {relative_path}",
content=content,
sha=contents.sha,
branch=branch
)
print(f"Updated {relative_path}")
except Exception as e:
# If not found (404), create it
if "404" in str(e) or "Not Found" in str(e):
repo.create_file(
path=relative_path,
message=f"Add {relative_path}",
content=content,
branch=branch
)
print(f"Created {relative_path}")
else:
print(f"Error with {relative_path}: {e}")
def enable_github_pages(username, repo_name, token):
"""تفعيل GitHub Pages"""
pages_url = f"https://api.github.com/repos/{username}/{repo_name}/pages"
headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json"
}
payload = {"source": {"branch": "main", "path": "/"}}
response = requests.post(pages_url, headers=headers, json=payload)
return response.status_code in [201, 204]
def get_repository(username, repo_name, token):
"""
Retrieve an existing GitHub repository.
Args:
username: GitHub username
repo_name: Repository name
token: GitHub personal access token
Returns:
Repository object or None if not found
"""
try:
g = Github(token)
repo = g.get_repo(f"{username}/{repo_name}")
return repo
except Exception as e:
print(f"Repository not found: {e}")
return None
def update_file_in_repo(repo, file_path, content, commit_message="Update file"):
"""
Update an existing file in the repository.
Args:
repo: Repository object
file_path: Path to file in repository (e.g., "index.html")
content: New file content (string or bytes)
commit_message: Commit message
Returns:
True if successful, False otherwise
"""
try:
# Get the file from the repository
file = repo.get_contents(file_path)
# Update the file
repo.update_file(
path=file_path,
message=commit_message,
content=content,
sha=file.sha,
branch="main"
)
print(f"Updated {file_path} in repository")
return True
except Exception as e:
print(f"Error updating file: {e}")
return False
def resync_webcraft_file(username, repo_name, token, html_file_path, commit_message="Resync from WebCraft"):
"""
Resync WebCraft HTML file with existing GitHub repository.
Args:
username: GitHub username
repo_name: Repository name
token: GitHub personal access token
html_file_path: Path to local HTML file
commit_message: Commit message for the update
Returns:
dict with status and URL, or error message
"""
try:
# Get the repository
repo = get_repository(username, repo_name, token)
if not repo:
return {
"status": "error",
"message": f"Repository '{repo_name}' not found"
}
# Read the HTML file
with open(html_file_path, 'rb') as f:
content = f.read()
# Find the HTML file in the repository (usually index.html)
filename = os.path.basename(html_file_path)
# Update the file
if update_file_in_repo(repo, filename, content, commit_message):
site_url = f"https://{username}.github.io/{repo_name}/"
return {
"status": "success",
"message": "Repository synced successfully",
"website_url": site_url,
"repo_url": repo.html_url
}
else:
return {
"status": "error",
"message": "Failed to update file in repository"
}
except Exception as e:
return {
"status": "error",
"message": str(e)
}