|
5 | 5 | from scripts.reviewer_bot_lib import review_state |
6 | 6 | from scripts.reviewer_bot_lib.config import GitHubApiResult |
7 | 7 | from tests.fixtures.app_harness import AppHarness |
8 | | -from tests.fixtures.reviewer_bot import make_state, valid_reviewer_board_metadata |
| 8 | +from tests.fixtures.reviewer_bot import ( |
| 9 | + make_state, |
| 10 | + make_tracked_review_state, |
| 11 | + pull_request_payload, |
| 12 | + review_payload, |
| 13 | + valid_reviewer_board_metadata, |
| 14 | +) |
| 15 | +from tests.fixtures.reviewer_bot_builders import accept_reviewer_review |
| 16 | +from tests.fixtures.reviewer_bot_fakes import RouteGitHubApi |
9 | 17 |
|
10 | 18 | pytestmark = pytest.mark.integration |
11 | 19 |
|
@@ -159,3 +167,88 @@ def test_execute_run_preview_reviewer_board_is_read_only(monkeypatch, capsys): |
159 | 167 | assert payload["state_save_attempted"] is False |
160 | 168 | assert payload["tracked_state_mutations_attempted"] is False |
161 | 169 | assert payload["touched_projection_attempted"] is False |
| 170 | + |
| 171 | + |
| 172 | +def test_execute_run_preview_reviewer_board_keeps_pr264_alternate_approval_projection(monkeypatch, capsys): |
| 173 | + harness = AppHarness(monkeypatch) |
| 174 | + harness.set_event( |
| 175 | + EVENT_NAME="workflow_dispatch", |
| 176 | + EVENT_ACTION="", |
| 177 | + MANUAL_ACTION="preview-reviewer-board", |
| 178 | + REVIEWER_BOARD_ENABLED="true", |
| 179 | + REVIEWER_BOARD_TOKEN="board-token", |
| 180 | + ISSUE_NUMBER=264, |
| 181 | + VALIDATION_NONCE="board-preview-pr264", |
| 182 | + GITHUB_SHA="workflow-head", |
| 183 | + ) |
| 184 | + monkeypatch.setattr(harness.runtime, "_reviewer_board_project_metadata", None, raising=False) |
| 185 | + |
| 186 | + state = make_state() |
| 187 | + review = make_tracked_review_state( |
| 188 | + state, |
| 189 | + 264, |
| 190 | + reviewer="iglesias", |
| 191 | + assigned_at="2026-02-10T17:20:07Z", |
| 192 | + active_cycle_started_at="2026-02-10T17:20:07Z", |
| 193 | + ) |
| 194 | + accept_reviewer_review( |
| 195 | + review, |
| 196 | + semantic_key="pull_request_review:77", |
| 197 | + timestamp="2026-03-18T01:09:05Z", |
| 198 | + actor="iglesias", |
| 199 | + reviewed_head_sha="head-old", |
| 200 | + ) |
| 201 | + |
| 202 | + routes = RouteGitHubApi().add_request( |
| 203 | + "GET", |
| 204 | + "issues/264", |
| 205 | + status_code=200, |
| 206 | + payload={"number": 264, "state": "open", "pull_request": {}, "labels": []}, |
| 207 | + ).add_request( |
| 208 | + "GET", |
| 209 | + "pulls/264", |
| 210 | + status_code=200, |
| 211 | + payload={ |
| 212 | + **pull_request_payload(264, head_sha="head-live", author="manhatsu"), |
| 213 | + "requested_reviewers": [], |
| 214 | + "labels": [], |
| 215 | + }, |
| 216 | + ).add_pull_request_reviews( |
| 217 | + 264, |
| 218 | + [review_payload(501, state="APPROVED", submitted_at="2026-03-18T12:10:42Z", commit_id="head-live", author="plaindocs")], |
| 219 | + ) |
| 220 | + harness.runtime.github.stub(routes) |
| 221 | + harness.stub_load_state(lambda *, fail_on_unavailable=False: state) |
| 222 | + harness.stub_lock(acquire=lambda: (_ for _ in ()).throw(AssertionError("preview should not acquire lock"))) |
| 223 | + harness.stub_pass_until(lambda current: (_ for _ in ()).throw(AssertionError("preview should skip pass-until processing"))) |
| 224 | + harness.stub_sync_members(lambda current: (_ for _ in ()).throw(AssertionError("preview should skip member sync"))) |
| 225 | + harness.stub_save_state(lambda current: (_ for _ in ()).throw(AssertionError("preview should not save state"))) |
| 226 | + harness.stub_sync_status_labels(lambda current, issue_numbers: (_ for _ in ()).throw(AssertionError("preview should not sync labels"))) |
| 227 | + monkeypatch.setattr(harness.runtime, "github_graphql", lambda query, variables=None, *, token=None: valid_reviewer_board_metadata()) |
| 228 | + harness.runtime.github.get_user_permission_status = lambda username, required_permission="push": "granted" |
| 229 | + |
| 230 | + result = harness.run_execute() |
| 231 | + |
| 232 | + assert result.exit_code == 0 |
| 233 | + payload = json.loads(capsys.readouterr().out) |
| 234 | + assert payload == { |
| 235 | + "schema_version": 1, |
| 236 | + "preview_action": "preview-reviewer-board", |
| 237 | + "issue_number": 264, |
| 238 | + "validation_nonce": "board-preview-pr264", |
| 239 | + "head_sha": "workflow-head", |
| 240 | + "workflow_path": ".github/workflows/reviewer-bot-preview.yml", |
| 241 | + "response_state": "awaiting_contributor_response", |
| 242 | + "reviewer_authority_outcome": "tracked_reviewer_confirmed", |
| 243 | + "suppression_reason": "current_head_alternate_approval_present", |
| 244 | + "current_scope_key": "reviewer=iglesias|head=head-live|cycle=2026-02-10T17:20:07Z|anchor=none", |
| 245 | + "current_scope_basis": "alternate_current_head_approval", |
| 246 | + "would_post_warning": False, |
| 247 | + "would_post_transition": False, |
| 248 | + "lock_attempted": False, |
| 249 | + "state_save_attempted": False, |
| 250 | + "tracked_state_mutations_attempted": False, |
| 251 | + "touched_projection_attempted": False, |
| 252 | + "board_attention": "No", |
| 253 | + "board_waiting_since": None, |
| 254 | + } |
0 commit comments