Comprehensive error handling improvements addressing inconsistent patterns: • Created markitect/exceptions.py with complete domain-specific exception hierarchy - MarkitectError base class with context and cause chaining support - Specific exceptions for Document, AST, Cache, Database, Schema operations - Built-in logging and context preservation • Fixed overly broad exception handling in tddai modules: - issue_fetcher.py: Replace generic Exception with specific Gitea errors - project_manager.py: Proper error translation with context preservation - coverage_analyzer.py: Replace silent suppression with logging • Enhanced cache_service.py error handling: - Specific OSError/PermissionError handling for file operations - Logging integration for unexpected errors - Preserved error collection and reporting • Implemented proper exception chaining patterns: - All error translations use `raise ... from e` for debugging - Preserved original exception context and stack traces - Added docstring declarations of raised exceptions • Benefits: - Eliminates silent error suppression and debugging black holes - Provides specific, actionable error messages - Preserves full error context for troubleshooting - Establishes consistent patterns for future development Resolves issue #21: Error handling standardization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
92 lines
3.5 KiB
Python
92 lines
3.5 KiB
Python
"""
|
|
Issue fetching using the Gitea facade.
|
|
|
|
This module now acts as an adapter to the new gitea package,
|
|
maintaining backwards compatibility while using the cleaner API.
|
|
"""
|
|
|
|
from typing import List, Dict, Any
|
|
|
|
from gitea import GiteaClient, Issue as GiteaIssue, GiteaConfig
|
|
from gitea.exceptions import GiteaError, GiteaNotFoundError, GiteaAuthError, GiteaApiError
|
|
from .config import get_config
|
|
from .exceptions import IssueError
|
|
|
|
# Re-export Issue for backwards compatibility
|
|
Issue = GiteaIssue
|
|
|
|
|
|
class IssueFetcher:
|
|
"""Fetches issues using the Gitea facade."""
|
|
|
|
def __init__(self, config=None):
|
|
self.config = config or get_config()
|
|
|
|
# Create Gitea client from tddai config
|
|
gitea_config = GiteaConfig.from_tddai_config(self.config)
|
|
self.gitea_client = GiteaClient(gitea_config)
|
|
|
|
def fetch_issue(self, issue_number: int) -> Issue:
|
|
"""Fetch a specific issue by number.
|
|
|
|
Raises:
|
|
IssueError: When issue cannot be fetched (with specific context)
|
|
"""
|
|
try:
|
|
return self.gitea_client.issues.get(issue_number)
|
|
except GiteaNotFoundError as e:
|
|
raise IssueError(f"Issue #{issue_number} not found") from e
|
|
except GiteaAuthError as e:
|
|
raise IssueError(f"Authentication failed when fetching issue #{issue_number}") from e
|
|
except GiteaApiError as e:
|
|
raise IssueError(f"API error fetching issue #{issue_number}: {e}") from e
|
|
except GiteaError as e:
|
|
raise IssueError(f"Gitea error fetching issue #{issue_number}: {e}") from e
|
|
|
|
def fetch_issues(self, state: str = "all") -> List[Issue]:
|
|
"""Fetch all issues with optional state filter.
|
|
|
|
Args:
|
|
state: Issue state filter ("all", "open", "closed")
|
|
|
|
Raises:
|
|
IssueError: When issues cannot be fetched (with specific context)
|
|
"""
|
|
try:
|
|
return self.gitea_client.issues.list(state=state)
|
|
except GiteaAuthError as e:
|
|
raise IssueError("Authentication failed when fetching issues") from e
|
|
except GiteaApiError as e:
|
|
raise IssueError(f"API error fetching issues with state '{state}': {e}") from e
|
|
except GiteaError as e:
|
|
raise IssueError(f"Gitea error fetching issues: {e}") from e
|
|
|
|
def fetch_open_issues(self) -> List[Issue]:
|
|
"""Fetch only open issues.
|
|
|
|
Raises:
|
|
IssueError: When open issues cannot be fetched (with specific context)
|
|
"""
|
|
try:
|
|
return self.gitea_client.issues.list_open()
|
|
except GiteaAuthError as e:
|
|
raise IssueError("Authentication failed when fetching open issues") from e
|
|
except GiteaApiError as e:
|
|
raise IssueError(f"API error fetching open issues: {e}") from e
|
|
except GiteaError as e:
|
|
raise IssueError(f"Gitea error fetching open issues: {e}") from e
|
|
|
|
def get_issue_data_dict(self, issue_number: int) -> Dict[str, Any]:
|
|
"""Get issue data as dictionary for workspace creation."""
|
|
issue = self.fetch_issue(issue_number)
|
|
return {
|
|
'number': issue.number,
|
|
'title': issue.title,
|
|
'body': issue.body,
|
|
'state': issue.state,
|
|
'created_at': issue.created_at.isoformat(),
|
|
'updated_at': issue.updated_at.isoformat(),
|
|
'html_url': issue.html_url,
|
|
'assignee': {'login': issue.assignee.login} if issue.assignee else None,
|
|
'labels': [{'name': label.name} for label in issue.labels]
|
|
} |