You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
3.7 KiB

"""
GitHub destination provider implementation
"""
import logging
from github import Github
from github.GithubException import GithubException
from typing import Dict
from ..base import DestinationProvider, Repository, ProviderError, ConfigurationError
logger = logging.getLogger(__name__)
class GitHubDestinationProvider(DestinationProvider):
"""GitHub destination provider implementation"""
def _validate_config(self) -> None:
"""Validate GitHub-specific configuration"""
required_keys = ['token', 'username']
missing = [key for key in required_keys if not self.config.get(key)]
if missing:
raise ConfigurationError(f"Missing GitHub configuration: {', '.join(missing)}")
self.token = self.config['token']
self.username = self.config['username']
try:
self.github = Github(self.token)
self.user = self.github.get_user()
except GithubException as e:
raise ConfigurationError(f"Failed to authenticate with GitHub: {e}")
def create_repository(self, repository: Repository, target_name: str) -> bool:
"""Create a new repository on GitHub"""
try:
# Check if repository already exists
if self.repository_exists(target_name):
logger.warning(f"Repository {target_name} already exists on GitHub")
return True
logger.info(f"Creating GitHub repository: {target_name}")
self.user.create_repo(
name=target_name,
description=repository.description or '',
private=repository.private,
auto_init=False # Don't auto-init since we'll push existing content
)
logger.info(f"Successfully created repository: {target_name}")
return True
except GithubException as e:
logger.error(f"GitHub API error creating repository {target_name}: {e}")
logger.error(f"GitHub error status: {e.status}")
logger.error(f"GitHub error data: {e.data}")
# Handle specific GitHub errors
if e.status == 422 and 'already exists' in str(e.data).lower():
logger.warning(f"Repository {target_name} already exists (422 error)")
return True
raise ProviderError(f"Failed to create GitHub repository: {e}")
except Exception as e:
logger.error(f"Unexpected error creating GitHub repository {target_name}: {e}")
logger.error(f"Exception type: {type(e).__name__}")
import traceback
logger.error(f"Full traceback: {traceback.format_exc()}")
raise ProviderError(f"Unexpected error creating GitHub repository: {e}")
def repository_exists(self, name: str) -> bool:
"""Check if a repository exists"""
try:
repo = self.user.get_repo(name)
logger.debug(f"Repository {name} exists: {repo.full_name}")
return True
except GithubException as e:
if e.status == 404:
logger.debug(f"Repository {name} does not exist (404)")
return False
else:
logger.warning(f"Error checking if repository {name} exists: {e}")
return False
except Exception as e:
logger.error(f"Unexpected error checking repository existence {name}: {e}")
return False
def get_authenticated_push_url(self, name: str) -> str:
"""Get authenticated URL for pushing to repository"""
return f"https://{self.token}@github.com/{self.username}/{name}.git"