# Task 2: Service Layer Refactoring
## Overview
**Priority**: Medium
**Goal**: Refactor service layer into single-responsibility services
**Target**: Clean separation between core operations and workflows
**Status**: ✅ COMPLETE
## Current Problem
The current service architecture has mixed responsibilities:
- `CommitzenService` handles both Commitizen operations AND git coordination
- `GitPythonService` is well-structured but located in root directory
- No clear separation between core operations and complex workflows
- Configuration and validation logic scattered across services
This makes the code:
- Harder to test individual components
- Difficult to reuse services in different contexts
- Challenging to maintain clear boundaries
- Complex to understand service interactions
## Target Structure
```
src/commit_helper_mcp/services/
├── __init__.py
├── commitizen_core.py # Pure Commitizen operations
├── gitpython_core.py # Pure GitPython operations (moved)
├── commit_orchestrator.py # Git + Commitizen workflow orchestration
├── repository_manager.py # Multi-repository handling
└── validation_service.py # Message validation logic
```
## Implementation Steps
### Step 1: Create Services Directory
**File**: `src/commit_helper_mcp/services/__init__.py`
```python
"""
Service Layer for Commit Helper MCP
This package contains focused, single-responsibility services that handle
different aspects of the commit workflow.
"""
from .commitizen_core import CommitzenCore
from .gitpython_core import GitPythonCore
from .commit_orchestrator import CommitOrchestrator
from .repository_manager import RepositoryManager
from .validation_service import ValidationService
__all__ = [
'CommitzenCore',
'GitPythonCore',
'CommitOrchestrator',
'RepositoryManager',
'ValidationService'
]
```
### Step 2: Extract CommitzenCore Service
**File**: `src/commit_helper_mcp/services/commitizen_core.py`
**Responsibilities**:
- Pure Commitizen operations (no git dependencies)
- Plugin management and configuration
- Message generation and validation
- Schema and example retrieval
**Extract from current `CommitzenService`**:
```python
class CommitzenCore:
"""Pure Commitizen operations without git dependencies."""
def __init__(self, repo_path: Optional[str] = None):
# Initialize Commitizen config and plugin adapter
def get_questions(self) -> List[Dict[str, Any]]:
# Extract from current implementation
def generate_message(self, answers: Dict[str, Any]) -> str:
# Extract from current implementation
def validate_message(self, message: str) -> bool:
# Extract from current implementation
def get_example(self) -> str:
# Extract from current implementation
def get_schema(self) -> Dict[str, Any]:
# Extract from current implementation
def get_info(self) -> Dict[str, Any]:
# Extract from current implementation
def get_commit_types(self) -> List[Dict[str, str]]:
# Extract from current implementation
def refresh_config(self) -> None:
# Extract from current implementation
```
### Step 3: Move GitPython Service
**File**: `src/commit_helper_mcp/services/gitpython_core.py`
**Action**: Move `src/commit_helper_mcp/gitpython_service.py` to services directory
**Changes**:
- Update imports in files that use GitPythonService
- Ensure all functionality remains the same
- Update class name to `GitPythonCore` for consistency
### Step 4: Create CommitOrchestrator Service
**File**: `src/commit_helper_mcp/services/commit_orchestrator.py`
**Responsibilities**:
- Coordinate between CommitzenCore and GitPythonCore
- Handle complex workflows that require both services
- Manage preview and execution workflows
- Orchestrate multi-step operations
```python
class CommitOrchestrator:
"""Orchestrates complex workflows between Commitizen and Git operations."""
def __init__(self, commitizen_core: CommitzenCore, gitpython_core: GitPythonCore):
self.commitizen = commitizen_core
self.git = gitpython_core
def preview_commit_operation(self, message: str, **kwargs) -> Dict[str, Any]:
"""Orchestrate: message validation + git preview"""
def execute_commit_operation(self, message: str, **kwargs) -> Dict[str, Any]:
"""Orchestrate: message validation + git execution + safety checks"""
def validate_commit_readiness(self, repo_path: str) -> Dict[str, Any]:
"""Comprehensive validation combining git status and message requirements"""
def smart_commit_suggestions(self, repo_path: str, **kwargs) -> Dict[str, Any]:
"""Generate intelligent commit suggestions based on repository changes"""
def batch_commit_analysis(self, repo_path: str, file_groups: List[Dict], **kwargs) -> Dict[str, Any]:
"""Analyze multiple file groups for batch commit operations"""
```
### Step 5: Create RepositoryManager Service
**File**: `src/commit_helper_mcp/services/repository_manager.py`
**Responsibilities**:
- Handle multi-repository targeting
- Manage environment variables and path resolution
- Validate repository access and security
- Coordinate repository-specific configurations
```python
class RepositoryManager:
"""Manages repository targeting and multi-repository operations."""
def __init__(self):
self._repository_cache = {}
def resolve_repository_path(self, repo_path: Optional[str] = None) -> str:
"""Resolve repository path with priority order"""
def validate_repository_access(self, repo_path: str) -> bool:
"""Validate repository exists and is accessible"""
def get_repository_services(self, repo_path: str) -> Tuple[CommitzenCore, GitPythonCore]:
"""Get or create services for specific repository"""
def manage_environment_variables(self) -> Dict[str, str]:
"""Handle COMMITIZEN_REPO_PATH and other environment variables"""
def clear_repository_cache(self) -> None:
"""Clear cached repository services"""
```
### Step 6: Create ValidationService
**File**: `src/commit_helper_mcp/services/validation_service.py`
**Responsibilities**:
- Centralized validation logic
- Input sanitization and security
- Cross-cutting validation concerns
- Standardized validation responses
```python
class ValidationService:
"""Centralized validation logic for all operations."""
@staticmethod
def validate_commit_message(message: str, commitizen_core: CommitzenCore) -> Dict[str, Any]:
"""Validate commit message with detailed feedback"""
@staticmethod
def validate_repository_state(git_core: GitPythonCore) -> Dict[str, Any]:
"""Validate repository is ready for operations"""
@staticmethod
def validate_file_paths(file_paths: List[str], repo_path: str) -> Dict[str, Any]:
"""Validate file paths are safe and within repository"""
@staticmethod
def sanitize_inputs(**kwargs) -> Dict[str, Any]:
"""Sanitize all inputs for security"""
@staticmethod
def validate_parameters(params: Dict[str, Any], schema: Dict[str, Any]) -> Dict[str, Any]:
"""Validate parameters against schema"""
```
### Step 7: Update CommitzenService
**File**: `src/commit_helper_mcp/commitizen_service.py`
Transform into a facade that coordinates the new services:
```python
class CommitzenService:
"""
Facade service that coordinates the new service architecture.
Maintains backward compatibility while delegating to specialized services.
"""
def __init__(self, repo_path: Optional[str] = None):
self.repository_manager = RepositoryManager()
self.repo_path = self.repository_manager.resolve_repository_path(repo_path)
# Initialize core services
self.commitizen_core = CommitzenCore(self.repo_path)
self.git_core = GitPythonCore(self.repo_path) if self._git_available() else None
self.orchestrator = CommitOrchestrator(self.commitizen_core, self.git_core) if self.git_core else None
# Maintain compatibility properties
self.git_enabled = self.git_core is not None
self.git_implementation = "GitPython" if self.git_core else None
self.git_service = self.git_core # Backward compatibility
# Delegate methods to appropriate services while maintaining existing interface
def generate_message(self, answers: Dict[str, Any]) -> str:
return self.commitizen_core.generate_message(answers)
def validate_message(self, message: str) -> bool:
return self.commitizen_core.validate_message(message)
def preview_commit_operation(self, message: str, **kwargs) -> Dict[str, Any]:
if self.orchestrator:
return self.orchestrator.preview_commit_operation(message, **kwargs)
else:
return {"error": "Git operations not available"}
# ... other delegated methods
```
## Implementation Guidelines
### Service Design Principles
1. **Single Responsibility**: Each service has one clear purpose
2. **Dependency Injection**: Services receive dependencies via constructor
3. **Interface Segregation**: Clean, focused interfaces
4. **Stateless Operations**: Prefer stateless methods where possible
### Backward Compatibility
1. **Facade Pattern**: CommitzenService becomes a facade
2. **Interface Preservation**: All existing methods remain available
3. **Gradual Migration**: Can migrate callers incrementally
### Testing Strategy
1. **Unit Tests**: Test each service in isolation
2. **Integration Tests**: Test service interactions
3. **Compatibility Tests**: Ensure existing code still works
## Migration Steps
### Phase 2.1: Create New Services
1. Create services directory and `__init__.py`
2. Extract CommitzenCore from CommitzenService
3. Move GitPythonService to services directory
4. Create RepositoryManager and ValidationService
### Phase 2.2: Create Orchestrator
1. Create CommitOrchestrator service
2. Move complex workflow logic from CommitzenService
3. Test orchestrator with new services
### Phase 2.3: Update Facade
1. Transform CommitzenService into facade
2. Update all method implementations to delegate
3. Ensure backward compatibility
### Phase 2.4: Update Imports
1. Update imports in server modules
2. Update test imports
3. Verify all functionality works
## Validation Criteria
### Success Metrics
- [ ] All services have single, clear responsibility
- [ ] CommitzenService maintains backward compatibility
- [ ] All existing tests pass
- [ ] New services are easily testable in isolation
- [ ] Service dependencies are clear and minimal
- [ ] Code is more maintainable and understandable
### Service Size Targets
- `commitizen_core.py`: ~200-300 lines
- `gitpython_core.py`: ~400 lines (moved, not changed)
- `commit_orchestrator.py`: ~200-300 lines
- `repository_manager.py`: ~150-200 lines
- `validation_service.py`: ~100-150 lines
## Potential Issues and Solutions
### Issue 1: Service Circular Dependencies
**Problem**: Services might depend on each other circularly
**Solution**: Use dependency injection and careful interface design
### Issue 2: Backward Compatibility
**Problem**: Existing code might break with new architecture
**Solution**: Maintain facade pattern in CommitzenService
### Issue 3: Service Initialization Order
**Problem**: Services might need specific initialization order
**Solution**: Use factory pattern or dependency injection container
## Testing Plan
### Unit Tests
- Test each service independently with mocked dependencies
- Verify service interfaces work as expected
- Test error handling in each service
### Integration Tests
- Test service interactions work correctly
- Verify orchestrator coordinates services properly
- Test repository manager handles multiple repositories
### Compatibility Tests
- Run all existing tests to ensure backward compatibility
- Test that MCP tools still work with facade
- Verify performance is not degraded
## Dependencies
### Prerequisites
- Task 1 (Server Decomposition) completed
- Understanding of dependency injection patterns
- Familiarity with facade pattern
### Affected Files
- `src/commit_helper_mcp/commitizen_service.py` (major refactor)
- `src/commit_helper_mcp/gitpython_service.py` (move to services/)
- All server modules (import updates)
- Test files (potential import updates)
## Estimated Effort
**Time Estimate**: 15 minutes
**Complexity**: High
**Risk Level**: Medium (significant architectural changes)
## Next Steps
After completing this task:
1. Proceed to Task 3: Configuration Management
2. Update documentation to reflect new service architecture
3. Consider adding service-level documentation
4. Update development guidelines for service patterns