import json from pathlib import Path from typing import Mapping import pytest from typer.testing import CliRunner from scripts import bm_bossbot_status def _event_payload(body: str = "Event snapshot body") -> dict[str, object]: return { "repository": {"full_name": "basicmachines-co/basic-memory"}, "pull_request": { "number": 925, "body": body, "head": {"sha": "abc123"}, }, } def test_status_script_is_uv_typer_entrypoint() -> None: source = bm_bossbot_status.__file__ assert source is not None text = open(source, encoding="utf-8").read() assert text.startswith("#!/usr/bin/env -S uv run --script\n") assert "# /// script" in text assert "typer" in text assert hasattr(bm_bossbot_status, "app") def _review_payload(**overrides: object) -> dict[str, object]: payload: dict[str, object] = { "reviewed_head_sha": "abc123", "review_complete": True, "verdict": "approve", "blocking_findings": [], "nonblocking_findings": [], "summary": "The change is ready.", } payload.update(overrides) return payload def test_validate_review_accepts_matching_approved_head_sha() -> None: result = bm_bossbot_status.validate_review(_review_payload(), expected_head_sha="abc123") assert result.approved is True assert result.state == "success" assert result.description == "BM Bossbot approved this head SHA" def test_validate_review_rejects_stale_head_sha() -> None: result = bm_bossbot_status.validate_review(_review_payload(), expected_head_sha="def456") assert result.approved is False assert result.state == "failure" assert result.description == "BM Bossbot reviewed a stale head SHA" def test_validate_review_rejects_blocking_findings() -> None: result = bm_bossbot_status.validate_review( _review_payload(blocking_findings=[{"title": "Missing test", "body": "Add coverage."}]), expected_head_sha="abc123", ) assert result.approved is False assert result.state == "failure" assert result.description == "BM Bossbot requested changes" def test_status_payload_uses_required_context() -> None: payload = bm_bossbot_status.build_status_payload( state="pending", description="BM Bossbot is reviewing this head SHA", target_url="https://github.com/basicmachines-co/basic-memory/actions/runs/1", ) assert payload == { "state": "pending", "context": "BM Bossbot Approval", "description": "BM Bossbot is reviewing this head SHA", "target_url": "https://github.com/basicmachines-co/basic-memory/actions/runs/1", } def test_upsert_summary_block_replaces_existing_block() -> None: body = "\n".join( [ "Intro", "", "Old summary", "", "Footer", ] ) updated = bm_bossbot_status.upsert_summary_block(body, "New summary") assert "Old summary" not in updated assert "New summary" in updated assert updated.startswith("Intro") assert updated.endswith("Footer") def test_finalize_review_fetches_current_pr_body_before_upserting( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: event_path = tmp_path / "event.json" review_path = tmp_path / "review.json" event_path.write_text(json.dumps(_event_payload()), encoding="utf-8") review_path.write_text(json.dumps(_review_payload()), encoding="utf-8") monkeypatch.setenv("GITHUB_TOKEN", "token") updated_bodies: list[str] = [] statuses: list[Mapping[str, str]] = [] def fake_get_pull_request_body(*, token: str, repo: str, number: int) -> str: assert token == "token" assert repo == "basicmachines-co/basic-memory" assert number == 925 return "Current body edited while the workflow was running" def fake_update_pull_request_body(*, token: str, repo: str, number: int, body: str) -> None: updated_bodies.append(body) def fake_set_commit_status( *, token: str, repo: str, sha: str, payload: Mapping[str, str], ) -> None: statuses.append(payload) monkeypatch.setattr(bm_bossbot_status, "get_pull_request_body", fake_get_pull_request_body) monkeypatch.setattr(bm_bossbot_status, "update_pull_request_body", fake_update_pull_request_body) monkeypatch.setattr(bm_bossbot_status, "set_commit_status", fake_set_commit_status) result = bm_bossbot_status.finalize_review( event_path=event_path, review_path=review_path, repo=None, run_url="https://github.com/basicmachines-co/basic-memory/actions/runs/1", token_env="GITHUB_TOKEN", ) assert result.approved is True assert "Current body edited while the workflow was running" in updated_bodies[0] assert "Event snapshot body" not in updated_bodies[0] assert statuses[0]["state"] == "success" def test_finalize_cli_marks_failure_when_review_file_is_missing( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: event_path = tmp_path / "event.json" missing_review_path = tmp_path / "missing-review.json" event_path.write_text(json.dumps(_event_payload(body="Current body")), encoding="utf-8") monkeypatch.setenv("GITHUB_TOKEN", "token") updated_bodies: list[str] = [] statuses: list[Mapping[str, str]] = [] def fake_get_pull_request_body(*, token: str, repo: str, number: int) -> str: return "Current body" def fake_update_pull_request_body(*, token: str, repo: str, number: int, body: str) -> None: updated_bodies.append(body) def fake_set_commit_status( *, token: str, repo: str, sha: str, payload: Mapping[str, str], ) -> None: statuses.append(payload) monkeypatch.setattr(bm_bossbot_status, "get_pull_request_body", fake_get_pull_request_body) monkeypatch.setattr(bm_bossbot_status, "update_pull_request_body", fake_update_pull_request_body) monkeypatch.setattr(bm_bossbot_status, "set_commit_status", fake_set_commit_status) result = CliRunner().invoke( bm_bossbot_status.app, [ "finalize", "--event", str(event_path), "--review", str(missing_review_path), "--repo", "basicmachines-co/basic-memory", "--run-url", "https://github.com/basicmachines-co/basic-memory/actions/runs/1", ], ) assert result.exit_code == 1 assert "BM Bossbot review output was invalid" in updated_bodies[0] assert statuses[0]["state"] == "failure"