Files
Yiqun/gitea-shim/python/gitea_github_shim.py

251 lines
8.0 KiB
Python

"""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 []