generated from coulomb/repo-seed
API-completeness polish
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from dataclasses import asdict
|
from dataclasses import asdict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from fastapi import Depends, FastAPI, HTTPException, Query
|
from fastapi import Depends, FastAPI, HTTPException, Query
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
@@ -324,6 +325,220 @@ class CandidateEvidenceMerge(BaseModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RepositoryResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
url: str
|
||||||
|
description: str | None
|
||||||
|
branch: str
|
||||||
|
status: str
|
||||||
|
|
||||||
|
|
||||||
|
class RepositorySnapshotResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
commit_hash: str
|
||||||
|
branch: str
|
||||||
|
source_path: str
|
||||||
|
file_count: int
|
||||||
|
|
||||||
|
|
||||||
|
class AnalysisRunResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
snapshot_id: int | None
|
||||||
|
status: str
|
||||||
|
started_at: str
|
||||||
|
completed_at: str | None
|
||||||
|
error_message: str | None
|
||||||
|
scanner_version: str
|
||||||
|
|
||||||
|
|
||||||
|
class ReviewDecisionResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
analysis_run_id: int | None
|
||||||
|
action: str
|
||||||
|
notes: str
|
||||||
|
created_at: str
|
||||||
|
|
||||||
|
|
||||||
|
class ObservedFactResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
analysis_run_id: int
|
||||||
|
snapshot_id: int | None
|
||||||
|
kind: str
|
||||||
|
path: str
|
||||||
|
name: str
|
||||||
|
value: str
|
||||||
|
metadata: dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class ContentChunkResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
analysis_run_id: int
|
||||||
|
snapshot_id: int | None
|
||||||
|
path: str
|
||||||
|
kind: str
|
||||||
|
start_line: int
|
||||||
|
end_line: int
|
||||||
|
text: str
|
||||||
|
|
||||||
|
|
||||||
|
class ScanSummaryResponse(BaseModel):
|
||||||
|
analysis_run: AnalysisRunResponse
|
||||||
|
snapshot: RepositorySnapshotResponse | None
|
||||||
|
facts: list[ObservedFactResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class SourceReferenceResponse(BaseModel):
|
||||||
|
fact_id: int | None
|
||||||
|
path: str
|
||||||
|
kind: str
|
||||||
|
name: str
|
||||||
|
line: int | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class CandidateEvidenceResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
type: str
|
||||||
|
reference: str
|
||||||
|
strength: str
|
||||||
|
status: str
|
||||||
|
source_refs: list[SourceReferenceResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class CandidateFeatureResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
type: str
|
||||||
|
location: str
|
||||||
|
confidence: float
|
||||||
|
status: str
|
||||||
|
source_refs: list[SourceReferenceResponse]
|
||||||
|
confidence_label: str
|
||||||
|
|
||||||
|
|
||||||
|
class CandidateCapabilityResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
inputs: list[str]
|
||||||
|
outputs: list[str]
|
||||||
|
confidence: float
|
||||||
|
status: str
|
||||||
|
source_refs: list[SourceReferenceResponse]
|
||||||
|
confidence_label: str
|
||||||
|
features: list[CandidateFeatureResponse]
|
||||||
|
evidence: list[CandidateEvidenceResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class CandidateAbilityResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
confidence: float
|
||||||
|
status: str
|
||||||
|
source_refs: list[SourceReferenceResponse]
|
||||||
|
confidence_label: str
|
||||||
|
capabilities: list[CandidateCapabilityResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class CandidateGraphResponse(BaseModel):
|
||||||
|
repository: RepositoryResponse
|
||||||
|
analysis_run: AnalysisRunResponse
|
||||||
|
abilities: list[CandidateAbilityResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class EvidenceResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
type: str
|
||||||
|
reference: str
|
||||||
|
strength: str
|
||||||
|
source_refs: list[SourceReferenceResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class FeatureResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
type: str
|
||||||
|
location: str
|
||||||
|
confidence: float
|
||||||
|
confidence_label: str
|
||||||
|
source_refs: list[SourceReferenceResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class CapabilityResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
inputs: list[str]
|
||||||
|
outputs: list[str]
|
||||||
|
confidence: float
|
||||||
|
confidence_label: str
|
||||||
|
features: list[FeatureResponse]
|
||||||
|
evidence: list[EvidenceResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class AbilityResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
confidence: float
|
||||||
|
confidence_label: str
|
||||||
|
capabilities: list[CapabilityResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class RepositoryAbilityMapResponse(BaseModel):
|
||||||
|
repository: RepositoryResponse
|
||||||
|
abilities: list[AbilityResponse]
|
||||||
|
|
||||||
|
|
||||||
|
class IdResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
|
||||||
|
|
||||||
|
class SearchResultResponse(BaseModel):
|
||||||
|
repository_id: int
|
||||||
|
repository_name: str
|
||||||
|
match_type: str
|
||||||
|
match_name: str
|
||||||
|
confidence: float
|
||||||
|
confidence_label: str
|
||||||
|
match_description: str
|
||||||
|
matched_field: str
|
||||||
|
ability_id: int | None = None
|
||||||
|
ability_name: str | None = None
|
||||||
|
capability_id: int | None = None
|
||||||
|
capability_name: str | None = None
|
||||||
|
evidence_level: str | None = None
|
||||||
|
source_reference: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class AbilitySummaryResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
repository_name: str
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
confidence: float
|
||||||
|
confidence_label: str
|
||||||
|
|
||||||
|
|
||||||
|
class CapabilitySummaryResponse(BaseModel):
|
||||||
|
id: int
|
||||||
|
repository_id: int
|
||||||
|
repository_name: str
|
||||||
|
ability_id: int
|
||||||
|
ability_name: str
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
confidence: float
|
||||||
|
confidence_label: str
|
||||||
|
|
||||||
|
|
||||||
API_DESCRIPTION = (
|
API_DESCRIPTION = (
|
||||||
"Register repositories, analyze their observable implementation facts, "
|
"Register repositories, analyze their observable implementation facts, "
|
||||||
"curate reviewable ability graphs, and search approved repository abilities."
|
"curate reviewable ability graphs, and search approved repository abilities."
|
||||||
@@ -356,7 +571,12 @@ def health() -> dict[str, str]:
|
|||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/repos", status_code=201, tags=["repositories"])
|
@app.post(
|
||||||
|
"/repos",
|
||||||
|
status_code=201,
|
||||||
|
tags=["repositories"],
|
||||||
|
response_model=RepositoryResponse,
|
||||||
|
)
|
||||||
def create_repository(
|
def create_repository(
|
||||||
payload: RepositoryCreate,
|
payload: RepositoryCreate,
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
@@ -368,14 +588,18 @@ def create_repository(
|
|||||||
return asdict(repository)
|
return asdict(repository)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos", tags=["repositories"])
|
@app.get("/repos", tags=["repositories"], response_model=list[RepositoryResponse])
|
||||||
def list_repositories(
|
def list_repositories(
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
) -> list[dict[str, object]]:
|
) -> list[dict[str, object]]:
|
||||||
return [asdict(repository) for repository in service.list_repositories()]
|
return [asdict(repository) for repository in service.list_repositories()]
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}", tags=["repositories"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}",
|
||||||
|
tags=["repositories"],
|
||||||
|
response_model=RepositoryResponse,
|
||||||
|
)
|
||||||
def get_repository(
|
def get_repository(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
@@ -386,7 +610,11 @@ def get_repository(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.patch("/repos/{repository_id}", tags=["repositories"])
|
@app.patch(
|
||||||
|
"/repos/{repository_id}",
|
||||||
|
tags=["repositories"],
|
||||||
|
response_model=RepositoryResponse,
|
||||||
|
)
|
||||||
def update_repository(
|
def update_repository(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
payload: RepositoryUpdate,
|
payload: RepositoryUpdate,
|
||||||
@@ -414,7 +642,12 @@ def delete_repository(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.post("/repos/{repository_id}/analysis-runs", status_code=201, tags=["analysis"])
|
@app.post(
|
||||||
|
"/repos/{repository_id}/analysis-runs",
|
||||||
|
status_code=201,
|
||||||
|
tags=["analysis"],
|
||||||
|
response_model=ScanSummaryResponse,
|
||||||
|
)
|
||||||
def create_analysis_run(
|
def create_analysis_run(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
payload: AnalysisRunCreate,
|
payload: AnalysisRunCreate,
|
||||||
@@ -430,7 +663,11 @@ def create_analysis_run(
|
|||||||
return asdict(summary)
|
return asdict(summary)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}/analysis-runs", tags=["analysis"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}/analysis-runs",
|
||||||
|
tags=["analysis"],
|
||||||
|
response_model=list[AnalysisRunResponse],
|
||||||
|
)
|
||||||
def list_analysis_runs(
|
def list_analysis_runs(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
@@ -441,7 +678,11 @@ def list_analysis_runs(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}/analysis-runs/{analysis_run_id}", tags=["analysis"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}",
|
||||||
|
tags=["analysis"],
|
||||||
|
response_model=AnalysisRunResponse,
|
||||||
|
)
|
||||||
def get_analysis_run(
|
def get_analysis_run(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
analysis_run_id: int,
|
analysis_run_id: int,
|
||||||
@@ -453,7 +694,11 @@ def get_analysis_run(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}/review-decisions", tags=["review"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}/review-decisions",
|
||||||
|
tags=["review"],
|
||||||
|
response_model=list[ReviewDecisionResponse],
|
||||||
|
)
|
||||||
def list_repository_review_decisions(
|
def list_repository_review_decisions(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
@@ -470,6 +715,7 @@ def list_repository_review_decisions(
|
|||||||
@app.get(
|
@app.get(
|
||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/review-decisions",
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/review-decisions",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=list[ReviewDecisionResponse],
|
||||||
)
|
)
|
||||||
def list_analysis_run_review_decisions(
|
def list_analysis_run_review_decisions(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -488,7 +734,11 @@ def list_analysis_run_review_decisions(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}/observed-facts", tags=["analysis"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}/observed-facts",
|
||||||
|
tags=["analysis"],
|
||||||
|
response_model=list[ObservedFactResponse],
|
||||||
|
)
|
||||||
def list_observed_facts(
|
def list_observed_facts(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
analysis_run_id: int | None = None,
|
analysis_run_id: int | None = None,
|
||||||
@@ -503,7 +753,11 @@ def list_observed_facts(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}/content-chunks", tags=["analysis"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}/content-chunks",
|
||||||
|
tags=["analysis"],
|
||||||
|
response_model=list[ContentChunkResponse],
|
||||||
|
)
|
||||||
def list_content_chunks(
|
def list_content_chunks(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
analysis_run_id: int | None = None,
|
analysis_run_id: int | None = None,
|
||||||
@@ -521,6 +775,7 @@ def list_content_chunks(
|
|||||||
@app.get(
|
@app.get(
|
||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/content-chunks",
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/content-chunks",
|
||||||
tags=["analysis"],
|
tags=["analysis"],
|
||||||
|
response_model=list[ContentChunkResponse],
|
||||||
)
|
)
|
||||||
def list_analysis_run_content_chunks(
|
def list_analysis_run_content_chunks(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -539,6 +794,7 @@ def list_analysis_run_content_chunks(
|
|||||||
@app.get(
|
@app.get(
|
||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph",
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def get_candidate_graph(
|
def get_candidate_graph(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -554,6 +810,7 @@ def get_candidate_graph(
|
|||||||
@app.post(
|
@app.post(
|
||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph/approve",
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/candidate-graph/approve",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
)
|
)
|
||||||
def approve_candidate_graph(
|
def approve_candidate_graph(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -577,6 +834,7 @@ def approve_candidate_graph(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-abilities/{candidate_ability_id}/reject",
|
"/candidate-abilities/{candidate_ability_id}/reject",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def reject_candidate_ability(
|
def reject_candidate_ability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -602,6 +860,7 @@ def reject_candidate_ability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-capabilities/{candidate_capability_id}/reject",
|
"/candidate-capabilities/{candidate_capability_id}/reject",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def reject_candidate_capability(
|
def reject_candidate_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -627,6 +886,7 @@ def reject_candidate_capability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-features/{candidate_feature_id}/reject",
|
"/candidate-features/{candidate_feature_id}/reject",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def reject_candidate_feature(
|
def reject_candidate_feature(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -652,6 +912,7 @@ def reject_candidate_feature(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-evidence/{candidate_evidence_id}/reject",
|
"/candidate-evidence/{candidate_evidence_id}/reject",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def reject_candidate_evidence(
|
def reject_candidate_evidence(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -677,6 +938,7 @@ def reject_candidate_evidence(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-abilities/{candidate_ability_id}",
|
"/candidate-abilities/{candidate_ability_id}",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def edit_candidate_ability(
|
def edit_candidate_ability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -702,6 +964,7 @@ def edit_candidate_ability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-capabilities/{candidate_capability_id}",
|
"/candidate-capabilities/{candidate_capability_id}",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def edit_candidate_capability(
|
def edit_candidate_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -727,6 +990,7 @@ def edit_candidate_capability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-capabilities/{candidate_capability_id}/relink",
|
"/candidate-capabilities/{candidate_capability_id}/relink",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def relink_candidate_capability(
|
def relink_candidate_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -752,6 +1016,7 @@ def relink_candidate_capability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-features/{candidate_feature_id}/relink",
|
"/candidate-features/{candidate_feature_id}/relink",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def relink_candidate_feature(
|
def relink_candidate_feature(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -777,6 +1042,7 @@ def relink_candidate_feature(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-evidence/{candidate_evidence_id}/relink",
|
"/candidate-evidence/{candidate_evidence_id}/relink",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def relink_candidate_evidence(
|
def relink_candidate_evidence(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -802,6 +1068,7 @@ def relink_candidate_evidence(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-abilities/{source_ability_id}/merge",
|
"/candidate-abilities/{source_ability_id}/merge",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def merge_candidate_ability(
|
def merge_candidate_ability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -827,6 +1094,7 @@ def merge_candidate_ability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-capabilities/{source_capability_id}/merge",
|
"/candidate-capabilities/{source_capability_id}/merge",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def merge_candidate_capability(
|
def merge_candidate_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -852,6 +1120,7 @@ def merge_candidate_capability(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-features/{source_feature_id}/merge",
|
"/candidate-features/{source_feature_id}/merge",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def merge_candidate_feature(
|
def merge_candidate_feature(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -877,6 +1146,7 @@ def merge_candidate_feature(
|
|||||||
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
|
||||||
"/candidate-evidence/{source_evidence_id}/merge",
|
"/candidate-evidence/{source_evidence_id}/merge",
|
||||||
tags=["review"],
|
tags=["review"],
|
||||||
|
response_model=CandidateGraphResponse,
|
||||||
)
|
)
|
||||||
def merge_candidate_evidence(
|
def merge_candidate_evidence(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
@@ -898,7 +1168,12 @@ def merge_candidate_evidence(
|
|||||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.post("/repos/{repository_id}/abilities", status_code=201, tags=["registry"])
|
@app.post(
|
||||||
|
"/repos/{repository_id}/abilities",
|
||||||
|
status_code=201,
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=IdResponse,
|
||||||
|
)
|
||||||
def create_ability(
|
def create_ability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
payload: AbilityCreate,
|
payload: AbilityCreate,
|
||||||
@@ -911,7 +1186,11 @@ def create_ability(
|
|||||||
return {"id": ability_id}
|
return {"id": ability_id}
|
||||||
|
|
||||||
|
|
||||||
@app.patch("/repos/{repository_id}/abilities/{ability_id}", tags=["registry"])
|
@app.patch(
|
||||||
|
"/repos/{repository_id}/abilities/{ability_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def update_ability(
|
def update_ability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
ability_id: int,
|
ability_id: int,
|
||||||
@@ -930,7 +1209,11 @@ def update_ability(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/repos/{repository_id}/abilities/{ability_id}", tags=["registry"])
|
@app.delete(
|
||||||
|
"/repos/{repository_id}/abilities/{ability_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def delete_ability(
|
def delete_ability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
ability_id: int,
|
ability_id: int,
|
||||||
@@ -942,7 +1225,12 @@ def delete_ability(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.post("/repos/{repository_id}/capabilities", status_code=201, tags=["registry"])
|
@app.post(
|
||||||
|
"/repos/{repository_id}/capabilities",
|
||||||
|
status_code=201,
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=IdResponse,
|
||||||
|
)
|
||||||
def create_capability(
|
def create_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
payload: CapabilityCreate,
|
payload: CapabilityCreate,
|
||||||
@@ -955,7 +1243,11 @@ def create_capability(
|
|||||||
return {"id": capability_id}
|
return {"id": capability_id}
|
||||||
|
|
||||||
|
|
||||||
@app.patch("/repos/{repository_id}/capabilities/{capability_id}", tags=["registry"])
|
@app.patch(
|
||||||
|
"/repos/{repository_id}/capabilities/{capability_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def update_capability(
|
def update_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
capability_id: int,
|
capability_id: int,
|
||||||
@@ -974,7 +1266,11 @@ def update_capability(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/repos/{repository_id}/capabilities/{capability_id}", tags=["registry"])
|
@app.delete(
|
||||||
|
"/repos/{repository_id}/capabilities/{capability_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def delete_capability(
|
def delete_capability(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
capability_id: int,
|
capability_id: int,
|
||||||
@@ -986,7 +1282,12 @@ def delete_capability(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.post("/repos/{repository_id}/features", status_code=201, tags=["registry"])
|
@app.post(
|
||||||
|
"/repos/{repository_id}/features",
|
||||||
|
status_code=201,
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=IdResponse,
|
||||||
|
)
|
||||||
def create_feature(
|
def create_feature(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
payload: FeatureCreate,
|
payload: FeatureCreate,
|
||||||
@@ -999,7 +1300,11 @@ def create_feature(
|
|||||||
return {"id": feature_id}
|
return {"id": feature_id}
|
||||||
|
|
||||||
|
|
||||||
@app.patch("/repos/{repository_id}/features/{feature_id}", tags=["registry"])
|
@app.patch(
|
||||||
|
"/repos/{repository_id}/features/{feature_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def update_feature(
|
def update_feature(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
feature_id: int,
|
feature_id: int,
|
||||||
@@ -1018,7 +1323,11 @@ def update_feature(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/repos/{repository_id}/features/{feature_id}", tags=["registry"])
|
@app.delete(
|
||||||
|
"/repos/{repository_id}/features/{feature_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def delete_feature(
|
def delete_feature(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
feature_id: int,
|
feature_id: int,
|
||||||
@@ -1030,7 +1339,12 @@ def delete_feature(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.post("/repos/{repository_id}/evidence", status_code=201, tags=["registry"])
|
@app.post(
|
||||||
|
"/repos/{repository_id}/evidence",
|
||||||
|
status_code=201,
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=IdResponse,
|
||||||
|
)
|
||||||
def create_evidence(
|
def create_evidence(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
payload: EvidenceCreate,
|
payload: EvidenceCreate,
|
||||||
@@ -1043,7 +1357,11 @@ def create_evidence(
|
|||||||
return {"id": evidence_id}
|
return {"id": evidence_id}
|
||||||
|
|
||||||
|
|
||||||
@app.patch("/repos/{repository_id}/evidence/{evidence_id}", tags=["registry"])
|
@app.patch(
|
||||||
|
"/repos/{repository_id}/evidence/{evidence_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def update_evidence(
|
def update_evidence(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
evidence_id: int,
|
evidence_id: int,
|
||||||
@@ -1062,7 +1380,11 @@ def update_evidence(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/repos/{repository_id}/evidence/{evidence_id}", tags=["registry"])
|
@app.delete(
|
||||||
|
"/repos/{repository_id}/evidence/{evidence_id}",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def delete_evidence(
|
def delete_evidence(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
evidence_id: int,
|
evidence_id: int,
|
||||||
@@ -1074,7 +1396,11 @@ def delete_evidence(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.get("/repos/{repository_id}/ability-map", tags=["registry"])
|
@app.get(
|
||||||
|
"/repos/{repository_id}/ability-map",
|
||||||
|
tags=["registry"],
|
||||||
|
response_model=RepositoryAbilityMapResponse,
|
||||||
|
)
|
||||||
def get_ability_map(
|
def get_ability_map(
|
||||||
repository_id: int,
|
repository_id: int,
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
@@ -1085,7 +1411,7 @@ def get_ability_map(
|
|||||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
@app.get("/search", tags=["search"])
|
@app.get("/search", tags=["search"], response_model=list[SearchResultResponse])
|
||||||
def search(
|
def search(
|
||||||
q: str = Query(
|
q: str = Query(
|
||||||
...,
|
...,
|
||||||
@@ -1127,14 +1453,18 @@ def search(
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@app.get("/abilities", tags=["search"])
|
@app.get("/abilities", tags=["search"], response_model=list[AbilitySummaryResponse])
|
||||||
def list_abilities(
|
def list_abilities(
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
) -> list[dict[str, object]]:
|
) -> list[dict[str, object]]:
|
||||||
return [asdict(ability) for ability in service.list_abilities()]
|
return [asdict(ability) for ability in service.list_abilities()]
|
||||||
|
|
||||||
|
|
||||||
@app.get("/capabilities", tags=["search"])
|
@app.get(
|
||||||
|
"/capabilities",
|
||||||
|
tags=["search"],
|
||||||
|
response_model=list[CapabilitySummaryResponse],
|
||||||
|
)
|
||||||
def list_capabilities(
|
def list_capabilities(
|
||||||
service: RegistryService = Depends(get_service),
|
service: RegistryService = Depends(get_service),
|
||||||
) -> list[dict[str, object]]:
|
) -> list[dict[str, object]]:
|
||||||
|
|||||||
@@ -20,10 +20,18 @@ def test_openapi_groups_agent_facing_endpoints():
|
|||||||
}
|
}
|
||||||
search_operation = schema["paths"]["/search"]["get"]
|
search_operation = schema["paths"]["/search"]["get"]
|
||||||
assert search_operation["tags"] == ["search"]
|
assert search_operation["tags"] == ["search"]
|
||||||
|
search_response = search_operation["responses"]["200"]["content"][
|
||||||
|
"application/json"
|
||||||
|
]["schema"]
|
||||||
|
assert search_response["items"]["$ref"].endswith("/SearchResultResponse")
|
||||||
assert {
|
assert {
|
||||||
parameter["name"]: parameter["description"]
|
parameter["name"]: parameter["description"]
|
||||||
for parameter in search_operation["parameters"]
|
for parameter in search_operation["parameters"]
|
||||||
}["q"].startswith("Natural-language")
|
}["q"].startswith("Natural-language")
|
||||||
|
ability_map_response = schema["paths"]["/repos/{repository_id}/ability-map"][
|
||||||
|
"get"
|
||||||
|
]["responses"]["200"]["content"]["application/json"]["schema"]
|
||||||
|
assert ability_map_response["$ref"].endswith("/RepositoryAbilityMapResponse")
|
||||||
|
|
||||||
|
|
||||||
def test_api_manual_registry_loop(tmp_path):
|
def test_api_manual_registry_loop(tmp_path):
|
||||||
|
|||||||
Reference in New Issue
Block a user