Files
markitect-main/domain/issues/models.py
tegwick 1fa0f1e84a
Some checks failed
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / performance-tests (push) Has been cancelled
Test Suite / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
fix: Eliminate all 111 test warnings by fixing root causes
- Replace deprecated datetime.utcnow() with datetime.now(timezone.utc)
  across all domain models, services, infrastructure, and test files
- Add missing timezone imports to all affected files
- Fix pytest.ini configuration format from [tool:pytest] to [pytest]
- Remove warning suppressions to expose actual issues
- Ensure proper pytest marker registration for smoke tests

Results:
- 305 passed, 2 skipped, 0 warnings (down from 111 warnings)
- All functionality preserved with modern datetime API usage
- Improved code quality by addressing root causes vs suppression

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-27 20:14:22 +02:00

116 lines
3.5 KiB
Python

"""
Issue domain models.
Contains core business entities and value objects for issue management.
"""
from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime, timezone
from enum import Enum
from .exceptions import IssueStateError
class IssueState(Enum):
"""Issue state enumeration."""
OPEN = "open"
CLOSED = "closed"
IN_PROGRESS = "in_progress"
@dataclass(frozen=True)
class Label:
"""Value object representing an issue label."""
name: str
color: Optional[str] = None
description: Optional[str] = None
def is_state_label(self) -> bool:
"""Check if this is a state-related label."""
return self.name.startswith('status:')
def is_priority_label(self) -> bool:
"""Check if this is a priority-related label."""
return self.name.startswith('priority:')
def is_type_label(self) -> bool:
"""Check if this is a type-related label."""
return self.name in ['bug', 'enhancement', 'feature', 'documentation']
@dataclass(frozen=True)
class LabelCategories:
"""Value object for categorized labels."""
state_labels: List[str]
priority_labels: List[str]
type_labels: List[str]
other_labels: List[str]
@dataclass
class Issue:
"""Issue aggregate root."""
number: int
title: str
state: IssueState
labels: List[Label]
created_at: datetime
updated_at: datetime
milestone: Optional[str] = None
assignee: Optional[str] = None
closed_at: Optional[datetime] = None
def categorize_labels(self) -> LabelCategories:
"""Categorize labels by type - pure domain logic."""
state_labels = [label.name for label in self.labels if label.is_state_label()]
priority_labels = [label.name for label in self.labels if label.is_priority_label()]
type_labels = [label.name for label in self.labels if label.is_type_label()]
other_labels = [
label.name for label in self.labels
if not (label.is_state_label() or label.is_priority_label() or label.is_type_label())
]
return LabelCategories(
state_labels=state_labels,
priority_labels=priority_labels,
type_labels=type_labels,
other_labels=other_labels
)
def close(self) -> None:
"""Close the issue - domain business rule."""
if self.state == IssueState.CLOSED:
raise IssueStateError(
"Issue is already closed",
current_state=self.state.value,
attempted_state=IssueState.CLOSED.value
)
self.state = IssueState.CLOSED
self.closed_at = datetime.now(timezone.utc)
def reopen(self) -> None:
"""Reopen the issue - domain business rule."""
if self.state != IssueState.CLOSED:
raise IssueStateError(
"Issue is not closed",
current_state=self.state.value,
attempted_state=IssueState.OPEN.value
)
self.state = IssueState.OPEN
self.closed_at = None
def add_label(self, label: Label) -> None:
"""Add a label to the issue."""
if label not in self.labels:
self.labels.append(label)
def remove_label(self, label_name: str) -> None:
"""Remove a label from the issue."""
self.labels = [label for label in self.labels if label.name != label_name]
def has_label(self, label_name: str) -> bool:
"""Check if issue has a specific label."""
return any(label.name == label_name for label in self.labels)