From 88b93e7ce6a33c7ca19943d1f2eebfd89b23f1bc Mon Sep 17 00:00:00 2001 From: Alejandro Ponce Date: Fri, 17 Jan 2025 13:26:12 +0200 Subject: [PATCH 1/3] Add `/api/v1` routes to openapi spec It was missing an import --- tests/pipeline/workspace/test_workspace.py | 8 ++------ tests/test_server.py | 4 +++- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/pipeline/workspace/test_workspace.py b/tests/pipeline/workspace/test_workspace.py index 039b69fe..d4b2721a 100644 --- a/tests/pipeline/workspace/test_workspace.py +++ b/tests/pipeline/workspace/test_workspace.py @@ -77,9 +77,7 @@ async def test_add_workspaces(args, existing_workspaces, expected_message): workspace_commands._db_reader = mock_db_reader # We'll also patch DbRecorder to ensure no real DB operations happen - with patch( - "codegate.pipeline.cli.commands.WorkspaceCrud", autospec=True - ) as mock_recorder_cls: + with patch("codegate.pipeline.cli.commands.WorkspaceCrud", autospec=True) as mock_recorder_cls: mock_recorder = mock_recorder_cls.return_value workspace_commands.workspace_crud = mock_recorder mock_recorder.add_workspace = AsyncMock() @@ -115,9 +113,7 @@ async def test_parse_execute_cmd( """ workspace_commands = Workspace() - with patch.object( - workspace_commands, "run", return_value=mocked_execute_response - ) as mock_run: + with patch.object(workspace_commands, "run", return_value=mocked_execute_response) as mock_run: result = await workspace_commands.exec(user_message) assert result == mocked_execute_response diff --git a/tests/test_server.py b/tests/test_server.py index ad3b3541..6fc923f7 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -81,6 +81,7 @@ def test_health_check(test_client: TestClient) -> None: assert response.status_code == 200 assert response.json() == {"status": "healthy"} + @patch("codegate.dashboard.dashboard.fetch_latest_version", return_value="foo") def test_version_endpoint(mock_fetch_latest_version, test_client: TestClient) -> None: """Test the version endpoint.""" @@ -89,11 +90,12 @@ def test_version_endpoint(mock_fetch_latest_version, test_client: TestClient) -> response_data = response.json() - assert response_data["current_version"] == __version__.lstrip('v') + assert response_data["current_version"] == __version__.lstrip("v") assert response_data["latest_version"] == "foo" assert isinstance(response_data["is_latest"], bool) assert response_data["is_latest"] is False + @patch("codegate.pipeline.secrets.manager.SecretsManager") @patch("codegate.server.ProviderRegistry") def test_provider_registration(mock_registry, mock_secrets_mgr, mock_pipeline_factory) -> None: From 8f3b030de43ed72eee3575adcb4a106b4a29b186 Mon Sep 17 00:00:00 2001 From: Alejandro Ponce Date: Fri, 17 Jan 2025 13:28:08 +0200 Subject: [PATCH 2/3] missing one file --- src/codegate/dashboard/dashboard.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/codegate/dashboard/dashboard.py b/src/codegate/dashboard/dashboard.py index 89e15314..070598bd 100644 --- a/src/codegate/dashboard/dashboard.py +++ b/src/codegate/dashboard/dashboard.py @@ -6,8 +6,9 @@ import structlog from fastapi import APIRouter, Depends, FastAPI from fastapi.responses import StreamingResponse -from codegate import __version__ +from codegate import __version__ +from codegate.api.v1 import v1 from codegate.dashboard.post_processing import ( parse_get_alert_conversation, parse_messages_in_conversations, @@ -20,23 +21,23 @@ dashboard_router = APIRouter(tags=["Dashboard"]) db_reader = None + def get_db_reader(): global db_reader if db_reader is None: db_reader = DbReader() return db_reader + def fetch_latest_version() -> str: url = "https://api.github.com/repos/stacklok/codegate/releases/latest" - headers = { - "Accept": "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28" - } + headers = {"Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"} response = requests.get(url, headers=headers, timeout=5) response.raise_for_status() data = response.json() return data.get("tag_name", "unknown") + @dashboard_router.get("/dashboard/messages") def get_messages(db_reader: DbReader = Depends(get_db_reader)) -> List[Conversation]: """ @@ -72,17 +73,18 @@ async def stream_sse(): """ return StreamingResponse(generate_sse_events(), media_type="text/event-stream") + @dashboard_router.get("/dashboard/version") def version_check(): try: latest_version = fetch_latest_version() # normalize the versions as github will return them with a 'v' prefix - current_version = __version__.lstrip('v') - latest_version_stripped = latest_version.lstrip('v') + current_version = __version__.lstrip("v") + latest_version_stripped = latest_version.lstrip("v") is_latest: bool = latest_version_stripped == current_version - + return { "current_version": current_version, "latest_version": latest_version_stripped, @@ -95,7 +97,7 @@ def version_check(): "current_version": __version__, "latest_version": "unknown", "is_latest": None, - "error": "An error occurred while fetching the latest version" + "error": "An error occurred while fetching the latest version", } except Exception as e: logger.error(f"Unexpected error: {str(e)}") @@ -103,7 +105,7 @@ def version_check(): "current_version": __version__, "latest_version": "unknown", "is_latest": None, - "error": "An unexpected error occurred" + "error": "An unexpected error occurred", } @@ -113,6 +115,7 @@ def generate_openapi(): # Include your defined router app.include_router(dashboard_router) + app.include_router(v1, prefix="/api/v1", tags=["CodeGate API"]) # Generate OpenAPI JSON openapi_schema = app.openapi() From 9b141e49175306cc871a7cbe5c8735e27d551127 Mon Sep 17 00:00:00 2001 From: Alejandro Ponce Date: Fri, 17 Jan 2025 15:20:06 +0200 Subject: [PATCH 3/3] moved generation of openapi spec to server.py --- pyproject.toml | 2 +- src/codegate/dashboard/dashboard.py | 20 +------------------- src/codegate/server.py | 13 +++++++++++++ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f90a6488..c38ca31b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] codegate = "codegate.cli:main" -generate-openapi = "src.codegate.dashboard.dashboard:generate_openapi" +generate-openapi = "src.codegate.server:generate_openapi" [tool.black] line-length = 100 diff --git a/src/codegate/dashboard/dashboard.py b/src/codegate/dashboard/dashboard.py index 070598bd..bf4a6037 100644 --- a/src/codegate/dashboard/dashboard.py +++ b/src/codegate/dashboard/dashboard.py @@ -1,14 +1,12 @@ import asyncio -import json from typing import AsyncGenerator, List, Optional import requests import structlog -from fastapi import APIRouter, Depends, FastAPI +from fastapi import APIRouter, Depends from fastapi.responses import StreamingResponse from codegate import __version__ -from codegate.api.v1 import v1 from codegate.dashboard.post_processing import ( parse_get_alert_conversation, parse_messages_in_conversations, @@ -107,19 +105,3 @@ def version_check(): "is_latest": None, "error": "An unexpected error occurred", } - - -def generate_openapi(): - # Create a temporary FastAPI app instance - app = FastAPI() - - # Include your defined router - app.include_router(dashboard_router) - app.include_router(v1, prefix="/api/v1", tags=["CodeGate API"]) - - # Generate OpenAPI JSON - openapi_schema = app.openapi() - - # Convert the schema to JSON string for easier handling or storage - openapi_json = json.dumps(openapi_schema, indent=2) - print(openapi_json) diff --git a/src/codegate/server.py b/src/codegate/server.py index d1da668e..dcd0809e 100644 --- a/src/codegate/server.py +++ b/src/codegate/server.py @@ -1,3 +1,4 @@ +import json import traceback import structlog @@ -102,3 +103,15 @@ async def health_check(): app.include_router(v1, prefix="/api/v1", tags=["CodeGate API"]) return app + + +def generate_openapi(): + # Create a temporary FastAPI app instance + app = init_app(None) + + # Generate OpenAPI JSON + openapi_schema = app.openapi() + + # Convert the schema to JSON string for easier handling or storage + openapi_json = json.dumps(openapi_schema, indent=2) + print(openapi_json)