From 8428a02f6c3f1a35159bf856601a9c4901e9a8dc Mon Sep 17 00:00:00 2001 From: tegwick Date: Sun, 7 Jun 2026 16:32:16 +0200 Subject: [PATCH] feat: reuse hub-core base schemas --- api/routers/repos.py | 1 + api/schemas/capability_request.py | 53 ++++--------------------------- api/schemas/managed_repo.py | 37 ++++++--------------- tests/test_hub_core_imports.py | 39 +++++++++++++++++++++++ tests/test_routers_core.py | 17 ++++++++++ 5 files changed, 73 insertions(+), 74 deletions(-) diff --git a/api/routers/repos.py b/api/routers/repos.py index 0766002..c8b0bc7 100644 --- a/api/routers/repos.py +++ b/api/routers/repos.py @@ -87,6 +87,7 @@ async def register_repo( slug=body.slug, name=body.name, local_path=body.local_path, + host_paths=body.host_paths, remote_url=body.remote_url, git_fingerprint=body.git_fingerprint, description=body.description, diff --git a/api/schemas/capability_request.py b/api/schemas/capability_request.py index a0ca3ae..222c5ab 100644 --- a/api/schemas/capability_request.py +++ b/api/schemas/capability_request.py @@ -3,41 +3,13 @@ from datetime import datetime from pydantic import BaseModel, ConfigDict - -# --------------------------------------------------------------------------- -# Capability Catalog schemas -# --------------------------------------------------------------------------- - -class CatalogCreate(BaseModel): - domain: str # slug, resolved to domain_id in router - capability_type: str - title: str - description: str | None = None - keywords: list[str] = [] - repo_slug: str | None = None # optional repo attribution - - -class CatalogPatch(BaseModel): - repo_slug: str | None = None - description: str | None = None - keywords: list[str] | None = None - status: str | None = None - - -class CatalogRead(BaseModel): - model_config = ConfigDict(from_attributes=True) - - id: uuid.UUID - domain_slug: str - repo_id: uuid.UUID | None = None - repo_slug: str | None = None - capability_type: str - title: str - description: str | None = None - keywords: list[str] = [] - status: str - created_at: datetime - updated_at: datetime +from hub_core.schemas.capability import ( + CapabilityRequestDispute, + CapabilityRequestStatusPatch, + CatalogCreate, + CatalogPatch, + CatalogRead, +) # --------------------------------------------------------------------------- @@ -60,11 +32,6 @@ class CapabilityRequestAccept(BaseModel): fulfilling_workstream_id: uuid.UUID | None = None -class CapabilityRequestStatusPatch(BaseModel): - status: str # in_progress | ready_for_review | completed | rejected | withdrawn - note: str | None = None - - class CapabilityRequestPatch(BaseModel): catalog_entry_id: uuid.UUID | None = None priority: str | None = None @@ -72,12 +39,6 @@ class CapabilityRequestPatch(BaseModel): fulfilling_workstream_id: uuid.UUID | None = None -class CapabilityRequestDispute(BaseModel): - reason: str - disputed_by: str - suggested_domain: str | None = None - - class CapabilityRequestReroute(BaseModel): note: str rerouted_by: str diff --git a/api/schemas/managed_repo.py b/api/schemas/managed_repo.py index 9486ec6..b6f28ce 100644 --- a/api/schemas/managed_repo.py +++ b/api/schemas/managed_repo.py @@ -2,17 +2,16 @@ import uuid from datetime import date, datetime from typing import Any, Literal -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, Field + +from hub_core.schemas.managed_repo import ( + RepoCreate as CoreRepoCreate, + RepoPathRegister, + RepoRead as CoreRepoRead, +) -class RepoCreate(BaseModel): - domain_slug: str - slug: str - name: str - local_path: str | None = None - remote_url: str | None = None - git_fingerprint: str | None = None - description: str | None = None +class RepoCreate(CoreRepoCreate): topic_id: uuid.UUID | None = None @@ -26,12 +25,6 @@ class RepoUpdate(BaseModel): last_state_synced_at: datetime | None = None -class RepoPathRegister(BaseModel): - """Register a machine-local path for a repo on a specific host.""" - host: str - path: str - - class RepoOnboardRequest(BaseModel): """Start scripted onboarding for a working copy that is visible to State Hub.""" domain_slug: str @@ -49,19 +42,7 @@ class RepoOnboardResult(BaseModel): stderr: str = "" -class RepoRead(BaseModel): - model_config = ConfigDict(from_attributes=True) - id: uuid.UUID - domain_id: uuid.UUID - domain_slug: str # derived from domain relationship - slug: str - name: str - local_path: str | None = None - host_paths: dict = {} - remote_url: str | None = None - git_fingerprint: str | None = None - description: str | None = None - status: str +class RepoRead(CoreRepoRead): topic_id: uuid.UUID | None = None sbom_source: str | None = None last_sbom_at: datetime | None = None diff --git a/tests/test_hub_core_imports.py b/tests/test_hub_core_imports.py index b1ae3e0..b3765da 100644 --- a/tests/test_hub_core_imports.py +++ b/tests/test_hub_core_imports.py @@ -1,8 +1,23 @@ from api.schemas.agent_message import MessageCreate +from api.schemas.capability_request import ( + CapabilityRequestDispute, + CapabilityRequestStatusPatch, + CatalogCreate, + CatalogPatch, + CatalogRead, +) from api.schemas.doi import DoIReport from api.schemas.domain import DomainCreate, DomainRead, DomainRename, DomainUpdate +from api.schemas.managed_repo import RepoCreate, RepoPathRegister, RepoRead from api.schemas.tpsc import GDPR_WARNING_LEVELS, TPSCCatalogRead, TPSCGDPRReport from hub_core.schemas.agent_message import MessageCreate as CoreMessageCreate +from hub_core.schemas.capability import ( + CapabilityRequestDispute as CoreCapabilityRequestDispute, + CapabilityRequestStatusPatch as CoreCapabilityRequestStatusPatch, + CatalogCreate as CoreCatalogCreate, + CatalogPatch as CoreCatalogPatch, + CatalogRead as CoreCatalogRead, +) from hub_core.schemas.doi import DoIReport as CoreDoIReport from hub_core.schemas.domain import ( DomainCreate as CoreDomainCreate, @@ -10,6 +25,11 @@ from hub_core.schemas.domain import ( DomainRename as CoreDomainRename, DomainUpdate as CoreDomainUpdate, ) +from hub_core.schemas.managed_repo import ( + RepoCreate as CoreRepoCreate, + RepoPathRegister as CoreRepoPathRegister, + RepoRead as CoreRepoRead, +) from hub_core.schemas.tpsc import ( GDPR_WARNING_LEVELS as CORE_GDPR_WARNING_LEVELS, TPSCCatalogRead as CoreTPSCCatalogRead, @@ -32,6 +52,25 @@ def test_state_hub_reexports_core_domain_base_schemas() -> None: assert DomainUpdate is CoreDomainUpdate +def test_state_hub_reexports_core_capability_base_schemas() -> None: + assert CatalogCreate is CoreCatalogCreate + assert CatalogPatch is CoreCatalogPatch + assert CatalogRead is CoreCatalogRead + assert CapabilityRequestDispute is CoreCapabilityRequestDispute + assert CapabilityRequestStatusPatch is CoreCapabilityRequestStatusPatch + + +def test_state_hub_reexports_core_repo_path_schema() -> None: + assert RepoPathRegister is CoreRepoPathRegister + + +def test_state_hub_repo_schemas_extend_core_contracts() -> None: + assert issubclass(RepoCreate, CoreRepoCreate) + assert issubclass(RepoRead, CoreRepoRead) + assert "topic_id" in RepoCreate.model_fields + assert "last_state_synced_at" in RepoRead.model_fields + + def test_state_hub_reexports_core_tpsc_schemas() -> None: assert TPSCCatalogRead is CoreTPSCCatalogRead assert TPSCGDPRReport is CoreTPSCGDPRReport diff --git a/tests/test_routers_core.py b/tests/test_routers_core.py index 2feee97..a31c507 100644 --- a/tests/test_routers_core.py +++ b/tests/test_routers_core.py @@ -75,6 +75,23 @@ class TestDomains: assert r.status_code == 409 +# --------------------------------------------------------------------------- +# Repo tests +# --------------------------------------------------------------------------- + +class TestRepos: + async def test_create_persists_host_paths(self, client): + await _create_domain(client) + r = await client.post("/repos/", json={ + "domain_slug": "testdomain", + "slug": "hosted-repo", + "name": "Hosted Repo", + "host_paths": {"workstation": "/srv/hosted-repo"}, + }) + assert r.status_code == 201 + assert r.json()["host_paths"] == {"workstation": "/srv/hosted-repo"} + + # --------------------------------------------------------------------------- # Topic tests # ---------------------------------------------------------------------------