feat(cli): add resource commands (core)
CI / lint (pull_request) Successful in 15s
CI / typecheck (pull_request) Successful in 28s
CI / security (pull_request) Successful in 23s
CI / quality (pull_request) Successful in 15s
CI / integration_tests (pull_request) Successful in 5m11s
CI / build (pull_request) Successful in 16s
CI / unit_tests (pull_request) Successful in 14m31s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 8m18s
CI / lint (push) Successful in 13s
CI / typecheck (push) Successful in 28s
CI / security (push) Successful in 23s
CI / quality (push) Successful in 16s
CI / integration_tests (push) Successful in 4m58s
CI / build (push) Successful in 15s
CI / unit_tests (push) Successful in 15m30s
CI / coverage (push) Has been cancelled
CI / docker (push) Has been cancelled

This commit was merged in pull request #71.
This commit is contained in:
Jeffrey Phillips Freeman
2026-02-15 10:33:34 +00:00
parent 36c571db83
commit f7d2f63ab8
28 changed files with 5852 additions and 122 deletions
+131
View File
@@ -0,0 +1,131 @@
"""ASV benchmarks for project repository operations.
Measures:
- NamespacedProjectRepository create/get/list throughput
- ProjectResourceLinkRepository create_link/list_links throughput
"""
from __future__ import annotations
from datetime import UTC, datetime
from sqlalchemy import create_engine, event, text
from sqlalchemy.orm import Session, sessionmaker
from cleveragents.domain.models.core.project import NamespacedProject
from cleveragents.infrastructure.database.models import (
Base,
ResourceModel,
ResourceTypeModel,
)
from cleveragents.infrastructure.database.repositories import (
NamespacedProjectRepository,
ProjectResourceLinkRepository,
)
def _now_iso() -> str:
return datetime.now(tz=UTC).isoformat()
def _set_sqlite_pragma(dbapi_conn: object, _connection_record: object) -> None:
cursor = dbapi_conn.cursor() # type: ignore[union-attr]
cursor.execute("PRAGMA foreign_keys = ON")
cursor.close()
class ProjectRepositoryCRUD:
"""Benchmark project repository CRUD operations."""
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
event.listen(self.engine, "connect", _set_sqlite_pragma)
with self.engine.connect() as conn:
conn.execute(text("PRAGMA foreign_keys = ON"))
conn.commit()
Base.metadata.create_all(self.engine)
self.sf = sessionmaker(bind=self.engine)
def teardown(self) -> None:
self.engine.dispose()
def time_create_and_get_project(self) -> None:
repo = NamespacedProjectRepository(session_factory=self.sf)
session = self.sf()
project = NamespacedProject(name="bench-proj", namespace="bench")
repo.create(project)
session.commit()
repo.get("bench/bench-proj")
repo.delete("bench/bench-proj")
session.commit()
def time_list_50_projects(self) -> None:
repo = NamespacedProjectRepository(session_factory=self.sf)
session = self.sf()
for i in range(50):
repo.create(NamespacedProject(name=f"proj-{i}", namespace="bench"))
session.commit()
repo.list_projects(namespace="bench", limit=50)
for i in range(50):
repo.delete(f"bench/proj-{i}")
session.commit()
class LinkRepositoryCRUD:
"""Benchmark link repository operations."""
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
event.listen(self.engine, "connect", _set_sqlite_pragma)
with self.engine.connect() as conn:
conn.execute(text("PRAGMA foreign_keys = ON"))
conn.commit()
Base.metadata.create_all(self.engine)
self.sf = sessionmaker(bind=self.engine)
session = self.sf()
# Resource type
rt = ResourceTypeModel()
rt.name = "bench/git-checkout" # type: ignore[assignment]
rt.namespace = "bench" # type: ignore[assignment]
rt.resource_kind = "physical" # type: ignore[assignment]
rt.user_addable = True # type: ignore[assignment]
rt.created_at = _now_iso() # type: ignore[assignment]
rt.updated_at = _now_iso() # type: ignore[assignment]
session.add(rt)
session.commit()
# Project
project_repo = NamespacedProjectRepository(session_factory=self.sf)
project_repo.create(NamespacedProject(name="link-bench", namespace="bench"))
session.commit()
# Resources
for i in range(30):
r = ResourceModel()
r.resource_id = str(i).zfill(26) # type: ignore[assignment]
r.type_name = "bench/git-checkout" # type: ignore[assignment]
r.resource_kind = "physical" # type: ignore[assignment]
r.created_at = _now_iso() # type: ignore[assignment]
r.updated_at = _now_iso() # type: ignore[assignment]
session.add(r)
session.commit()
def teardown(self) -> None:
self.engine.dispose()
def time_create_and_list_30_links(self) -> None:
link_repo = ProjectResourceLinkRepository(session_factory=self.sf)
session = self.sf()
link_ids: list[str] = []
for i in range(30):
link = link_repo.create_link(
project_name="bench/link-bench",
resource_id=str(i).zfill(26),
)
session.commit()
link_ids.append(str(link.link_id))
link_repo.list_links("bench/link-bench")
for lid in link_ids:
link_repo.remove_link(lid)
session.commit()
+103
View File
@@ -0,0 +1,103 @@
"""ASV benchmarks for Resource CLI command parsing overhead.
Measures the import time and basic construction of resource CLI objects
to track startup overhead.
"""
from __future__ import annotations
class ResourceCliImportBench:
"""Benchmark resource CLI module import time."""
timeout = 30.0
def setup(self) -> None:
"""Pre-warm Python import caches."""
pass
def time_import_resource_module(self) -> None:
"""Measure import time of the resource CLI module."""
import importlib
import cleveragents.cli.commands.resource as mod
importlib.reload(mod)
def time_import_formatting_module(self) -> None:
"""Measure import time of the formatting module."""
import importlib
import cleveragents.cli.formatting as mod
importlib.reload(mod)
class ResourceDictConversionBench:
"""Benchmark resource dict conversion helpers."""
timeout = 30.0
def setup(self) -> None:
"""Set up test data."""
from datetime import UTC, datetime
self.mock_resource_data = {
"resource_id": "01HXYZ1234567890ABCDEFGHIJ",
"name": "local/bench-resource",
"resource_type_name": "git-checkout",
"classification": "physical",
"description": "Benchmark test resource",
"location": "/tmp/bench",
"properties": {"path": "/tmp/bench", "branch": "main"},
"created_at": datetime.now(tz=UTC),
"updated_at": datetime.now(tz=UTC),
}
def time_resource_dict_construction(self) -> None:
"""Measure dict construction for resource output."""
data = self.mock_resource_data
result = {
"resource_id": data["resource_id"],
"name": data["name"],
"type": data["resource_type_name"],
"classification": str(data["classification"]),
"description": data["description"],
"location": data["location"],
"properties": data["properties"],
"created_at": data["created_at"].isoformat(),
"updated_at": data["updated_at"].isoformat(),
}
assert result["name"] == "local/bench-resource"
class ResourceTypeListBench:
"""Benchmark resource type list operations."""
timeout = 60.0
def setup(self) -> None:
"""Create an in-memory registry with bootstrapped types."""
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from cleveragents.application.services.resource_registry_service import (
ResourceRegistryService,
)
from cleveragents.infrastructure.database.models import Base
engine = create_engine("sqlite:///:memory:", echo=False)
Base.metadata.create_all(engine)
factory = sessionmaker(bind=engine, expire_on_commit=False)
self.service = ResourceRegistryService(session_factory=factory)
self.service.bootstrap_builtin_types()
def time_list_types(self) -> None:
"""Measure listing all resource types."""
types = self.service.list_types()
assert len(types) >= 2
def time_show_type(self) -> None:
"""Measure showing a single resource type."""
spec = self.service.show_type("git-checkout")
assert spec.name == "git-checkout"
+74
View File
@@ -0,0 +1,74 @@
"""ASV benchmarks for ResourceRegistryService operations."""
from __future__ import annotations
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from cleveragents.application.services.resource_registry_service import (
ResourceRegistryService,
)
from cleveragents.infrastructure.database.models import Base
class BootstrapBenchmark:
"""Benchmark built-in type bootstrap."""
timeout = 30.0
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(self.engine)
self.factory = sessionmaker(bind=self.engine)
def time_bootstrap_builtin_types(self) -> None:
svc = ResourceRegistryService(session_factory=self.factory)
svc.bootstrap_builtin_types()
def time_bootstrap_idempotent(self) -> None:
svc = ResourceRegistryService(session_factory=self.factory)
svc.bootstrap_builtin_types()
svc.bootstrap_builtin_types()
class ListTypesBenchmark:
"""Benchmark type listing operations."""
timeout = 30.0
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(self.engine)
self.factory = sessionmaker(bind=self.engine)
svc = ResourceRegistryService(session_factory=self.factory)
svc.bootstrap_builtin_types()
self.svc = svc
def time_list_all_types(self) -> None:
self.svc.list_types()
def time_show_type(self) -> None:
self.svc.show_type("git-checkout")
class RegisterResourceBenchmark:
"""Benchmark resource registration."""
timeout = 30.0
def setup(self) -> None:
self.engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(self.engine)
self.factory = sessionmaker(bind=self.engine)
svc = ResourceRegistryService(session_factory=self.factory)
svc.bootstrap_builtin_types()
self.svc = svc
self.counter = 0
def time_register_resource(self) -> None:
self.counter += 1
self.svc.register_resource(
type_name="git-checkout",
name=f"local/bench-repo-{self.counter}",
location="/tmp/bench",
)