chore(repo): replace app symlink/submodule with in-repo app directory; enable committing app/Dockerfile and tooling\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
a12270ad01
commit
ae2c674b81
25 files changed
+3417
-1
No files matched your search
@@ -0,0 +1,151 @@
|
||||
"""Data models for the migration pipeline."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Enumerations
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class Track(str, Enum):
|
||||
"""Migration track."""
|
||||
A = "track_a_conservative" # Qt5→Qt6 compatibility only
|
||||
B = "track_b_modern" # Qt6 + C++20 modernisation
|
||||
|
||||
|
||||
class FileStatus(str, Enum):
|
||||
PENDING = "pending"
|
||||
IN_PROGRESS = "in_progress"
|
||||
SUCCESS = "success"
|
||||
QUARANTINED = "quarantined"
|
||||
|
||||
|
||||
class FailureClass(str, Enum):
|
||||
COMPILE_ERROR = "compile_error"
|
||||
LINK_ERROR = "link_error"
|
||||
TEST_FAILURE = "test_failure"
|
||||
TEST_BUILD_FAILURE = "test_build_failure"
|
||||
BUDGET_EXCEEDED = "budget_exceeded"
|
||||
API_ERROR = "api_error"
|
||||
CHUNK_MERGE_ERROR = "chunk_merge_error"
|
||||
UNKNOWN = "unknown"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Chunk
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class CodeChunk:
|
||||
"""A contiguous slice of a C++ source file."""
|
||||
index: int
|
||||
start_line: int # 0-based, inclusive
|
||||
end_line: int # 0-based, exclusive
|
||||
content: str
|
||||
boundary_type: str # "complete" | "semantic" | "fallback"
|
||||
|
||||
@property
|
||||
def line_count(self) -> int:
|
||||
return self.end_line - self.start_line
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Quality gates
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class QualityGateResult:
|
||||
"""Result of all quality gates for one migration attempt."""
|
||||
build_ok: bool = False
|
||||
build_errors: str = ""
|
||||
build_warnings: list[str] = field(default_factory=list)
|
||||
|
||||
existing_tests_ok: bool = False
|
||||
new_tests_ok: bool = False
|
||||
test_output: str = ""
|
||||
test_warnings: list[str] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def all_gates_passed(self) -> bool:
|
||||
"""Hard gates: build green, all tests green.
|
||||
Warnings are advisory and do NOT block (config.WARNINGS_ARE_BLOCKING=False)."""
|
||||
from migration_pipeline.config import WARNINGS_ARE_BLOCKING
|
||||
if WARNINGS_ARE_BLOCKING:
|
||||
return (
|
||||
self.build_ok
|
||||
and self.existing_tests_ok
|
||||
and self.new_tests_ok
|
||||
and not self.build_warnings
|
||||
and not self.test_warnings
|
||||
)
|
||||
return self.build_ok and self.existing_tests_ok and self.new_tests_ok
|
||||
|
||||
@property
|
||||
def total_warnings(self) -> int:
|
||||
return len(self.build_warnings) + len(self.test_warnings)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Quarantine
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class QuarantineEntry:
|
||||
"""Rich metadata for a file that could not be migrated automatically."""
|
||||
file_path: str
|
||||
track: str
|
||||
failure_class: str
|
||||
last_error: str # truncated at 2000 chars
|
||||
affected_apis: list[str]
|
||||
chunk_info: str
|
||||
manual_recommendation: str
|
||||
timestamp: str # ISO-8601 UTC
|
||||
retry_count: int
|
||||
elapsed_seconds: float
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Per-file result
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class FileResult:
|
||||
file_path: str
|
||||
track: str
|
||||
status: str # FileStatus value
|
||||
iterations: int
|
||||
elapsed_seconds: float
|
||||
gate: QualityGateResult
|
||||
quarantine_entry: Optional[QuarantineEntry] = None
|
||||
migrated_path: str = ""
|
||||
test_name: str = ""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Batch result
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class BatchResult:
|
||||
"""Aggregated result for one batch + one track."""
|
||||
batch_id: str
|
||||
track: str
|
||||
branch: str
|
||||
total_files: int
|
||||
success_count: int = 0
|
||||
quarantine_count: int = 0
|
||||
total_warnings: int = 0
|
||||
mean_elapsed_seconds: float = 0.0
|
||||
results: list[FileResult] = field(default_factory=list)
|
||||
|
||||
@property
|
||||
def success_rate(self) -> float:
|
||||
return self.success_count / self.total_files if self.total_files else 0.0
|
||||
|
||||
@property
|
||||
def quarantine_rate(self) -> float:
|
||||
return self.quarantine_count / self.total_files if self.total_files else 0.0
|
||||
Reference in new issue
Block a user