feat: добавлена пометка типа операции (Build/Push) в истории сборок Dockerfile

- Добавлена колонка 'Тип' во все таблицы истории сборок
- Для push операций отображается registry вместо платформ
- Сохранение пользователя при создании push лога
- Исправлена ошибка с logger в push_docker_image endpoint
- Улучшено отображение истории сборок с визуальными индикаторами
This commit is contained in:
Сергей Антропов
2026-02-15 22:59:02 +03:00
parent 23e1a6037b
commit 1fbf9185a2
232 changed files with 38075 additions and 5 deletions

View File

@@ -0,0 +1,226 @@
"""
Сервис для работы с историей команд и тестов
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""
from datetime import datetime
from typing import Dict, List, Optional
from sqlalchemy.orm import Session
from app.models.database import (
CommandHistory, TestResult, DeploymentHistory,
ExportHistory, ImportHistory
)
from app.db.session import get_db
class HistoryService:
"""Сервис для работы с историей"""
def save_command(
self,
command: str,
command_type: str,
role_name: Optional[str] = None,
preset_name: Optional[str] = None,
status: str = "running",
user: Optional[str] = None
) -> int:
"""Сохранение команды в историю"""
db = next(get_db())
try:
cmd_history = CommandHistory(
command=command,
command_type=command_type,
role_name=role_name,
preset_name=preset_name,
status=status,
user=user,
started_at=datetime.utcnow()
)
db.add(cmd_history)
db.commit()
db.refresh(cmd_history)
return cmd_history.id
finally:
db.close()
def update_command(
self,
command_id: int,
status: str,
stdout: Optional[str] = None,
stderr: Optional[str] = None,
returncode: Optional[int] = None
):
"""Обновление команды после выполнения"""
db = next(get_db())
try:
cmd = db.query(CommandHistory).filter(CommandHistory.id == command_id).first()
if cmd:
cmd.status = status
cmd.stdout = stdout
cmd.stderr = stderr
cmd.returncode = returncode
cmd.finished_at = datetime.utcnow()
if cmd.started_at:
duration = (cmd.finished_at - cmd.started_at).total_seconds()
cmd.duration = int(duration)
db.commit()
finally:
db.close()
def get_command_history(
self,
limit: int = 50,
role_name: Optional[str] = None,
command_type: Optional[str] = None
) -> List[Dict]:
"""Получение истории команд"""
db = next(get_db())
try:
query = db.query(CommandHistory)
if role_name:
query = query.filter(CommandHistory.role_name == role_name)
if command_type:
query = query.filter(CommandHistory.command_type == command_type)
commands = query.order_by(CommandHistory.started_at.desc()).limit(limit).all()
return [
{
"id": cmd.id,
"command": cmd.command,
"command_type": cmd.command_type,
"role_name": cmd.role_name,
"preset_name": cmd.preset_name,
"status": cmd.status,
"started_at": cmd.started_at.isoformat() if cmd.started_at else None,
"finished_at": cmd.finished_at.isoformat() if cmd.finished_at else None,
"duration": cmd.duration
}
for cmd in commands
]
finally:
db.close()
def save_test_result(
self,
command_id: int,
role_name: str,
preset_name: Optional[str],
test_type: str,
status: str,
output: Optional[str] = None,
error: Optional[str] = None,
duration: Optional[int] = None
) -> int:
"""Сохранение результата теста"""
db = next(get_db())
try:
test_result = TestResult(
command_id=command_id,
role_name=role_name,
preset_name=preset_name,
test_type=test_type,
status=status,
output=output,
error=error,
duration=duration,
created_at=datetime.utcnow()
)
db.add(test_result)
db.commit()
db.refresh(test_result)
return test_result.id
finally:
db.close()
def save_deployment(
self,
role_name: str,
inventory: str,
hosts: List[str],
status: str,
output: Optional[str] = None,
error: Optional[str] = None,
user: Optional[str] = None
) -> int:
"""Сохранение истории деплоя"""
db = next(get_db())
try:
deployment = DeploymentHistory(
role_name=role_name,
inventory=inventory,
hosts=hosts,
status=status,
output=output,
error=error,
user=user,
started_at=datetime.utcnow()
)
db.add(deployment)
db.commit()
db.refresh(deployment)
return deployment.id
finally:
db.close()
def save_export(
self,
role_name: str,
repo_url: str,
branch: str,
version: Optional[str],
commit_hash: Optional[str],
status: str,
user: Optional[str] = None
) -> int:
"""Сохранение истории экспорта"""
db = next(get_db())
try:
export = ExportHistory(
role_name=role_name,
repo_url=repo_url,
branch=branch,
version=version,
commit_hash=commit_hash,
status=status,
user=user,
started_at=datetime.utcnow(),
finished_at=datetime.utcnow() if status != "running" else None
)
db.add(export)
db.commit()
db.refresh(export)
return export.id
finally:
db.close()
def save_import(
self,
role_name: str,
source_type: str,
source_url: Optional[str],
status: str,
user: Optional[str] = None
) -> int:
"""Сохранение истории импорта"""
db = next(get_db())
try:
import_history = ImportHistory(
role_name=role_name,
source_type=source_type,
source_url=source_url,
status=status,
user=user,
started_at=datetime.utcnow(),
finished_at=datetime.utcnow() if status != "running" else None
)
db.add(import_history)
db.commit()
db.refresh(import_history)
return import_history.id
finally:
db.close()