Add organization and task queue features

- Introduced new models for `Organization` and `ReviewTask` to manage organizations and review tasks.
- Implemented API endpoints for CRUD operations on organizations and tasks, including scanning organizations for repositories and PRs.
- Developed a background worker for sequential processing of review tasks with priority handling and automatic retries.
- Created frontend components for managing organizations and monitoring task queues, including real-time updates and filtering options.
- Added comprehensive documentation for organization features and quick start guides.
- Fixed UI issues and improved navigation for better user experience.
This commit is contained in:
Primakov Alexandr Alexandrovich
2025-10-13 00:10:04 +03:00
parent 70889421ea
commit 6ae2d0d8ec
18 changed files with 2725 additions and 3 deletions

View File

@@ -4,6 +4,8 @@ from app.models.repository import Repository
from app.models.pull_request import PullRequest
from app.models.review import Review
from app.models.comment import Comment
from app.models.organization import Organization
from app.models.review_task import ReviewTask
__all__ = ["Repository", "PullRequest", "Review", "Comment"]
__all__ = ["Repository", "PullRequest", "Review", "Comment", "Organization", "ReviewTask"]

View File

@@ -0,0 +1,38 @@
"""Organization model"""
from sqlalchemy import Column, Integer, String, Boolean, DateTime, JSON, Enum
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from datetime import datetime
import enum
from app.database import Base
class OrganizationPlatformEnum(str, enum.Enum):
"""Git platform types"""
GITEA = "gitea"
GITHUB = "github"
BITBUCKET = "bitbucket"
class Organization(Base):
"""Organization model for tracking Git organizations"""
__tablename__ = "organizations"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False) # Имя организации
platform = Column(Enum(OrganizationPlatformEnum), nullable=False)
base_url = Column(String, nullable=False) # https://git.example.com
api_token = Column(String, nullable=True) # Encrypted, optional (uses master token)
webhook_secret = Column(String, nullable=False)
config = Column(JSON, default=dict) # Review configuration
is_active = Column(Boolean, default=True)
last_scan_at = Column(DateTime, nullable=True) # Когда последний раз сканировали
created_at = Column(DateTime, default=datetime.utcnow, server_default=func.now())
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, server_default=func.now())
def __repr__(self):
return f"<Organization(id={self.id}, name={self.name}, platform={self.platform})>"

View File

@@ -0,0 +1,52 @@
"""Review Task Queue model"""
from sqlalchemy import Column, Integer, String, DateTime, Enum, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from datetime import datetime
import enum
from app.database import Base
class TaskStatusEnum(str, enum.Enum):
"""Task status types"""
PENDING = "pending" # В очереди
IN_PROGRESS = "in_progress" # Выполняется
COMPLETED = "completed" # Завершено
FAILED = "failed" # Ошибка
class TaskPriorityEnum(str, enum.Enum):
"""Task priority types"""
LOW = "low"
NORMAL = "normal"
HIGH = "high"
class ReviewTask(Base):
"""Review task queue for sequential processing"""
__tablename__ = "review_tasks"
id = Column(Integer, primary_key=True, index=True)
pull_request_id = Column(Integer, ForeignKey("pull_requests.id"), nullable=False)
status = Column(Enum(TaskStatusEnum), default=TaskStatusEnum.PENDING, nullable=False, index=True)
priority = Column(Enum(TaskPriorityEnum), default=TaskPriorityEnum.NORMAL, nullable=False)
# Tracking
created_at = Column(DateTime, default=datetime.utcnow, server_default=func.now())
started_at = Column(DateTime, nullable=True) # Когда началась обработка
completed_at = Column(DateTime, nullable=True) # Когда завершилась
error_message = Column(String, nullable=True)
# Retry logic
retry_count = Column(Integer, default=0)
max_retries = Column(Integer, default=3)
# Relationships
pull_request = relationship("PullRequest", backref="review_tasks")
def __repr__(self):
return f"<ReviewTask(id={self.id}, pr_id={self.pull_request_id}, status={self.status})>"