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.
105 lines
4.3 KiB
105 lines
4.3 KiB
"""
|
|
GitLab destination provider implementation (Example for extensibility)
|
|
"""
|
|
import logging
|
|
import requests
|
|
from typing import Dict
|
|
from ..base import DestinationProvider, Repository, ProviderError, ConfigurationError
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class GitLabDestinationProvider(DestinationProvider):
|
|
"""GitLab destination provider implementation"""
|
|
|
|
def _validate_config(self) -> None:
|
|
"""Validate GitLab-specific configuration"""
|
|
required_keys = ['url', 'token', 'username']
|
|
missing = [key for key in required_keys if not self.config.get(key)]
|
|
|
|
if missing:
|
|
raise ConfigurationError(f"Missing GitLab configuration: {', '.join(missing)}")
|
|
|
|
self.base_url = self.config['url'].rstrip('/')
|
|
self.token = self.config['token']
|
|
self.username = self.config['username']
|
|
|
|
# Setup HTTP session
|
|
self.session = requests.Session()
|
|
# GitLab uses different token formats - try Private-Token first
|
|
if self.token.startswith('glpat-'):
|
|
# Personal Access Token
|
|
self.session.headers.update({
|
|
'Private-Token': self.token,
|
|
'Content-Type': 'application/json'
|
|
})
|
|
else:
|
|
# OAuth token or other format
|
|
self.session.headers.update({
|
|
'Authorization': f'Bearer {self.token}',
|
|
'Content-Type': 'application/json'
|
|
})
|
|
|
|
# Verify authentication
|
|
try:
|
|
response = self.session.get(f"{self.base_url}/api/v4/user")
|
|
response.raise_for_status()
|
|
self.user_id = response.json()['id']
|
|
except requests.RequestException as e:
|
|
raise ConfigurationError(f"Failed to authenticate with GitLab: {e}")
|
|
|
|
def create_repository(self, repository: Repository, target_name: str) -> bool:
|
|
"""Create a new repository on GitLab"""
|
|
response = None
|
|
try:
|
|
# Check if repository already exists
|
|
if self.repository_exists(target_name):
|
|
logger.warning(f"Repository {target_name} already exists on GitLab")
|
|
return True
|
|
|
|
project_data = {
|
|
'name': target_name,
|
|
'description': repository.description or '',
|
|
'visibility': 'private' if repository.private else 'public',
|
|
'initialize_with_readme': False
|
|
}
|
|
|
|
response = self.session.post(
|
|
f"{self.base_url}/api/v4/projects",
|
|
json=project_data
|
|
)
|
|
response.raise_for_status()
|
|
|
|
logger.info(f"Created repository: {target_name}")
|
|
return True
|
|
|
|
except requests.RequestException as e:
|
|
logger.error(f"Failed to create repository {target_name}: {e}")
|
|
if response and response.status_code == 400:
|
|
# Repository might already exist or name is invalid
|
|
logger.warning(f"Repository creation failed, possibly already exists: {target_name}")
|
|
return self.repository_exists(target_name)
|
|
elif response and response.status_code == 409:
|
|
# Conflict - repository already exists
|
|
logger.warning(f"Repository {target_name} already exists (conflict)")
|
|
return True
|
|
raise ProviderError(f"Failed to create GitLab repository: {e}")
|
|
except Exception as e:
|
|
logger.error(f"Unexpected error creating repository {target_name}: {e}")
|
|
return False
|
|
|
|
def repository_exists(self, name: str) -> bool:
|
|
"""Check if a repository exists"""
|
|
project_path = f"{self.username}/{name}"
|
|
url = f"{self.base_url}/api/v4/projects/{requests.utils.quote(project_path, safe='')}"
|
|
|
|
try:
|
|
response = self.session.get(url)
|
|
return response.status_code == 200
|
|
except requests.RequestException:
|
|
return False
|
|
|
|
def get_authenticated_push_url(self, name: str) -> str:
|
|
"""Get authenticated URL for pushing to repository"""
|
|
base_url = self.base_url.replace('https://', '').replace('http://', '')
|
|
return f"https://oauth2:{self.token}@{base_url}/{self.username}/{name}.git" |