owenrusk.dev

casebench

test cases straight onto the board.

git clone https://owenrusk.dev/casebench.git

commit 206a88464e78e7cc470254d25607b7ee82b62670
parent 92339d27479548c60dda5a2e69bb2a09914949b3
author Owen Rusk <owen@papermothgames.com>
date   2025-04-02 13:22:16 -0500
note: write a note under a case's title
casebench/cli.py+42-13
casebench/db.py+7-0
diff --git a/casebench/cli.py b/casebench/cli.py
index c50bb1f..5c8b704 100644
--- a/casebench/cli.py
+++ b/casebench/cli.py
@@ -3,34 +3,63 @@ import os
 import sys
 from pathlib import Path
 
+import psycopg
+
 from . import casefile, db
 
 
+class Fail(Exception):
+    pass
+
+
 def main(argv: list[str] | None = None) -> int:
     parser = argparse.ArgumentParser(prog="casebench")
     sub = parser.add_subparsers(dest="command", required=True)
+
     put = sub.add_parser("put", help="put a case on a player's board")
     put.add_argument("folder", type=Path)
     put.add_argument("--player", required=True)
-    args = parser.parse_args(argv)
+    put.set_defaults(run=run_put)
+
+    note = sub.add_parser("note", help="write a note on a case")
+    note.add_argument("case")
+    note.add_argument("text")
+    note.add_argument("--player", required=True)
+    note.set_defaults(run=run_note)
 
+    args = parser.parse_args(argv)
     dsn = os.environ.get("CASEBENCH_DSN")
     if not dsn:
         print("casebench: set CASEBENCH_DSN", file=sys.stderr)
         return 2
     try:
-        case = casefile.load(args.folder)
-    except casefile.CaseError as e:
+        with db.connect(dsn) as conn:
+            args.run(conn, args)
+    except (Fail, casefile.CaseError) as e:
         print(f"casebench: {e}", file=sys.stderr)
         return 1
-    with db.connect(dsn) as conn:
-        player = db.player_id(conn, args.player)
-        if player is None:
-            print(f"casebench: no player {args.player}", file=sys.stderr)
-            return 1
-        if db.source(conn, player, case.id) not in (None, "bench"):
-            print(f"casebench: {args.player} already has {case.id} from the runtime", file=sys.stderr)
-            return 1
-        db.put(conn, player, case)
-    print(f"{args.player}: put {case.id}")
     return 0
+
+
+def player(conn: psycopg.Connection, handle: str) -> str:
+    found = db.player_id(conn, handle)
+    if found is None:
+        raise Fail(f"no player {handle}")
+    return found
+
+
+def run_put(conn: psycopg.Connection, args: argparse.Namespace) -> None:
+    case = casefile.load(args.folder)
+    who = player(conn, args.player)
+    if db.source(conn, who, case.id) not in (None, "bench"):
+        raise Fail(f"{args.player} already has {case.id} from the runtime")
+    db.put(conn, who, case)
+    print(f"{args.player}: put {case.id}")
+
+
+def run_note(conn: psycopg.Connection, args: argparse.Namespace) -> None:
+    who = player(conn, args.player)
+    if db.source(conn, who, args.case) is None:
+        raise Fail(f"{args.player} doesn't have {args.case}")
+    db.note(conn, who, args.case, args.text)
+    print(f"{args.player}: noted {args.case}")
diff --git a/casebench/db.py b/casebench/db.py
index 41591cc..1a1a03b 100644
--- a/casebench/db.py
+++ b/casebench/db.py
@@ -34,3 +34,10 @@ def put(conn: psycopg.Connection, player: str, case: Case) -> None:
                 " values (%s, %s, %s, %s, %s, %s)",
                 (player, case.id, item.id, position, item.title, item.text),
             )
+
+
+def note(conn: psycopg.Connection, player: str, case_id: str, text: str) -> None:
+    conn.execute(
+        "insert into board_notes (player_id, case_id, body) values (%s, %s, %s)", (player, case_id, text)
+    )
+    conn.commit()