fix(plan): address review findings on worktree sandbox cleanup
CI / status-check (pull_request) Blocked by required conditions
CI / helm (pull_request) Successful in 29s
CI / build (pull_request) Successful in 3m47s
CI / lint (pull_request) Successful in 3m57s
CI / quality (pull_request) Successful in 4m14s
CI / unit_tests (pull_request) Failing after 4m18s
CI / typecheck (pull_request) Successful in 4m35s
CI / security (pull_request) Successful in 4m46s
CI / coverage (pull_request) Waiting to run
CI / docker (pull_request) Has been skipped
CI / push-validation (pull_request) Successful in 22s
CI / e2e_tests (pull_request) Successful in 6m54s
CI / integration_tests (pull_request) Successful in 6m58s
CI / status-check (pull_request) Blocked by required conditions
CI / helm (pull_request) Successful in 29s
CI / build (pull_request) Successful in 3m47s
CI / lint (pull_request) Successful in 3m57s
CI / quality (pull_request) Successful in 4m14s
CI / unit_tests (pull_request) Failing after 4m18s
CI / typecheck (pull_request) Successful in 4m35s
CI / security (pull_request) Successful in 4m46s
CI / coverage (pull_request) Waiting to run
CI / docker (pull_request) Has been skipped
CI / push-validation (pull_request) Successful in 22s
CI / e2e_tests (pull_request) Successful in 6m54s
CI / integration_tests (pull_request) Successful in 6m58s
- Move get_container and GitWorktreeSandbox imports to module top level (G2: satisfies top-of-file import requirement) - Replace bare 'except Exception' with specific NotFoundError, CleverAgentsError, SQLAlchemyError catches with structlog logging (G3: proper error handling) - Add input validation: empty/whitespace plan_id returns early with warning log (G4: guard against invalid input) - cleanup_stale() now tracks branch_deleted flag and logs partial cleanup warning when branch deletion fails (G5: accurate reporting) - Check off all issue #9230 subtasks (G7: process compliance) ISSUES CLOSED: #9230
This commit is contained in:
@@ -31,6 +31,7 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Annotated, Any, Literal, cast
|
||||
|
||||
import structlog
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
@@ -39,13 +40,18 @@ from rich.table import Table
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
from cleveragents.a2a.models import A2aRequest
|
||||
from cleveragents.application.container import get_container
|
||||
from cleveragents.cli.formatting import OutputFormat, format_output
|
||||
from cleveragents.core.exceptions import (
|
||||
CleverAgentsError,
|
||||
NotFoundError,
|
||||
PlanError,
|
||||
ValidationError,
|
||||
)
|
||||
from cleveragents.domain.models.core.plan import PlanPhase, ProcessingState
|
||||
from cleveragents.infrastructure.sandbox.git_worktree import (
|
||||
GitWorktreeSandbox,
|
||||
)
|
||||
|
||||
# Regex for validating namespaced actor names (namespace/name format)
|
||||
_NAMESPACED_ACTOR_RE = re.compile(r"^[a-z][a-z0-9-]*/[a-z][a-z0-9._-]*$")
|
||||
@@ -1349,6 +1355,9 @@ def _get_lifecycle_service():
|
||||
return container.plan_lifecycle_service()
|
||||
|
||||
|
||||
_cleanup_logger = structlog.get_logger("cleveragents.cli.commands.plan.cleanup")
|
||||
|
||||
|
||||
def _cleanup_sandbox_for_plan(
|
||||
plan_id: str,
|
||||
service: PlanLifecycleService,
|
||||
@@ -1361,19 +1370,33 @@ def _cleanup_sandbox_for_plan(
|
||||
|
||||
Used by ``plan cancel`` to prevent resource leaks.
|
||||
"""
|
||||
from cleveragents.application.container import get_container
|
||||
from cleveragents.infrastructure.sandbox.git_worktree import (
|
||||
GitWorktreeSandbox,
|
||||
)
|
||||
if not plan_id or not plan_id.strip():
|
||||
_cleanup_logger.warning("cleanup_sandbox.skipped", reason="empty plan_id")
|
||||
return
|
||||
|
||||
container = get_container()
|
||||
plan = service.get_plan(plan_id)
|
||||
|
||||
try:
|
||||
plan = service.get_plan(plan_id)
|
||||
except (NotFoundError, CleverAgentsError) as exc:
|
||||
_cleanup_logger.warning(
|
||||
"cleanup_sandbox.plan_not_found",
|
||||
plan_id=plan_id,
|
||||
error=str(exc),
|
||||
)
|
||||
return
|
||||
|
||||
project_names = [pl.project_name for pl in getattr(plan, "project_links", [])]
|
||||
|
||||
for project_name in project_names:
|
||||
try:
|
||||
project = container.namespaced_project_repo().get(project_name)
|
||||
except Exception:
|
||||
except (NotFoundError, CleverAgentsError, SQLAlchemyError) as exc:
|
||||
_cleanup_logger.debug(
|
||||
"cleanup_sandbox.project_lookup_failed",
|
||||
project_name=project_name,
|
||||
error=str(exc),
|
||||
)
|
||||
continue
|
||||
if project is None:
|
||||
continue
|
||||
@@ -1382,7 +1405,12 @@ def _cleanup_sandbox_for_plan(
|
||||
resource = container.resource_registry_service().show_resource(
|
||||
lr.resource_id,
|
||||
)
|
||||
except Exception:
|
||||
except (NotFoundError, CleverAgentsError, SQLAlchemyError) as exc:
|
||||
_cleanup_logger.debug(
|
||||
"cleanup_sandbox.resource_lookup_failed",
|
||||
resource_id=lr.resource_id,
|
||||
error=str(exc),
|
||||
)
|
||||
continue
|
||||
if (
|
||||
resource.resource_type_name not in ("git-checkout", "git")
|
||||
|
||||
@@ -226,9 +226,11 @@ class GitWorktreeSandbox:
|
||||
branch_name,
|
||||
)
|
||||
|
||||
branch_deleted = True
|
||||
try:
|
||||
_run_git(["branch", "-D", branch_name], cwd=repo_path)
|
||||
except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
|
||||
branch_deleted = False
|
||||
logger.warning(
|
||||
"Failed to delete stale branch %s",
|
||||
branch_name,
|
||||
@@ -240,8 +242,14 @@ class GitWorktreeSandbox:
|
||||
):
|
||||
_run_git(["worktree", "prune"], cwd=repo_path)
|
||||
|
||||
logger.info("Stale sandbox branch cleaned up: branch=%s", branch_name)
|
||||
return True
|
||||
if branch_deleted:
|
||||
logger.info("Stale sandbox branch cleaned up: branch=%s", branch_name)
|
||||
else:
|
||||
logger.warning(
|
||||
"Partial cleanup: worktree removed but branch persists: branch=%s",
|
||||
branch_name,
|
||||
)
|
||||
return True # Branch was found; cleanup attempted (even if partial)
|
||||
|
||||
# -- protocol methods ----------------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user