"""Main shim class that provides GitHub-compatible interface for Gitea.""" import os from typing import Optional, Dict, Any, List try: # When running tests or using as a module from models.repository import Repository from models.user import User from models.pull_request import PullRequest except ImportError: # When using as a package from .models.repository import Repository from .models.user import User from .models.pull_request import PullRequest # Mock the Gitea import for testing try: from gitea import Gitea except ImportError: # Mock Gitea for testing purposes class Gitea: def __init__(self, url, token): self.url = url self.token = token class GiteaGitHubShim: """ A shim class that provides a GitHub-compatible interface for Gitea. This class mimics the PyGitHub's Github class API, translating calls to the py-gitea SDK. """ def __init__(self, base_url_or_token: Optional[str] = None, base_url: Optional[str] = None, timeout: int = 60, per_page: int = 30): """ Initialize the Gitea client with GitHub-compatible interface. Args: base_url_or_token: If only one arg provided, treated as token (GitHub compat) base_url: The Gitea instance URL timeout: Request timeout in seconds per_page: Number of items per page for pagination """ # Handle GitHub-style initialization where only token is provided if base_url is None and base_url_or_token: # In GitHub mode, we expect GITEA_URL to be set self.token = base_url_or_token self.base_url = os.getenv('GITEA_URL', 'http://localhost:3000') else: self.token = base_url_or_token self.base_url = base_url or os.getenv('GITEA_URL', 'http://localhost:3000') # Remove trailing slash from base URL self.base_url = self.base_url.rstrip('/') # Initialize the Gitea client self._gitea = Gitea(self.base_url, self.token) self.timeout = timeout self.per_page = per_page def get_repo(self, full_name_or_id: str) -> Repository: """ Get a repository by its full name (owner/repo) or ID. Args: full_name_or_id: Repository full name (owner/repo) or ID Returns: Repository object with GitHub-compatible interface """ if '/' in str(full_name_or_id): # It's a full name (owner/repo) owner, repo_name = full_name_or_id.split('/', 1) try: gitea_repo = self._gitea.get_repo(owner, repo_name) except Exception as e: # Handle case where repo doesn't exist raise Exception(f"Repository {full_name_or_id} not found: {str(e)}") else: # It's an ID - Gitea doesn't support this directly # We'd need to implement a search or listing mechanism raise NotImplementedError("Getting repository by ID is not yet supported") return Repository(gitea_repo, self._gitea) def get_user(self, login: Optional[str] = None) -> User: """ Get a user by login name or get the authenticated user. Args: login: Username to get. If None, returns authenticated user. Returns: User object with GitHub-compatible interface """ if login is None: # Get authenticated user gitea_user = self._gitea.get_user() else: # Get specific user gitea_user = self._gitea.get_user(login) return User(gitea_user, self._gitea) def get_organization(self, login: str): """ Get an organization by login name. Args: login: Organization name Returns: Organization object (not yet implemented) """ # Organizations in Gitea are similar to GitHub gitea_org = self._gitea.get_org(login) # TODO: Implement Organization model return gitea_org def create_repo(self, name: str, **kwargs) -> Repository: """ Create a new repository. Args: name: Repository name **kwargs: Additional parameters (description, private, etc.) Returns: Repository object """ # Map GitHub parameters to Gitea parameters gitea_params = { 'name': name, 'description': kwargs.get('description', ''), 'private': kwargs.get('private', False), 'auto_init': kwargs.get('auto_init', False), 'gitignores': kwargs.get('gitignore_template', ''), 'license': kwargs.get('license_template', ''), 'readme': kwargs.get('readme', '') } gitea_repo = self._gitea.create_repo(**gitea_params) return Repository(gitea_repo, self._gitea) def get_api_status(self) -> Dict[str, Any]: """Get API status information.""" # Gitea doesn't have a direct equivalent, return version info try: version = self._gitea.get_version() return { 'status': 'good', 'version': version, 'api': 'gitea' } except Exception: return { 'status': 'unknown', 'version': 'unknown', 'api': 'gitea' } def get_rate_limit(self) -> Dict[str, Any]: """ Get rate limit information. Note: Gitea doesn't have rate limiting like GitHub, so we return mock data indicating no limits. """ return { 'rate': { 'limit': 999999, 'remaining': 999999, 'reset': 0 } } def search_repositories(self, query: str, **kwargs) -> List[Repository]: """ Search repositories. Args: query: Search query **kwargs: Additional search parameters Returns: List of Repository objects """ # Gitea search might have different parameters gitea_repos = self._gitea.search_repos(query, **kwargs) return [Repository(repo, self._gitea) for repo in gitea_repos] def search_users(self, query: str, **kwargs) -> List[User]: """ Search users. Args: query: Search query **kwargs: Additional search parameters Returns: List of User objects """ gitea_users = self._gitea.search_users(query, **kwargs) return [User(user, self._gitea) for user in gitea_users] def get_emojis(self) -> Dict[str, str]: """ Get available emojis. Note: Gitea might not support this, return empty dict """ return {} def get_gitignore_templates(self) -> List[str]: """ Get available gitignore templates. Returns: List of template names """ try: templates = self._gitea.get_gitignore_templates() return [t.name for t in templates] except Exception: return [] def get_license_templates(self) -> List[Dict[str, Any]]: """ Get available license templates. Returns: List of license template objects """ try: licenses = self._gitea.get_license_templates() return [ { 'key': lic.key, 'name': lic.name, 'url': lic.url, 'spdx_id': lic.spdx_id } for lic in licenses ] except Exception: return []