fix(robomp): keep label failures best effort
This commit is contained in:
@@ -143,6 +143,10 @@ def _issue_needs_info(bindings: ToolBindings) -> bool:
|
||||
return row is not None and row.state == "needs_info"
|
||||
|
||||
|
||||
def _optional_label_error(exc: Exception) -> str:
|
||||
return f"{type(exc).__name__}: {exc}"
|
||||
|
||||
|
||||
def _remove_needs_info_label(bindings: ToolBindings) -> bool:
|
||||
try:
|
||||
_run_coro(
|
||||
@@ -154,6 +158,12 @@ def _remove_needs_info_label(bindings: ToolBindings) -> bool:
|
||||
return True
|
||||
log.warning("needs-info label cleanup failed", extra={"issue": bindings.issue_key, "err": str(exc)})
|
||||
return False
|
||||
except Exception as exc: # noqa: BLE001 - best-effort optional label cleanup
|
||||
log.warning(
|
||||
"needs-info label cleanup failed",
|
||||
extra={"issue": bindings.issue_key, "err": _optional_label_error(exc)},
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -934,6 +944,10 @@ def _build_mark_unable(bindings: ToolBindings) -> HostTool[Any, Any]:
|
||||
# info-request comment, so label setup must not block resumption.
|
||||
log.warning("needs-info label failed", extra={"issue": bindings.issue_key, "err": str(exc)})
|
||||
result["label_error"] = f"{exc.status} {exc.message}"
|
||||
except Exception as exc: # noqa: BLE001 - best-effort optional label setup
|
||||
error = _optional_label_error(exc)
|
||||
log.warning("needs-info label failed", extra={"issue": bindings.issue_key, "err": error})
|
||||
result["label_error"] = error
|
||||
bindings.db.set_issue_state(bindings.issue_key, "needs_info")
|
||||
_audit(bindings, "mark_unable_to_reproduce", args, result=result)
|
||||
return f"posted needs-info comment id={comment.id}"
|
||||
|
||||
@@ -437,6 +437,31 @@ def test_repro_record_advances_needs_info_when_label_is_missing(db: Database, tm
|
||||
assert issue and issue.state == "reproducing"
|
||||
|
||||
|
||||
def test_repro_record_advances_needs_info_when_cleanup_transport_fails(db: Database, tmp_path: Path) -> None:
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
raise httpx.ConnectError("connection dropped", request=request)
|
||||
|
||||
bindings, loop, t = _bindings(db, tmp_path, httpx.MockTransport(handler))
|
||||
db.set_issue_state(bindings.issue_key, "needs_info")
|
||||
try:
|
||||
tool = next(x for x in build(bindings) if x.name == "repro_record")
|
||||
result = tool.execute(
|
||||
{
|
||||
"title": "panic on empty input",
|
||||
"command": "bun test foo.test.ts",
|
||||
"output": "Error: boom",
|
||||
"exit_code": 1,
|
||||
},
|
||||
_ctx(),
|
||||
)
|
||||
finally:
|
||||
_stop_loop(loop, t)
|
||||
|
||||
assert result == "recorded"
|
||||
issue = db.get_issue(bindings.issue_key)
|
||||
assert issue and issue.state == "reproducing"
|
||||
|
||||
|
||||
def test_repro_record_chowns_to_slot_when_root(db: Database, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
chowns: list[tuple[Path, int, int]] = []
|
||||
monkeypatch.setattr(host_tools, "_slot_permissions_active", lambda slot_uid: slot_uid is not None)
|
||||
@@ -519,6 +544,34 @@ def test_mark_unable_keeps_needs_info_when_label_is_missing(db: Database, tmp_pa
|
||||
assert issue and issue.state == "needs_info"
|
||||
|
||||
|
||||
def test_mark_unable_keeps_needs_info_when_label_transport_fails(db: Database, tmp_path: Path) -> None:
|
||||
comments = 0
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
nonlocal comments
|
||||
if request.url.path.endswith("/labels"):
|
||||
raise httpx.ConnectError("connection dropped", request=request)
|
||||
comments += 1
|
||||
return httpx.Response(201, json={"id": 321, "user": {"login": "robomp-bot"}, "body": "x", "created_at": "t"})
|
||||
|
||||
bindings, loop, t = _bindings(db, tmp_path, httpx.MockTransport(handler))
|
||||
try:
|
||||
tool = next(x for x in build(bindings) if x.name == "mark_unable_to_reproduce")
|
||||
tool.execute({"diagnosis": "needed exact version", "info_needed": "post bun --version"}, _ctx())
|
||||
finally:
|
||||
_stop_loop(loop, t)
|
||||
|
||||
assert comments == 1
|
||||
issue = db.get_issue(bindings.issue_key)
|
||||
assert issue and issue.state == "needs_info"
|
||||
row = db._conn.execute(
|
||||
"SELECT result_json FROM tool_calls WHERE tool='mark_unable_to_reproduce' ORDER BY id DESC LIMIT 1"
|
||||
).fetchone()
|
||||
assert row is not None
|
||||
result = json.loads(row["result_json"])
|
||||
assert "ConnectError" in result["label_error"]
|
||||
|
||||
|
||||
def test_abort_task_signals_controller_and_abandons_without_comment(db: Database, tmp_path: Path) -> None:
|
||||
# Any HTTP call is a regression: abort_task MUST NOT touch GitHub.
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
|
||||
Reference in New Issue
Block a user