reorg files
This commit is contained in:
+8
-7
@@ -4,7 +4,8 @@ from types import SimpleNamespace
|
||||
import pytest
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
|
||||
import agentci.app as app_module
|
||||
import agentci.api.app as app_module
|
||||
import agentci.api.lifespan as lifespan_module
|
||||
|
||||
|
||||
class BlockingWorker:
|
||||
@@ -56,8 +57,8 @@ async def test_lifespan_starts_worker_cancels_it_and_closes_runtime(
|
||||
built_with.append(settings)
|
||||
return runtime
|
||||
|
||||
monkeypatch.setattr(app_module, "build_runtime", build)
|
||||
monkeypatch.setattr(app_module, "configure_logging", lambda: configured.append(True))
|
||||
monkeypatch.setattr(lifespan_module, "build_runtime", build)
|
||||
monkeypatch.setattr(lifespan_module, "configure_logging", lambda: configured.append(True))
|
||||
application = app_module.create_app(selected_settings) # type: ignore[arg-type]
|
||||
|
||||
async with application.router.lifespan_context(application):
|
||||
@@ -80,8 +81,8 @@ async def test_lifespan_closes_runtime_when_worker_task_fails(
|
||||
async def build(_settings: object) -> FakeRuntime:
|
||||
return runtime
|
||||
|
||||
monkeypatch.setattr(app_module, "build_runtime", build)
|
||||
monkeypatch.setattr(app_module, "configure_logging", lambda: None)
|
||||
monkeypatch.setattr(lifespan_module, "build_runtime", build)
|
||||
monkeypatch.setattr(lifespan_module, "configure_logging", lambda: None)
|
||||
application = app_module.create_app(SimpleNamespace()) # type: ignore[arg-type]
|
||||
|
||||
with pytest.raises(RuntimeError, match="worker failed"):
|
||||
@@ -100,8 +101,8 @@ async def test_lifespan_propagates_runtime_startup_failure_without_starting_work
|
||||
async def fail_build(_settings: object) -> None:
|
||||
raise RuntimeError("database unavailable")
|
||||
|
||||
monkeypatch.setattr(app_module, "build_runtime", fail_build)
|
||||
monkeypatch.setattr(app_module, "configure_logging", lambda: configured.append(True))
|
||||
monkeypatch.setattr(lifespan_module, "build_runtime", fail_build)
|
||||
monkeypatch.setattr(lifespan_module, "configure_logging", lambda: configured.append(True))
|
||||
application = app_module.create_app(SimpleNamespace()) # type: ignore[arg-type]
|
||||
|
||||
with pytest.raises(RuntimeError, match="database unavailable"):
|
||||
|
||||
@@ -2,7 +2,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from agentci.codegraph import CodeGraph, CodeGraphError
|
||||
from agentci.integrations.codegraph import CodeGraph, CodeGraphError
|
||||
|
||||
|
||||
class FakeProcess:
|
||||
@@ -27,7 +27,7 @@ async def test_initializes_incomplete_index_and_excludes_it_from_git(
|
||||
return FakeProcess()
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agentci.codegraph.asyncio.create_subprocess_exec",
|
||||
"agentci.integrations.codegraph.asyncio.create_subprocess_exec",
|
||||
create_subprocess_exec,
|
||||
)
|
||||
|
||||
@@ -53,7 +53,7 @@ async def test_syncs_an_existing_index_without_duplicating_exclude(
|
||||
return FakeProcess()
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agentci.codegraph.asyncio.create_subprocess_exec",
|
||||
"agentci.integrations.codegraph.asyncio.create_subprocess_exec",
|
||||
create_subprocess_exec,
|
||||
)
|
||||
|
||||
@@ -86,7 +86,7 @@ async def test_handles_exclude_file_boundaries(
|
||||
return FakeProcess()
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agentci.codegraph.asyncio.create_subprocess_exec",
|
||||
"agentci.integrations.codegraph.asyncio.create_subprocess_exec",
|
||||
create_subprocess_exec,
|
||||
)
|
||||
|
||||
@@ -103,7 +103,7 @@ async def test_reports_missing_executable(tmp_path: Path, monkeypatch: pytest.Mo
|
||||
raise FileNotFoundError(2, "No such file or directory", "codegraph")
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agentci.codegraph.asyncio.create_subprocess_exec",
|
||||
"agentci.integrations.codegraph.asyncio.create_subprocess_exec",
|
||||
create_subprocess_exec,
|
||||
)
|
||||
|
||||
@@ -125,7 +125,7 @@ async def test_reports_nonzero_exit_with_bounded_non_utf8_stderr(
|
||||
return FakeProcess(returncode=7, stderr=stderr)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agentci.codegraph.asyncio.create_subprocess_exec",
|
||||
"agentci.integrations.codegraph.asyncio.create_subprocess_exec",
|
||||
create_subprocess_exec,
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from pathlib import Path
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from agentci.config import Settings
|
||||
from agentci.config.settings import Settings
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from typing import cast
|
||||
|
||||
from agentci.engine.repository import Repository
|
||||
from agentci.gitea import CommentInfo, Gitea, IssueInfo, PullRequestInfo
|
||||
from agentci.integrations.gitea.client import Gitea
|
||||
from agentci.integrations.gitea.models import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.workflows.context import build_issue_context, build_pull_request_context
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from agentci.development import (
|
||||
from agentci.integrations.development import (
|
||||
DevelopmentEnvironment,
|
||||
DevelopmentEnvironmentError,
|
||||
)
|
||||
@@ -169,7 +169,7 @@ async def test_wraps_subprocess_start_error(
|
||||
raise OSError("exec unavailable")
|
||||
|
||||
monkeypatch.setattr(
|
||||
"agentci.development.asyncio.create_subprocess_exec",
|
||||
"agentci.integrations.development.asyncio.create_subprocess_exec",
|
||||
create_subprocess_exec,
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from agentci.git import Git, GitError
|
||||
from agentci.integrations.git import Git, GitError
|
||||
|
||||
|
||||
class FakeProcess:
|
||||
|
||||
+9
-8
@@ -1,17 +1,18 @@
|
||||
import json
|
||||
from collections.abc import AsyncIterator, Callable, Coroutine
|
||||
from collections.abc import AsyncGenerator, Callable, Coroutine
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from agentci.gitea import CommentInfo, Gitea, GiteaError, IssueInfo, PullRequestInfo
|
||||
from agentci.integrations.gitea.client import Gitea, GiteaError
|
||||
from agentci.integrations.gitea.models import CommentInfo, IssueInfo, PullRequestInfo
|
||||
|
||||
Handler = Callable[[httpx.Request], Coroutine[None, None, httpx.Response]]
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def gitea_client(handler: Handler, *, retries: int = 3) -> AsyncIterator[Gitea]:
|
||||
async def gitea_client(handler: Handler, *, retries: int = 3) -> AsyncGenerator[Gitea]:
|
||||
client = Gitea(
|
||||
"https://gitea.example/",
|
||||
"secret",
|
||||
@@ -232,7 +233,7 @@ async def test_nonretryable_status_fails_once(status: int, monkeypatch: pytest.M
|
||||
async def sleep(delay: int) -> None:
|
||||
sleeps.append(delay)
|
||||
|
||||
monkeypatch.setattr("agentci.gitea.asyncio.sleep", sleep)
|
||||
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
|
||||
async with gitea_client(handler) as client:
|
||||
with pytest.raises(
|
||||
GiteaError,
|
||||
@@ -261,7 +262,7 @@ async def test_retryable_status_recovers_after_backoff(
|
||||
async def sleep(delay: int) -> None:
|
||||
sleeps.append(delay)
|
||||
|
||||
monkeypatch.setattr("agentci.gitea.asyncio.sleep", sleep)
|
||||
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
|
||||
async with gitea_client(handler) as client:
|
||||
assert await client.default_branch("org", "repo") == "main"
|
||||
|
||||
@@ -283,7 +284,7 @@ async def test_retryable_status_exhaustion_uses_exponential_backoff(
|
||||
async def sleep(delay: int) -> None:
|
||||
sleeps.append(delay)
|
||||
|
||||
monkeypatch.setattr("agentci.gitea.asyncio.sleep", sleep)
|
||||
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
|
||||
async with gitea_client(handler) as client:
|
||||
with pytest.raises(
|
||||
GiteaError,
|
||||
@@ -309,7 +310,7 @@ async def test_transport_failure_retries_and_recovers(monkeypatch: pytest.Monkey
|
||||
async def sleep(delay: int) -> None:
|
||||
sleeps.append(delay)
|
||||
|
||||
monkeypatch.setattr("agentci.gitea.asyncio.sleep", sleep)
|
||||
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
|
||||
async with gitea_client(handler) as client:
|
||||
assert await client.default_branch("org", "repo") == "main"
|
||||
|
||||
@@ -331,7 +332,7 @@ async def test_transport_failure_exhaustion_preserves_cause(
|
||||
async def sleep(delay: int) -> None:
|
||||
sleeps.append(delay)
|
||||
|
||||
monkeypatch.setattr("agentci.gitea.asyncio.sleep", sleep)
|
||||
monkeypatch.setattr("agentci.integrations.gitea.client.asyncio.sleep", sleep)
|
||||
async with gitea_client(handler, retries=2) as client:
|
||||
with pytest.raises(
|
||||
GiteaError,
|
||||
|
||||
@@ -4,7 +4,7 @@ import pytest
|
||||
from fastapi import FastAPI
|
||||
from httpx import ASGITransport, AsyncClient, Response
|
||||
|
||||
from agentci.health import router
|
||||
from agentci.api.routes.health import router
|
||||
|
||||
|
||||
class Provider:
|
||||
|
||||
@@ -6,7 +6,7 @@ from datetime import UTC, datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from agentci.logging import JsonFormatter, configure_logging
|
||||
from agentci.observability.logging import JsonFormatter, configure_logging
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
||||
@@ -5,7 +5,7 @@ from pathlib import Path
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from agentci.opencode import OpenCode, OpenCodeError
|
||||
from agentci.integrations.opencode.client import OpenCode, OpenCodeError
|
||||
from agentci.workflows.model import AgentResult
|
||||
|
||||
API_DOCUMENT = {
|
||||
|
||||
@@ -3,7 +3,7 @@ from pathlib import Path
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
from agentci.opencode import OpenCode, OpenCodeError
|
||||
from agentci.integrations.opencode.client import OpenCode, OpenCodeError
|
||||
|
||||
|
||||
def client(tmp_path: Path, status: int) -> OpenCode:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from agentci.opencode import api_contract_ready, models_ready
|
||||
from agentci.integrations.opencode.readiness import api_contract_ready, models_ready
|
||||
|
||||
|
||||
def test_api_contract_requires_session_message_and_abort_routes() -> None:
|
||||
|
||||
@@ -5,8 +5,8 @@ import pytest
|
||||
from pydantic import BaseModel
|
||||
|
||||
import agentci.prompts
|
||||
from agentci.opencode import load_schema
|
||||
from agentci.prompts import PromptLibrary
|
||||
from agentci.integrations.opencode.schemas import load_schema
|
||||
from agentci.prompts.library import PromptLibrary
|
||||
from agentci.workflows.model import (
|
||||
AgentResult,
|
||||
DiscussionReply,
|
||||
|
||||
+6
-10
@@ -4,9 +4,9 @@ from unittest.mock import AsyncMock, Mock
|
||||
|
||||
import pytest
|
||||
|
||||
import agentci.runtime as runtime_module
|
||||
from agentci.config import Settings
|
||||
from agentci.runtime import Runtime
|
||||
import agentci.application.runtime as runtime_module
|
||||
from agentci.application.runtime import Runtime
|
||||
from agentci.config.settings import Settings
|
||||
|
||||
|
||||
class ClosingClient:
|
||||
@@ -90,7 +90,7 @@ async def test_build_runtime_wires_components_without_starting_real_clients(
|
||||
git = SimpleNamespace()
|
||||
opencode = SimpleNamespace()
|
||||
development = SimpleNamespace()
|
||||
prompts = SimpleNamespace()
|
||||
prompts = SimpleNamespace(schemas_dir=tmp_path / "schemas")
|
||||
services = SimpleNamespace()
|
||||
worker = SimpleNamespace()
|
||||
repository_constructor = Mock(return_value=repository)
|
||||
@@ -112,11 +112,7 @@ async def test_build_runtime_wires_components_without_starting_real_clients(
|
||||
|
||||
built = await runtime_module.build_runtime(settings)
|
||||
|
||||
assert runtime_module.__file__ is not None
|
||||
package_dir = Path(runtime_module.__file__).parent
|
||||
repository_constructor.assert_called_once_with(
|
||||
settings.database_path, package_dir / "migrations"
|
||||
)
|
||||
repository_constructor.assert_called_once_with(settings.database_path)
|
||||
initialize.assert_awaited_once_with()
|
||||
gitea_constructor.assert_called_once_with("https://gitea.example", "token")
|
||||
git_constructor.assert_called_once_with(
|
||||
@@ -131,7 +127,7 @@ async def test_build_runtime_wires_components_without_starting_real_clients(
|
||||
base_url="https://opencode.example",
|
||||
username=settings.opencode_server_username,
|
||||
password="password",
|
||||
schemas_dir=package_dir / "prompts" / "schemas",
|
||||
schemas_dir=prompts.schemas_dir,
|
||||
health_directory=settings.workspaces_dir,
|
||||
required_models=(
|
||||
(settings.plan_model, settings.plan_variant),
|
||||
|
||||
@@ -7,8 +7,12 @@ import pytest
|
||||
from fastapi import FastAPI
|
||||
from httpx import ASGITransport, AsyncClient, Response
|
||||
|
||||
from agentci.api.routes.webhook import router
|
||||
from agentci.engine.model import IncomingCommand
|
||||
from agentci.webhook import _event_from_payload, router, valid_signature
|
||||
from agentci.integrations.gitea.webhooks import (
|
||||
incoming_command_from_payload,
|
||||
valid_signature,
|
||||
)
|
||||
|
||||
|
||||
class FakeRepository:
|
||||
@@ -167,7 +171,7 @@ def test_payload_parser_supports_owner_username_and_pull_request() -> None:
|
||||
value = payload("/agent plan", is_pull=True)
|
||||
value["repository"]["owner"] = {"username": "fallback-owner"}
|
||||
|
||||
event = _event_from_payload("delivery", value)
|
||||
event = incoming_command_from_payload("delivery", value)
|
||||
|
||||
assert event is not None
|
||||
assert event.repo_owner == "fallback-owner"
|
||||
|
||||
@@ -5,6 +5,8 @@ from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from agentci.application.worker.errors import safe_error
|
||||
from agentci.application.worker.runner import Worker
|
||||
from agentci.engine.events import (
|
||||
CommentLinked,
|
||||
JobCompleted,
|
||||
@@ -30,8 +32,7 @@ from agentci.engine.model import (
|
||||
)
|
||||
from agentci.engine.reducer import render_job_comment
|
||||
from agentci.engine.repository import Repository
|
||||
from agentci.gitea import CommentInfo
|
||||
from agentci.worker import Worker, _safe_error
|
||||
from agentci.integrations.gitea.models import CommentInfo
|
||||
from agentci.workflows.render import JobRejected
|
||||
|
||||
MIGRATIONS = Path(__file__).parents[1] / "src" / "agentci" / "migrations"
|
||||
@@ -408,7 +409,7 @@ async def test_execute_completes_with_workflow_comment(
|
||||
async def dispatch(_job: Job, _run: object, _services: object) -> str:
|
||||
return "final workflow body"
|
||||
|
||||
monkeypatch.setattr("agentci.worker.dispatch", dispatch)
|
||||
monkeypatch.setattr("agentci.application.worker.execution.dispatch", dispatch)
|
||||
execute = task()
|
||||
|
||||
await value._execute(execute, current)
|
||||
@@ -432,7 +433,7 @@ async def test_execute_records_expected_rejection(
|
||||
async def dispatch(_job: Job, _run: object, _services: object) -> str:
|
||||
raise JobRejected("pull request is closed")
|
||||
|
||||
monkeypatch.setattr("agentci.worker.dispatch", dispatch)
|
||||
monkeypatch.setattr("agentci.application.worker.execution.dispatch", dispatch)
|
||||
|
||||
await make_worker(tmp_path, repository)._execute(task(), current)
|
||||
|
||||
@@ -452,7 +453,7 @@ async def test_execute_records_failure_at_latest_persisted_stage(
|
||||
repository.job = replace(repository.job, stage="cloning")
|
||||
raise RuntimeError("provider\nfailed")
|
||||
|
||||
monkeypatch.setattr("agentci.worker.dispatch", dispatch)
|
||||
monkeypatch.setattr("agentci.application.worker.execution.dispatch", dispatch)
|
||||
|
||||
await make_worker(tmp_path, repository)._execute(task(), current)
|
||||
|
||||
@@ -471,7 +472,7 @@ async def test_execute_marks_running_job_interrupted_after_restart(
|
||||
async def unexpected_dispatch(_job: Job, _run: object, _services: object) -> str:
|
||||
pytest.fail("running jobs must not be dispatched again")
|
||||
|
||||
monkeypatch.setattr("agentci.worker.dispatch", unexpected_dispatch)
|
||||
monkeypatch.setattr("agentci.application.worker.execution.dispatch", unexpected_dispatch)
|
||||
execute = task()
|
||||
|
||||
await make_worker(tmp_path, repository)._execute(execute, current)
|
||||
@@ -642,7 +643,7 @@ async def test_abort_without_persisted_sessions_is_noop(tmp_path: Path) -> None:
|
||||
|
||||
|
||||
def test_safe_error_is_single_line_and_bounded() -> None:
|
||||
value = _safe_error(RuntimeError("bad\n" + "x" * 2000))
|
||||
value = safe_error(RuntimeError("bad\n" + "x" * 2000))
|
||||
|
||||
assert "\n" not in value
|
||||
assert len(value) == 1000
|
||||
|
||||
@@ -7,7 +7,7 @@ import pytest
|
||||
|
||||
from agentci.engine.model import Job, JobKind, Workflow, WorkflowKind, WorkflowStatus
|
||||
from agentci.engine.run import JobRun
|
||||
from agentci.gitea import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.integrations.gitea.models import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.workflows.implementation import implement
|
||||
from agentci.workflows.model import AgentResult, ReviewReport
|
||||
from agentci.workflows.render import JobRejected
|
||||
|
||||
@@ -8,7 +8,7 @@ from pydantic import BaseModel
|
||||
|
||||
from agentci.engine.model import Job, JobKind, Workflow, WorkflowKind, WorkflowStatus
|
||||
from agentci.engine.run import JobRun
|
||||
from agentci.gitea import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.integrations.gitea.models import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.workflows.model import DiscussionReply, PlanArtifact, ReviewReport
|
||||
from agentci.workflows.plan import create_plan, discuss_plan, iterate_plan
|
||||
from agentci.workflows.render import JobRejected
|
||||
|
||||
@@ -8,7 +8,7 @@ from pydantic import BaseModel
|
||||
|
||||
from agentci.engine.model import Job, JobKind, Workflow, WorkflowKind, WorkflowStatus
|
||||
from agentci.engine.run import JobRun
|
||||
from agentci.gitea import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.integrations.gitea.models import CommentInfo, IssueInfo, PullRequestInfo
|
||||
from agentci.workflows.model import AgentResult, ReviewReport
|
||||
from agentci.workflows.pull_request import fix_pull_request, iterate_implementation
|
||||
from agentci.workflows.render import JobRejected
|
||||
|
||||
Reference in New Issue
Block a user