Download github_helper.py from iitmbs24f/prj1: direct link, hf CLI and curl.
- Browser
- Download file 8.04 kB
-
https://huggingface.co/spaces/iitmbs24f/prj1/resolve/main/github_helper.py
- Command line
-
hf download hf://spaces/iitmbs24f/prj1/github_helper.py
-
curl -L -o github_helper.py https://huggingface.co/spaces/iitmbs24f/prj1/resolve/main/github_helper.py
8.04 kB
| """ | |
| GitHub Helper Module for creating repositories and enabling GitHub Pages | |
| Updated for classic personal access token usage. | |
| """ | |
| import os | |
| import logging | |
| from typing import Dict, Any, Optional | |
| from github import Github, GithubException | |
| from datetime import datetime | |
| import time | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| class GitHubHelper: | |
| def __init__(self): | |
| self.token = os.getenv("GITHUB_TOKEN") | |
| self.username = os.getenv("GITHUB_USERNAME") | |
| if not self.token or not self.username: | |
| raise ValueError("GITHUB_TOKEN and GITHUB_USERNAME must be set") | |
| # Authenticate with token | |
| self.github = Github(self.token) | |
| try: | |
| # Always create under authenticated user | |
| self.owner = self.github.get_user() | |
| logger.info(f"Using GitHub user owner: {self.owner.login}") | |
| except GithubException as e: | |
| logger.error(f"Failed to resolve GitHub owner: status={getattr(e, 'status', None)} data={getattr(e, 'data', None)}") | |
| raise | |
| def create_repo_and_deploy( | |
| self, | |
| app_name: str, | |
| html_content: str, | |
| css_content: str, | |
| js_content: str, | |
| metadata: Dict[str, Any], | |
| is_revision: bool = False, | |
| existing_repo_name: Optional[str] = None | |
| ) -> Dict[str, Any]: | |
| """ | |
| Create a new repository or update existing one and enable GitHub Pages | |
| """ | |
| try: | |
| if is_revision and existing_repo_name: | |
| repo_name = existing_repo_name | |
| repo = self.github.get_repo(f"{self.owner.login}/{repo_name}") | |
| logger.info(f"Updating existing repository: {repo_name}") | |
| else: | |
| repo_name = self._generate_repo_name(app_name) | |
| repo = self._create_repository(repo_name, metadata) | |
| logger.info(f"Created new repository: {repo_name}") | |
| # Prepare files for deployment | |
| extra_files = metadata.get("_extra_files") if isinstance(metadata, dict) else None | |
| files_to_commit = self._prepare_files(html_content, css_content, js_content, metadata, extra_files) | |
| # Commit files | |
| commit_sha = self._commit_files(repo, files_to_commit, is_revision) | |
| # Enable GitHub Pages | |
| pages_url = self._enable_github_pages(repo) | |
| return { | |
| "repo_name": repo.name, | |
| "repo_url": repo.html_url, | |
| "commit_sha": commit_sha, | |
| "pages_url": pages_url, | |
| "success": True | |
| } | |
| except GithubException as e: | |
| logger.error(f"GitHub API error: status={getattr(e, 'status', None)} data={getattr(e, 'data', None)}") | |
| return { | |
| "success": False, | |
| "error": f"GitHub API error (status {getattr(e, 'status', 'unknown')}): {getattr(e, 'data', None)}" | |
| } | |
| except Exception as e: | |
| logger.error(f"Error in GitHub deployment: {repr(e)}") | |
| return { | |
| "success": False, | |
| "error": repr(e) | |
| } | |
| def _generate_repo_name(self, app_name: str) -> str: | |
| """Generate a unique repository name""" | |
| timestamp = datetime.now().strftime("%Y%m%d%H%M%S") | |
| clean_name = "".join(c for c in app_name if c.isalnum() or c in ('-', '_')).lower() | |
| return f"llm-app-{clean_name}-{timestamp}" | |
| def _create_repository(self, repo_name: str, metadata: Dict[str, Any]): | |
| """Create a new GitHub repository under authenticated user""" | |
| description = metadata.get("description", "LLM Generated Web Application") | |
| try: | |
| repo = self.owner.create_repo( | |
| name=repo_name, | |
| description=description, | |
| private=False, | |
| auto_init=True # ensures default branch exists | |
| ) | |
| logger.info(f"Repository '{repo_name}' created successfully") | |
| return repo | |
| except GithubException as e: | |
| if e.status == 422: # Repo already exists | |
| repo_name = f"{repo_name}-{datetime.now().strftime('%H%M%S')}" | |
| return self._create_repository(repo_name, metadata) | |
| else: | |
| raise | |
| def _prepare_files(self, html_content, css_content, js_content, metadata, extra_files: Optional[Dict[str, str]] = None) -> Dict[str, str]: | |
| """Prepare files for commit""" | |
| files = {} | |
| files["index.html"] = html_content | |
| if css_content and css_content.strip(): | |
| files["styles.css"] = css_content | |
| if js_content and js_content.strip(): | |
| files["script.js"] = js_content | |
| files["README.md"] = self._generate_readme(metadata) | |
| files["LICENSE"] = self._generate_license() | |
| if extra_files: | |
| for name, content in extra_files.items(): | |
| if not isinstance(name, str) or not name: | |
| continue | |
| if isinstance(content, str): | |
| files[name] = content | |
| return files | |
| def _commit_files(self, repo, files: Dict[str, str], is_revision: bool = False) -> str: | |
| """Commit or update files in repo""" | |
| default_branch = repo.default_branch or "main" | |
| last_commit_sha = None | |
| for file_path, content in files.items(): | |
| attempts_remaining = 5 | |
| while attempts_remaining > 0: | |
| try: | |
| try: | |
| existing_file = repo.get_contents(file_path, ref=default_branch) | |
| update = repo.update_file( | |
| path=file_path, | |
| message=("Update file " + file_path) if is_revision else ("Add file " + file_path), | |
| content=content, | |
| sha=existing_file.sha, | |
| branch=default_branch | |
| ) | |
| last_commit_sha = update["commit"].sha | |
| except GithubException as ge: | |
| if getattr(ge, 'status', None) == 404: | |
| created = repo.create_file( | |
| path=file_path, | |
| message="Add file " + file_path, | |
| content=content, | |
| branch=default_branch | |
| ) | |
| last_commit_sha = created["commit"].sha | |
| else: | |
| raise | |
| break | |
| except Exception: | |
| attempts_remaining -= 1 | |
| time.sleep(1) | |
| if attempts_remaining <= 0: | |
| raise | |
| return last_commit_sha or "" | |
| def _enable_github_pages(self, repo) -> str: | |
| """Return expected GitHub Pages URL""" | |
| try: | |
| return f"https://{self.owner.login}.github.io/{repo.name}" | |
| except Exception: | |
| return f"https://{self.owner.login}.github.io/{repo.name}" | |
| def _generate_readme(self, metadata: Dict[str, Any]) -> str: | |
| """Generate README content""" | |
| title = metadata.get("title", "LLM Generated Application") | |
| description = metadata.get("description", "A web application generated by LLM Code Deployment system") | |
| return f"""# {title} | |
| {description} | |
| ## About | |
| Automatically generated by LLM Code Deployment. | |
| ## Usage | |
| Open `index.html` in your browser to run the app. | |
| ## Files | |
| - `index.html` - main HTML | |
| - `styles.css` - CSS (optional) | |
| - `script.js` - JS (optional) | |
| Generated on {datetime.now().strftime("%Y-%m-%d %H:%M:%S UTC")} | |
| """ | |
| def _generate_license(self) -> str: | |
| """MIT License""" | |
| return """MIT License | |
| Copyright (c) 2024 LLM Code Deployment | |
| Permission is hereby granted, free of charge, to any person obtaining a copy | |
| of this software... | |
| """ | |