mirror of
https://github.com/openai/codex.git
synced 2026-04-29 02:41:12 +03:00
Fix PR babysitter review comment monitoring (#16363)
## Summary - prioritize newly surfaced review comments ahead of CI and mergeability handling in the PR babysitter watcher - keep `--watch` running for open PRs even when they are currently merge-ready so later review feedback is not missed
This commit is contained in:
155
.codex/skills/babysit-pr/scripts/test_gh_pr_watch.py
Normal file
155
.codex/skills/babysit-pr/scripts/test_gh_pr_watch.py
Normal file
@@ -0,0 +1,155 @@
|
||||
import argparse
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
MODULE_PATH = Path(__file__).with_name("gh_pr_watch.py")
|
||||
MODULE_SPEC = importlib.util.spec_from_file_location("gh_pr_watch", MODULE_PATH)
|
||||
gh_pr_watch = importlib.util.module_from_spec(MODULE_SPEC)
|
||||
assert MODULE_SPEC.loader is not None
|
||||
MODULE_SPEC.loader.exec_module(gh_pr_watch)
|
||||
|
||||
|
||||
def sample_pr():
|
||||
return {
|
||||
"number": 123,
|
||||
"url": "https://github.com/openai/codex/pull/123",
|
||||
"repo": "openai/codex",
|
||||
"head_sha": "abc123",
|
||||
"head_branch": "feature",
|
||||
"state": "OPEN",
|
||||
"merged": False,
|
||||
"closed": False,
|
||||
"mergeable": "MERGEABLE",
|
||||
"merge_state_status": "CLEAN",
|
||||
"review_decision": "",
|
||||
}
|
||||
|
||||
|
||||
def sample_checks(**overrides):
|
||||
checks = {
|
||||
"pending_count": 0,
|
||||
"failed_count": 0,
|
||||
"passed_count": 12,
|
||||
"all_terminal": True,
|
||||
}
|
||||
checks.update(overrides)
|
||||
return checks
|
||||
|
||||
|
||||
def test_collect_snapshot_fetches_review_items_before_ci(monkeypatch, tmp_path):
|
||||
call_order = []
|
||||
pr = sample_pr()
|
||||
|
||||
monkeypatch.setattr(gh_pr_watch, "resolve_pr", lambda *args, **kwargs: pr)
|
||||
monkeypatch.setattr(gh_pr_watch, "load_state", lambda path: ({}, True))
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"get_authenticated_login",
|
||||
lambda: call_order.append("auth") or "octocat",
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"fetch_new_review_items",
|
||||
lambda *args, **kwargs: call_order.append("review") or [],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"get_pr_checks",
|
||||
lambda *args, **kwargs: call_order.append("checks") or [],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"summarize_checks",
|
||||
lambda checks: call_order.append("summarize") or sample_checks(),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"get_workflow_runs_for_sha",
|
||||
lambda *args, **kwargs: call_order.append("workflow") or [],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"failed_runs_from_workflow_runs",
|
||||
lambda *args, **kwargs: call_order.append("failed_runs") or [],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"recommend_actions",
|
||||
lambda *args, **kwargs: call_order.append("recommend") or ["idle"],
|
||||
)
|
||||
monkeypatch.setattr(gh_pr_watch, "save_state", lambda *args, **kwargs: None)
|
||||
|
||||
args = argparse.Namespace(
|
||||
pr="123",
|
||||
repo=None,
|
||||
state_file=str(tmp_path / "watcher-state.json"),
|
||||
max_flaky_retries=3,
|
||||
)
|
||||
|
||||
gh_pr_watch.collect_snapshot(args)
|
||||
|
||||
assert call_order.index("review") < call_order.index("checks")
|
||||
assert call_order.index("review") < call_order.index("workflow")
|
||||
|
||||
|
||||
def test_recommend_actions_prioritizes_review_comments():
|
||||
actions = gh_pr_watch.recommend_actions(
|
||||
sample_pr(),
|
||||
sample_checks(failed_count=1),
|
||||
[{"run_id": 99}],
|
||||
[{"kind": "review_comment", "id": "1"}],
|
||||
0,
|
||||
3,
|
||||
)
|
||||
|
||||
assert actions == [
|
||||
"process_review_comment",
|
||||
"diagnose_ci_failure",
|
||||
"retry_failed_checks",
|
||||
]
|
||||
|
||||
|
||||
def test_run_watch_keeps_polling_open_ready_to_merge_pr(monkeypatch):
|
||||
sleeps = []
|
||||
events = []
|
||||
snapshot = {
|
||||
"pr": sample_pr(),
|
||||
"checks": sample_checks(),
|
||||
"failed_runs": [],
|
||||
"new_review_items": [],
|
||||
"actions": ["ready_to_merge"],
|
||||
"retry_state": {
|
||||
"current_sha_retries_used": 0,
|
||||
"max_flaky_retries": 3,
|
||||
},
|
||||
}
|
||||
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"collect_snapshot",
|
||||
lambda args: (snapshot, Path("/tmp/codex-babysit-pr-state.json")),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
gh_pr_watch,
|
||||
"print_event",
|
||||
lambda event, payload: events.append((event, payload)),
|
||||
)
|
||||
|
||||
class StopWatch(Exception):
|
||||
pass
|
||||
|
||||
def fake_sleep(seconds):
|
||||
sleeps.append(seconds)
|
||||
if len(sleeps) >= 2:
|
||||
raise StopWatch
|
||||
|
||||
monkeypatch.setattr(gh_pr_watch.time, "sleep", fake_sleep)
|
||||
|
||||
with pytest.raises(StopWatch):
|
||||
gh_pr_watch.run_watch(argparse.Namespace(poll_seconds=30))
|
||||
|
||||
assert sleeps == [30, 30]
|
||||
assert [event for event, _ in events] == ["snapshot", "snapshot"]
|
||||
Reference in New Issue
Block a user