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.
258 lines
7.2 KiB
258 lines
7.2 KiB
# 🏗 Migration Tool Architecture
|
|
|
|
## Overview
|
|
|
|
The Migration Tool has been designed according to the following development principles:
|
|
|
|
- **Single Responsibility Principle (SRP)**: Each class has a unique responsibility
|
|
- **Open/Closed Principle**: Open to extension, closed to modification
|
|
- **Dependency Inversion**: Dependency on abstractions, not implementations
|
|
- **Extensibility**: Ease of adding new providers
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
GitMigrator/
|
|
├── providers/ # Providers for different Git services
|
|
│ ├── __init__.py
|
|
│ ├── base.py # Abstract classes and models
|
|
│ ├── factory.py # Factory to create providers
|
|
│ ├── source/ # Source providers (Gitea, GitLab, etc.)
|
|
│ │ ├── __init__.py
|
|
│ │ ├── gitea.py
|
|
│ │ └── gitlab.py
|
|
│ └── destination/ # Destination providers (GitHub, GitLab, etc.)
|
|
│ ├── __init__.py
|
|
│ ├── github.py
|
|
│ └── gitlab.py
|
|
├── core/ # Core business logic
|
|
│ ├── __init__.py
|
|
│ ├── config.py # Configuration management
|
|
│ └── migration_engine.py # Migration engine
|
|
├── ui/ # User interface
|
|
│ ├── __init__.py
|
|
│ └── interactive_selector.py
|
|
├── main.py # Main entry point
|
|
└── run.sh # Launch script
|
|
```
|
|
|
|
## Module Responsibilities
|
|
|
|
### 🔧 Providers (providers/)
|
|
|
|
#### Base (`providers/base.py`)
|
|
- **Repository**: Unified data model for all providers
|
|
- **SourceProvider**: Abstract interface for source providers
|
|
- **DestinationProvider**: Abstract interface for destination providers
|
|
- **Exceptions**: Specialized exceptions for error handling
|
|
|
|
#### Factory (`providers/factory.py`)
|
|
- Dynamic creation of provider instances
|
|
- Registration of new providers
|
|
- Validation of available provider types
|
|
|
|
#### Source Providers (`providers/source/`)
|
|
- **Gitea**: Implementation for Gitea
|
|
- **GitLab**: Implementation for GitLab (extensibility example)
|
|
|
|
#### Destination Providers (`providers/destination/`)
|
|
- **GitHub**: Implementation for GitHub
|
|
- **GitLab**: Implementation for GitLab (extensibility example)
|
|
|
|
### ⚙ Core (`core/`)
|
|
|
|
#### Configuration (`core/config.py`)
|
|
- Centralized configuration management
|
|
- Multi-provider support via environment variables
|
|
- Configuration parameter validation
|
|
|
|
#### Migration Engine (`core/migration_engine.py`)
|
|
- Migration process orchestration
|
|
- Temporary repository management
|
|
- Git command execution
|
|
- Logging and progress reporting
|
|
|
|
### 🎨 UI (`ui/`)
|
|
|
|
#### Interactive Selector (`ui/interactive_selector.py`)
|
|
- Interactive interface for repository selection
|
|
- Keyboard navigation
|
|
- Renaming system
|
|
- Paginated display
|
|
|
|
## Extensibility
|
|
|
|
### Adding a new source provider
|
|
|
|
1. **Create the file**: `providers/source/my_provider.py`
|
|
|
|
```python
|
|
from typing import List, Optional
|
|
from ..base import SourceProvider, Repository, ProviderError, ConfigurationError
|
|
|
|
class MyProviderSourceProvider(SourceProvider):
|
|
def _validate_config(self) -> None:
|
|
# Validate specific configuration
|
|
pass
|
|
|
|
def get_user_repositories(self) -> List[Repository]:
|
|
# Retrieve user repositories
|
|
pass
|
|
|
|
def get_accessible_repositories(self) -> List[Repository]:
|
|
# Retrieve all accessible repositories
|
|
pass
|
|
|
|
def get_repository_info(self, owner: str, name: str) -> Optional[Repository]:
|
|
# Retrieve specific repository information
|
|
pass
|
|
|
|
def get_authenticated_clone_url(self, repository: Repository) -> str:
|
|
# Generate authenticated clone URL
|
|
pass
|
|
```
|
|
|
|
2. **Register the provider** in `providers/factory.py`:
|
|
|
|
```python
|
|
from .source.my_provider import MyProviderSourceProvider
|
|
|
|
class ProviderFactory:
|
|
_source_providers: Dict[str, Type[SourceProvider]] = {
|
|
'gitea': GiteaSourceProvider,
|
|
'gitlab': GitLabSourceProvider,
|
|
'my_provider': MyProviderSourceProvider, # New provider
|
|
}
|
|
```
|
|
|
|
3. **Add configuration** in `core/config.py`:
|
|
|
|
```python
|
|
def _load_source_config(self) -> Dict[str, Any]:
|
|
if self.source_provider == 'my_provider':
|
|
return {
|
|
'url': os.getenv('MY_PROVIDER_URL'),
|
|
'token': os.getenv('MY_PROVIDER_TOKEN'),
|
|
'username': os.getenv('MY_PROVIDER_USERNAME')
|
|
}
|
|
# ... other providers
|
|
```
|
|
|
|
### Adding a new destination provider
|
|
|
|
The process is identical, but in `providers/destination/`.
|
|
|
|
## Design Patterns Used
|
|
|
|
### 1. Abstract Factory Pattern
|
|
- `ProviderFactory` creates provider instances
|
|
- Allows adding new providers without modifying existing code
|
|
|
|
### 2. Strategy Pattern
|
|
- Providers implement different strategies to access APIs
|
|
- Migration engine uses these strategies transparently
|
|
|
|
### 3. Template Method Pattern
|
|
- `SourceProvider` and `DestinationProvider` define operation skeletons
|
|
- Concrete implementations fill in specific details
|
|
|
|
### 4. Dependency Injection
|
|
- Providers are injected into `MigrationEngine`
|
|
- Facilitates testing and flexibility
|
|
|
|
## Configuration
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Source provider
|
|
SOURCE_PROVIDER=gitea|gitlab
|
|
GITEA_URL=https://gitea.example.com
|
|
GITEA_TOKEN=your_token
|
|
GITEA_USERNAME=your_username
|
|
|
|
# Destination provider
|
|
DESTINATION_PROVIDER=github|gitlab
|
|
GITHUB_TOKEN=your_token
|
|
GITHUB_USERNAME=your_username
|
|
```
|
|
|
|
### Configuration Extensibility
|
|
|
|
To add a new provider, simply add corresponding variables and modify `MigrationConfig`.
|
|
|
|
## Tests
|
|
|
|
### Recommended Structure
|
|
|
|
```
|
|
tests/
|
|
├── unit/
|
|
│ ├── providers/
|
|
│ │ ├── test_gitea_provider.py
|
|
│ │ └── test_github_provider.py
|
|
│ ├── core/
|
|
│ │ └── test_migration_engine.py
|
|
│ └── ui/
|
|
│ └── test_interactive_selector.py
|
|
├── integration/
|
|
│ └── test_full_migration.py
|
|
└── fixtures/
|
|
└── sample_repositories.json
|
|
```
|
|
|
|
### Test Examples
|
|
|
|
```python
|
|
# Provider test
|
|
def test_gitea_provider_validates_config():
|
|
config = {'url': 'https://gitea.com', 'token': 'token', 'username': 'user'}
|
|
provider = GiteaSourceProvider(config)
|
|
assert provider.base_url == 'https://gitea.com'
|
|
|
|
# Migration engine test
|
|
def test_migration_engine_handles_errors():
|
|
source = Mock(spec=SourceProvider)
|
|
dest = Mock(spec=DestinationProvider)
|
|
engine = MigrationEngine(source, dest)
|
|
# Test error handling...
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### 1. Error Handling
|
|
- Specialized exceptions for each error type
|
|
- Appropriate logging at each level
|
|
- Graceful failure handling
|
|
|
|
### 2. Documentation
|
|
- Docstrings for all public methods
|
|
- Type hints for code clarity
|
|
- README and architecture documentation
|
|
|
|
### 3. Security
|
|
- Tokens never logged
|
|
- Temporary repository cleanup
|
|
- User input validation
|
|
|
|
### 4. Performance
|
|
- Pagination for repository lists
|
|
- Possible migration parallelization
|
|
- Efficient memory management
|
|
|
|
## Future Evolutions
|
|
|
|
### Potential Features
|
|
- Incremental migration (changes only)
|
|
- Webhook support
|
|
- Web interface
|
|
- REST API
|
|
- Metadata migration (issues, pull requests)
|
|
|
|
### New Providers
|
|
- Bitbucket
|
|
- Azure DevOps
|
|
- Sourcehut
|
|
- Codeberg
|
|
|
|
The current architecture allows easy addition of these features without major restructuring. |