FastAPI_App / github_deployer.py
Kr-Adarsh
FastAPI application files for Hugging Face Space deployment
42f12bd
"""
GitHub repository automation
Creates/updates repositories, deploys to GitHub Pages
"""
from github import Github, Auth, GithubException
import os
import time
import logging
import requests
logger = logging.getLogger(__name__)
# To deploy the site on the git-pages
def enable_github_pages(repo_full_name, branch="main"):
"""
Enable GitHub Pages for the repo via REST API
"""
token = os.getenv("GITHUB_TOKEN")
url = f"https://api.github.com/repos/{repo_full_name}/pages"
headers = {
"Authorization": f"token {token}",
"Accept": "application/vnd.github.v3+json"
}
payload = {
"source": {
"branch": branch,
"path": "/"
}
}
response = requests.post(url, json=payload, headers=headers)
if response.status_code in [201, 204]:
logger.info("βœ“ GitHub Pages enabled via REST API")
elif response.status_code == 422:
logger.info("GitHub Pages already enabled or validation error")
else:
logger.warning(f"Failed to enable GitHub Pages: {response.status_code} {response.text}")
def deploy_to_github(task_name: str, html_content: str, readme_content: str, round_num: int = 1) -> tuple[str, str, str]:
"""
Complete GitHub deployment workflow
Args:
task_name: Unique task identifier (used as repo name)
html_content: HTML code to deploy
readme_content: README markdown content
round_num: 1 for initial creation, 2 for updates
Returns:
Tuple of (repo_url, commit_sha, pages_url)
"""
# Authenticate
auth = Auth.Token(os.getenv("GITHUB_TOKEN"))
g = Github(auth=auth)
try:
user = g.get_user()
repo_name = f"{task_name}" # Use task name directly
logger.info(f"GitHub user: {user.login}")
logger.info(f"Target repo: {repo_name}")
if round_num == 1:
# ROUND 1: Create new repository
logger.info("Creating new repository...")
repo = user.create_repo(
name=repo_name,
private=False,
auto_init=True,
license_template="mit", # Automatically adds MIT LICENSE
description=f"LLM-generated application for task {task_name}"
)
logger.info(f"βœ“ Repository created: {repo.html_url}")
# Wait for repo to initialize
time.sleep(3)
# Add index.html (safe to create)
html_result = repo.create_file(
path="index.html",
message="Initial commit - Add application",
content=html_content
)
commit_sha = html_result['commit'].sha
logger.info("βœ“ Added index.html")
# Check if README.md exists (likely created by auto_init=True)
try:
existing_readme = repo.get_contents("README.md")
# If exists, update it
repo.update_file(
path="README.md",
message="Update README documentation",
content=readme_content,
sha=existing_readme.sha
)
logger.info("βœ“ Updated README.md")
except GithubException as e:
if e.status == 404:
# README.md doesn't exist, create it
repo.create_file(
path="README.md",
message="Add README documentation",
content=readme_content
)
logger.info("βœ“ Added README.md")
else:
logger.error(f"README.md handling error: {e}")
# Enable GitHub Pages
try:
enable_github_pages(repo.full_name, branch="main")
# logger.info("βœ“ GitHub Pages enabled") #is covered in the function
except GithubException as e:
if e.status == 409:
logger.info("Pages already enabled")
else:
logger.warning(f"Pages enabling: {e}")
else:
# ROUND 2: Update existing repository
logger.info("Updating existing repository...")
repo = user.get_repo(repo_name)
logger.info(f"βœ“ Found repository: {repo.html_url}")
# Update index.html
html_file = repo.get_contents("index.html")
html_result = repo.update_file(
path=html_file.path,
message=f"Round {round_num} - Update application",
content=html_content,
sha=html_file.sha
)
commit_sha = html_result['commit'].sha
logger.info("βœ“ Updated index.html")
# Update README.md
readme_file = repo.get_contents("README.md")
repo.update_file(
path=readme_file.path,
message=f"Round {round_num} - Update README",
content=readme_content,
sha=readme_file.sha
)
logger.info("βœ“ Updated README.md")
# Construct URLs
repo_url = repo.html_url
pages_url = f"https://{user.login}.github.io/{repo_name}/"
logger.info(f"Deployment complete!")
logger.info(f" Repository: {repo_url}")
logger.info(f" Commit SHA: {commit_sha}")
logger.info(f" Pages URL: {pages_url}")
logger.info(f" ⚠️ Pages may take 2-5 minutes to be live")
g.close()
return repo_url, commit_sha, pages_url
except GithubException as e:
logger.error(f"GitHub API Error: {e.status} - {e.data}")
g.close()
raise
except Exception as e:
logger.error(f"Deployment error: {str(e)}")
g.close()
raise