From aa59dbb852e6ffe5e19ec96965bdebe044b30e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bot=20of=20Thomas=20G=C3=BCttler?= Date: Sat, 23 May 2026 15:05:07 +0200 Subject: [PATCH] feat: show CI run link in 'CI passed' message (#151) (#174) --- scripts/agent_loop.py | 3 ++- scripts/test_agent_loop.py | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/scripts/agent_loop.py b/scripts/agent_loop.py index d480e8b..1d17304 100755 --- a/scripts/agent_loop.py +++ b/scripts/agent_loop.py @@ -528,7 +528,8 @@ def _run_loop() -> int: ) return 0 _close_issue(pending_issue) - print(f"CI passed — closed {_issue_url(pending_issue)}.") + ci_run_part = f" {_ci_run_url(run['id'])}" if run else "" + print(f"CI passed{ci_run_part} — closed {_issue_url(pending_issue)}.") return 0 # Find a Ready issue. diff --git a/scripts/test_agent_loop.py b/scripts/test_agent_loop.py index 33fad9c..b1cd8c8 100644 --- a/scripts/test_agent_loop.py +++ b/scripts/test_agent_loop.py @@ -267,6 +267,33 @@ class TestPendingCi(unittest.TestCase): self.assertEqual(result, 0) mock_close.assert_called_once_with(10) + def test_ci_passed_output_includes_ci_run_url(self): + """'CI passed' line includes the CI run URL when a run is available.""" + buf = io.StringIO() + with patch("agent_loop._read_state", return_value=self._dead_state(10)), \ + patch("agent_loop._latest_ci_run", return_value={"id": 4145144, "status": "success"}), \ + patch("agent_loop._close_issue"), \ + patch("agent_loop._clear_state"), \ + contextlib.redirect_stdout(buf): + agent_loop._run_loop() + output = buf.getvalue() + self.assertIn("https://codeberg.org/guettli/sharedinbox/actions/runs/4145144", output) + self.assertIn("https://codeberg.org/guettli/sharedinbox/issues/10", output) + + def test_ci_passed_output_without_run_omits_ci_url(self): + """'CI passed' line still works when no CI run is available.""" + buf = io.StringIO() + with patch("agent_loop._read_state", return_value=self._dead_state(10)), \ + patch("agent_loop._latest_ci_run", return_value=None), \ + patch("agent_loop._close_issue"), \ + patch("agent_loop._clear_state"), \ + contextlib.redirect_stdout(buf): + agent_loop._run_loop() + output = buf.getvalue() + self.assertIn("CI passed", output) + self.assertIn("https://codeberg.org/guettli/sharedinbox/issues/10", output) + self.assertNotIn("/actions/runs/", output) + def test_does_not_close_issue_when_ci_fails(self): """After issue agent finishes, loop must NOT close the issue if CI failed.""" with patch("agent_loop._read_state", return_value=self._dead_state(10)), \