diff --git a/src/agent_gitea/cli.py b/src/agent_gitea/cli.py index a80cb46..0b094ba 100644 --- a/src/agent_gitea/cli.py +++ b/src/agent_gitea/cli.py @@ -1,5 +1,6 @@ from __future__ import annotations +import logging from pathlib import Path from typing import Annotated @@ -30,6 +31,8 @@ def main( ctx: typer.Context, config: Annotated[Path, typer.Option("--config", "-c", help="Path to YAML config.")] = Path("config.yaml"), ) -> None: + logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s") + logging.getLogger("httpx").setLevel(logging.WARNING) ctx.obj = CliContext(config) diff --git a/src/agent_gitea/gitea.py b/src/agent_gitea/gitea.py index 9280e98..7e1ea03 100644 --- a/src/agent_gitea/gitea.py +++ b/src/agent_gitea/gitea.py @@ -92,7 +92,7 @@ class GiteaClient: response.raise_for_status() issues: list[GiteaIssue] = [] for item in response.json(): - if "pull_request" in item: + if item.get("pull_request"): continue issues.append( GiteaIssue( diff --git a/src/agent_gitea/service.py b/src/agent_gitea/service.py index 0f06a78..e21fe47 100644 --- a/src/agent_gitea/service.py +++ b/src/agent_gitea/service.py @@ -2,6 +2,7 @@ from __future__ import annotations import socket import time +import logging from pathlib import Path from .agents import CommandRunner, read_report, render_command, write_prompt @@ -21,6 +22,9 @@ from .state import validate_transition from .workspace import WorkspaceManager, safe_branch_name +logger = logging.getLogger(__name__) + + def sync_repositories(db: Database, config: AppConfig, client: GiteaClient) -> list[RepositoryRecord]: synced: list[RepositoryRecord] = [] discovered = client.list_owned_repositories() @@ -89,10 +93,19 @@ class TaskRunner: def worker_loop(self) -> None: while True: - sync_repositories(self.db, self.config, self.gitea) - scan_issues(self.db, self.config, self.gitea) - task = self.run_once() - if task is None: + try: + repos = sync_repositories(self.db, self.config, self.gitea) + logger.info("synced %d repositories", len(repos)) + task_ids = scan_issues(self.db, self.config, self.gitea) + logger.info("created %d tasks from issue scan", len(task_ids)) + task = self.run_once() + if task is None: + logger.info("no task available; sleeping %d seconds", self.config.scheduler.interval_seconds) + time.sleep(self.config.scheduler.interval_seconds) + else: + logger.info("task %d finished in state %s", task.id, task.state.value) + except Exception: + logger.exception("worker iteration failed") time.sleep(self.config.scheduler.interval_seconds) def run_claimed(self, task: TaskRecord) -> TaskRecord: diff --git a/tests/test_gitea_service.py b/tests/test_gitea_service.py index 68fff9a..e580723 100644 --- a/tests/test_gitea_service.py +++ b/tests/test_gitea_service.py @@ -89,6 +89,36 @@ def test_sync_and_scan_with_mocked_gitea(db, tmp_path): assert len(task_ids) == 1 +def test_list_open_issues_keeps_normal_issues_with_null_pull_request(): + def handler(request: httpx.Request) -> httpx.Response: + assert request.url.path == "/api/v1/repos/acme/service/issues" + return httpx.Response( + 200, + json=[ + { + "number": 1, + "title": "Normal issue", + "body": "Body", + "state": "open", + "labels": [{"name": "agent:ready"}], + "pull_request": None, + }, + { + "number": 2, + "title": "PR issue", + "body": "Body", + "state": "open", + "labels": [{"name": "agent:ready"}], + "pull_request": {"url": "https://gitea.test/pr/2"}, + }, + ], + ) + + issues = make_client(handler).list_open_issues("acme", "service") + + assert [issue.number for issue in issues] == [1] + + class FakeWorkspaceManager: def __init__(self, root: Path, *, diff: bool = True): self.root = root