kin: auto-commit after pipeline
This commit is contained in:
parent
f805aff86b
commit
6c2da26b6c
6 changed files with 138 additions and 10 deletions
|
|
@ -6,6 +6,7 @@ Each agent = separate process with isolated context.
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import sqlite3
|
||||
import subprocess
|
||||
|
|
@ -778,16 +779,20 @@ def _is_test_failure(result: dict) -> bool:
|
|||
_AUTO_TEST_ROLES = {"backend_dev", "frontend_dev"}
|
||||
|
||||
|
||||
def _run_project_tests(project_path: str, timeout: int = 120) -> dict:
|
||||
"""Run `make test` in project_path. Returns {success, output, returncode}.
|
||||
def _run_project_tests(project_path: str, test_command: str = 'make test', timeout: int = 120) -> dict:
|
||||
"""Run test_command in project_path. Returns {success, output, returncode}.
|
||||
|
||||
Never raises — all errors are captured and returned in output.
|
||||
"""
|
||||
env = _build_claude_env()
|
||||
make_cmd = shutil.which("make", path=env["PATH"]) or "make"
|
||||
parts = shlex.split(test_command)
|
||||
if not parts:
|
||||
return {"success": False, "output": "Empty test_command", "returncode": -1}
|
||||
resolved = shutil.which(parts[0], path=env["PATH"]) or parts[0]
|
||||
cmd = [resolved] + parts[1:]
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[make_cmd, "test"],
|
||||
cmd,
|
||||
cwd=project_path,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
|
|
@ -797,9 +802,9 @@ def _run_project_tests(project_path: str, timeout: int = 120) -> dict:
|
|||
output = (result.stdout or "") + (result.stderr or "")
|
||||
return {"success": result.returncode == 0, "output": output, "returncode": result.returncode}
|
||||
except subprocess.TimeoutExpired:
|
||||
return {"success": False, "output": f"make test timed out after {timeout}s", "returncode": 124}
|
||||
return {"success": False, "output": f"{test_command} timed out after {timeout}s", "returncode": 124}
|
||||
except FileNotFoundError:
|
||||
return {"success": False, "output": "make not found — no Makefile or make not in PATH", "returncode": 127}
|
||||
return {"success": False, "output": f"{parts[0]} not found in PATH", "returncode": 127}
|
||||
except Exception as exc:
|
||||
return {"success": False, "output": f"Test run error: {exc}", "returncode": -1}
|
||||
|
||||
|
|
@ -1568,14 +1573,15 @@ def run_pipeline(
|
|||
):
|
||||
max_auto_test_attempts = int(os.environ.get("KIN_AUTO_TEST_MAX_ATTEMPTS") or 3)
|
||||
p_path_str = str(Path(project_for_wt["path"]).expanduser())
|
||||
test_run = _run_project_tests(p_path_str)
|
||||
p_test_cmd = project_for_wt.get("test_command") or "make test"
|
||||
test_run = _run_project_tests(p_path_str, p_test_cmd)
|
||||
results.append({"role": "_auto_test", "success": test_run["success"],
|
||||
"output": test_run["output"], "_project_test": True})
|
||||
auto_test_attempt = 0
|
||||
while not test_run["success"] and auto_test_attempt < max_auto_test_attempts:
|
||||
auto_test_attempt += 1
|
||||
fix_context = (
|
||||
f"Automated project test run (make test) failed after your changes.\n"
|
||||
f"Automated project test run ({p_test_cmd}) failed after your changes.\n"
|
||||
f"Test output:\n{test_run['output'][:4000]}\n"
|
||||
f"Fix the failing tests. Do NOT modify test files."
|
||||
)
|
||||
|
|
@ -1591,13 +1597,13 @@ def run_pipeline(
|
|||
total_tokens += fix_result.get("tokens_used") or 0
|
||||
total_duration += fix_result.get("duration_seconds") or 0
|
||||
results.append({**fix_result, "_auto_test_fix_attempt": auto_test_attempt})
|
||||
test_run = _run_project_tests(p_path_str)
|
||||
test_run = _run_project_tests(p_path_str, p_test_cmd)
|
||||
results.append({"role": "_auto_test", "success": test_run["success"],
|
||||
"output": test_run["output"], "_project_test": True,
|
||||
"_attempt": auto_test_attempt})
|
||||
if not test_run["success"]:
|
||||
block_reason = (
|
||||
f"Auto-test (make test) failed after {auto_test_attempt} fix attempt(s). "
|
||||
f"Auto-test ({p_test_cmd}) failed after {auto_test_attempt} fix attempt(s). "
|
||||
f"Last output: {test_run['output'][:500]}"
|
||||
)
|
||||
models.update_task(conn, task_id, status="blocked", blocked_reason=block_reason)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue