feat(robomp): resume needs-info issues

This commit is contained in:
oldschoola
2026-06-15 17:55:48 -07:00
parent 12290e080d
commit a409fd3216
7 changed files with 130 additions and 19 deletions
+28 -6
View File
@@ -419,12 +419,15 @@ def test_repro_record_rejects_bad_args(db: Database, tmp_path: Path) -> None:
_stop_loop(loop, t)
def test_mark_unable_posts_comment_and_abandons(db: Database, tmp_path: Path) -> None:
def test_mark_unable_posts_comment_marks_needs_info_and_labels_issue(db: Database, tmp_path: Path) -> None:
captured: dict[str, Any] = {}
def handler(request: httpx.Request) -> httpx.Response:
captured["body"] = json.loads(request.content)
return httpx.Response(201, json={"id": 77, "user": {"login": "robomp-bot"}, "body": "x", "created_at": "t"})
if request.url.path.endswith("/labels"):
captured["labels"] = json.loads(request.content)
return httpx.Response(200, json=[{"name": "bug"}, {"name": "needs-info"}])
captured["comment"] = json.loads(request.content)
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:
@@ -432,10 +435,29 @@ def test_mark_unable_posts_comment_and_abandons(db: Database, tmp_path: Path) ->
result = tool.execute({"diagnosis": "needed exact version", "info_needed": "post bun --version"}, _ctx())
finally:
_stop_loop(loop, t)
assert "abandonment" in result
assert "Could not reproduce" in captured["body"]["body"]
assert "needs-info comment" in result
assert captured["labels"] == {"labels": ["needs-info"]}
assert "resume from this context" in captured["comment"]["body"]
issue = db.get_issue(bindings.issue_key)
assert issue and issue.state == "abandoned"
assert issue and issue.state == "needs_info"
def test_mark_unable_keeps_needs_info_when_label_is_missing(db: Database, tmp_path: Path) -> None:
def handler(request: httpx.Request) -> httpx.Response:
if request.url.path.endswith("/labels"):
return httpx.Response(422, json={"message": "Label does not exist"})
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)
issue = db.get_issue(bindings.issue_key)
assert issue and issue.state == "needs_info"
def test_abort_task_signals_controller_and_abandons_without_comment(db: Database, tmp_path: Path) -> None:
+75
View File
@@ -2211,6 +2211,81 @@ async def test_handle_comment_finalized_without_directive_still_replies(
close_database()
async def test_handle_comment_resumes_needs_info_reply(
settings: Settings, tmp_path: Path, stub_run_task, monkeypatch
) -> None:
"""Reporter details after a needs-info request resume the existing session."""
from robomp import tasks
from robomp.github_client import GitHubClient, IssueInfo, RepoInfo
sandbox = _RecordingSandbox(tmp_path)
db = get_database(settings.sqlite_path)
db.upsert_issue(
key="octo/widget#88",
repo="octo/widget",
number=88,
state="needs_info",
branch="farm/old/branch",
)
repo = RepoInfo(
full_name="octo/widget", default_branch="main", clone_url="https://github.com/octo/widget.git", private=False
)
issue = IssueInfo(
repo="octo/widget",
number=88,
title="boom",
body="details",
state="open",
author="alice",
labels=("needs-info",),
is_pull_request=False,
)
async def _resolve(_gh, _payload):
return repo, issue
monkeypatch.setattr(tasks, "_resolve_repo_and_issue", _resolve)
post_comment_calls: list = []
async def _capture_post(self, *args, **kwargs):
post_comment_calls.append((args, kwargs))
return None
monkeypatch.setattr(GitHubClient, "post_comment", _capture_post)
payload = {
"action": "created",
"issue": {"number": 88, "user": {"login": "alice"}, "title": "boom"},
"comment": {
"user": {"login": "alice"},
"body": "I am on Bun 1.3.14 and here is the trace",
"id": 4,
"created_at": "2026-05-14T23:00:00Z",
},
"repository": {"full_name": "octo/widget"},
}
await tasks.handle_comment(
settings=settings,
db=db,
github=GitHubClient("t"),
git_transport=LocalGitTransport(token=None),
sandbox=sandbox,
payload=payload,
delivery_id="test-delivery-needs-info",
)
assert len(stub_run_task) == 1
call = stub_run_task[0]
assert call["task_kind"] == "handle_comment"
assert call["comment"].body == "I am on Bun 1.3.14 and here is the trace"
assert sandbox.ensure_calls[0]["existing_branch"] == "farm/old/branch"
assert post_comment_calls == [], "needs-info replies must not get the finalized-issue notice"
row = db.get_issue("octo/widget#88")
assert row is not None and row.state == "needs_info"
close_database()
async def test_directive_handler_attaches_thread_from_github(
settings: Settings, tmp_path: Path, stub_run_task, monkeypatch
) -> None: