fix(release): fail closed on dashboard parse errors
This commit is contained in:
@@ -6,10 +6,10 @@ from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
from .catalog import collect_catalog_snapshot
|
||||
from .contracts import collect_contracts
|
||||
from .contracts import collect_contracts_with_diagnostics
|
||||
from .git_state import collect_repository_snapshot, read_pyproject_version
|
||||
from .migrations import collect_migration_snapshots
|
||||
from .model import DashboardSummary, ReleaseDashboard, RepositorySnapshot
|
||||
from .model import DashboardCollectionError, DashboardSummary, ReleaseDashboard, RepositorySnapshot
|
||||
from .workspace import META_ROOT, core_root, load_repository_specs, resolve_workspace_root
|
||||
|
||||
|
||||
@@ -26,10 +26,25 @@ def build_dashboard(
|
||||
channel: str = "stable",
|
||||
) -> ReleaseDashboard:
|
||||
resolved_workspace = resolve_workspace_root(workspace_root)
|
||||
collection_errors: list[DashboardCollectionError] = []
|
||||
if check_public_catalog is None:
|
||||
check_public_catalog = online
|
||||
if target_version is None:
|
||||
target_version = read_pyproject_version(core_root(resolved_workspace))
|
||||
try:
|
||||
target_version = read_pyproject_version(core_root(resolved_workspace))
|
||||
except Exception as exc: # noqa: BLE001 - bounded fail-closed diagnostic.
|
||||
collection_errors.append(
|
||||
DashboardCollectionError(
|
||||
code="core_version_metadata_unreadable",
|
||||
message=f"Core version metadata could not be read or parsed ({type(exc).__name__}).",
|
||||
remediation=(
|
||||
"Repair govoplan-core/pyproject.toml, refresh the dashboard, "
|
||||
"then rebuild the release plan."
|
||||
),
|
||||
repo="govoplan-core",
|
||||
source="govoplan-core/pyproject.toml",
|
||||
)
|
||||
)
|
||||
target_tag = f"v{target_version}" if target_version else None
|
||||
|
||||
repositories = tuple(
|
||||
@@ -38,7 +53,11 @@ def build_dashboard(
|
||||
)
|
||||
catalog = collect_catalog_snapshot(workspace_root=resolved_workspace, channel=channel, check_public=check_public_catalog)
|
||||
migrations = collect_migration_snapshots() if include_migrations else ()
|
||||
contracts = collect_contracts(repositories) if include_contracts else ()
|
||||
if include_contracts:
|
||||
contracts, contract_errors = collect_contracts_with_diagnostics(repositories)
|
||||
collection_errors.extend(contract_errors)
|
||||
else:
|
||||
contracts = ()
|
||||
return ReleaseDashboard(
|
||||
generated_at=datetime.now(tz=UTC).replace(microsecond=0).isoformat().replace("+00:00", "Z"),
|
||||
meta_root=str(META_ROOT),
|
||||
@@ -47,28 +66,34 @@ def build_dashboard(
|
||||
target_tag=target_tag,
|
||||
online=online or check_remote_tags or check_public_catalog,
|
||||
include_migrations=include_migrations,
|
||||
summary=summarize(repositories, target_tag=target_tag),
|
||||
summary=summarize(repositories, target_tag=target_tag, collection_errors=tuple(collection_errors)),
|
||||
repositories=repositories,
|
||||
catalog=catalog,
|
||||
migrations=migrations,
|
||||
contracts=contracts,
|
||||
collection_errors=tuple(collection_errors),
|
||||
)
|
||||
|
||||
|
||||
def summarize(repositories: tuple[RepositorySnapshot, ...], *, target_tag: str | None) -> DashboardSummary:
|
||||
def summarize(
|
||||
repositories: tuple[RepositorySnapshot, ...],
|
||||
*,
|
||||
target_tag: str | None,
|
||||
collection_errors: tuple[DashboardCollectionError, ...] = (),
|
||||
) -> DashboardSummary:
|
||||
missing_count = sum(1 for repo in repositories if not repo.exists or not repo.is_git)
|
||||
dirty_count = sum(1 for repo in repositories if repo.dirty)
|
||||
ahead_count = sum(1 for repo in repositories if repo.ahead)
|
||||
behind_count = sum(1 for repo in repositories if repo.behind)
|
||||
no_head_count = sum(1 for repo in repositories if repo.exists and repo.is_git and not repo.has_head)
|
||||
error_count = sum(1 for repo in repositories if repo.errors)
|
||||
error_count = sum(1 for repo in repositories if repo.errors) + len(collection_errors)
|
||||
safe_directory_count = sum(1 for repo in repositories if repo.safe_directory_required)
|
||||
local_target_tag_missing_count = (
|
||||
sum(1 for repo in repositories if repo.local_target_tag_exists is False and repo.versions.primary == target_tag.removeprefix("v"))
|
||||
if target_tag
|
||||
else 0
|
||||
)
|
||||
if missing_count or behind_count or safe_directory_count:
|
||||
if missing_count or behind_count or safe_directory_count or collection_errors:
|
||||
status = "blocked"
|
||||
elif dirty_count or ahead_count or no_head_count or error_count or local_target_tag_missing_count:
|
||||
status = "attention"
|
||||
|
||||
Reference in New Issue
Block a user