A Zulip bot agent to sit in our Black Sun. Ever evolving

Add debug logging for git commands in poe loop

Log the exact command and working directory for all git operations when
running with -vv verbosity. Also log the resolved monorepo path at startup
to help diagnose configuration issues like "not a git repository" errors.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

+34 -24
+9 -3
lib/changelog.ml
··· 22 22 } 23 23 24 24 let get_commit_files ~proc ~cwd ~hash = 25 + let cmd = ["git"; "diff-tree"; "--no-commit-id"; "--name-only"; "-r"; hash] in 26 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) (Eio.Path.native_exn cwd)); 25 27 Eio.Switch.run @@ fun sw -> 26 28 let buf = Buffer.create 256 in 27 29 let child = Eio.Process.spawn proc ~sw ~cwd 28 30 ~stdout:(Eio.Flow.buffer_sink buf) 29 - ["git"; "diff-tree"; "--no-commit-id"; "--name-only"; "-r"; hash] 31 + cmd 30 32 in 31 33 match Eio.Process.await child with 32 34 | `Exited 0 -> ··· 37 39 38 40 let get_git_log ~proc ~cwd ~since_head = 39 41 Log.info (fun m -> m "Getting commits since %s" since_head); 42 + let cmd = ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; since_head ^ "..HEAD"] in 43 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) (Eio.Path.native_exn cwd)); 40 44 Eio.Switch.run @@ fun sw -> 41 45 let buf = Buffer.create 1024 in 42 46 let child = Eio.Process.spawn proc ~sw ~cwd 43 47 ~stdout:(Eio.Flow.buffer_sink buf) 44 - ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; since_head ^ "..HEAD"] 48 + cmd 45 49 in 46 50 match Eio.Process.await child with 47 51 | `Exited 0 -> ··· 59 63 60 64 let get_recent_commits ~proc ~cwd ~count = 61 65 Log.info (fun m -> m "Getting last %d commits" count); 66 + let cmd = ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; "-n"; string_of_int count] in 67 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) (Eio.Path.native_exn cwd)); 62 68 Eio.Switch.run @@ fun sw -> 63 69 let buf = Buffer.create 1024 in 64 70 let child = Eio.Process.spawn proc ~sw ~cwd 65 71 ~stdout:(Eio.Flow.buffer_sink buf) 66 - ["git"; "log"; "--pretty=format:%h|%an|%ae|%s"; "-n"; string_of_int count] 72 + cmd 67 73 in 68 74 match Eio.Process.await child with 69 75 | `Exited 0 ->
+25 -21
lib/loop.ml
··· 6 6 let src = Logs.Src.create "poe.loop" ~doc:"Poe polling loop" 7 7 module Log = (val Logs.src_log src : Logs.LOG) 8 8 9 - let get_git_head ~proc ~cwd = 10 - Eio.Switch.run @@ fun sw -> 11 - let buf = Buffer.create 64 in 12 - let child = Eio.Process.spawn proc ~sw ~cwd 13 - ~stdout:(Eio.Flow.buffer_sink buf) 14 - ["git"; "rev-parse"; "--short"; "HEAD"] 15 - in 16 - match Eio.Process.await child with 17 - | `Exited 0 -> Some (String.trim (Buffer.contents buf)) 18 - | _ -> None 19 - 20 - let run_git_pull ~proc ~cwd = 21 - Log.info (fun m -> m "Pulling latest changes from remote"); 9 + let run_command ~proc ~cwd cmd = 10 + let cwd_str = Eio.Path.native_exn cwd in 11 + Log.debug (fun m -> m "Running: %s (in %s)" (String.concat " " cmd) cwd_str); 22 12 Eio.Switch.run @@ fun sw -> 23 13 let buf_stdout = Buffer.create 256 in 24 14 let buf_stderr = Buffer.create 256 in 25 15 let child = Eio.Process.spawn proc ~sw ~cwd 26 16 ~stdout:(Eio.Flow.buffer_sink buf_stdout) 27 17 ~stderr:(Eio.Flow.buffer_sink buf_stderr) 28 - ["git"; "pull"; "--ff-only"] 18 + cmd 29 19 in 20 + let stdout = Buffer.contents buf_stdout in 21 + let stderr = Buffer.contents buf_stderr in 30 22 match Eio.Process.await child with 31 - | `Exited 0 -> 32 - let output = String.trim (Buffer.contents buf_stdout) in 23 + | `Exited code -> (code, stdout, stderr) 24 + | `Signaled sig_ -> (-sig_, stdout, stderr) 25 + 26 + let get_git_head ~proc ~cwd = 27 + match run_command ~proc ~cwd ["git"; "rev-parse"; "--short"; "HEAD"] with 28 + | (0, stdout, _) -> Some (String.trim stdout) 29 + | _ -> None 30 + 31 + let run_git_pull ~proc ~cwd = 32 + Log.info (fun m -> m "Pulling latest changes from remote"); 33 + match run_command ~proc ~cwd ["git"; "pull"; "--ff-only"] with 34 + | (0, stdout, _) -> 35 + let output = String.trim stdout in 33 36 if output = "Already up to date." then 34 37 Log.info (fun m -> m "Repository already up to date") 35 38 else begin ··· 40 43 if line <> "" then Log.info (fun m -> m " %s" line)) 41 44 end; 42 45 true 43 - | `Exited code -> 44 - let stderr = String.trim (Buffer.contents buf_stderr) in 45 - Log.warn (fun m -> m "git pull exited with code %d: %s" code stderr); 46 + | (code, _, stderr) when code > 0 -> 47 + Log.warn (fun m -> m "git pull exited with code %d: %s" code (String.trim stderr)); 46 48 false 47 - | `Signaled sig_ -> 48 - Log.warn (fun m -> m "git pull killed by signal %d" sig_); 49 + | (sig_, _, _) -> 50 + Log.warn (fun m -> m "git pull killed by signal %d" (-sig_)); 49 51 false 50 52 51 53 let send_message ~client ~stream ~topic ~content = ··· 63 65 let storage = Zulip_bot.Storage.create client in 64 66 65 67 let monorepo_path = Eio.Path.(fs / config.Config.monorepo_path) in 68 + let monorepo_native = Eio.Path.native_exn monorepo_path in 66 69 67 70 Log.info (fun m -> m "Starting loop with %d second interval" interval); 71 + Log.info (fun m -> m "Monorepo path: %s" monorepo_native); 68 72 69 73 let broadcast_loop () = 70 74 let rec loop () =