Skip to content

Commit e4b3ceb

Browse files
feat: version endpoint (#612)
* feat: version endpoint * chore: move version check into dashboard router, mock Github API call in tests * chore: revert unecessary changes to server.py * fix(versions endpoint): add logging, handle broader range of exceptions, don't return raw error detail to client * refactor(version endpoint): use requests instead of httpx + ThreadPoolExecutor * fix(version endpoint): add timeout to request to github API
1 parent 234727a commit e4b3ceb

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

src/codegate/dashboard/dashboard.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
import json
33
from typing import AsyncGenerator, List, Optional
44

5+
import requests
56
import structlog
67
from fastapi import APIRouter, Depends, FastAPI
78
from fastapi.responses import StreamingResponse
9+
from codegate import __version__
810

911
from codegate.dashboard.post_processing import (
1012
parse_get_alert_conversation,
@@ -18,13 +20,22 @@
1820
dashboard_router = APIRouter(tags=["Dashboard"])
1921
db_reader = None
2022

21-
2223
def get_db_reader():
2324
global db_reader
2425
if db_reader is None:
2526
db_reader = DbReader()
2627
return db_reader
2728

29+
def fetch_latest_version() -> str:
30+
url = "https://api.github.com/repos/stacklok/codegate/releases/latest"
31+
headers = {
32+
"Accept": "application/vnd.github+json",
33+
"X-GitHub-Api-Version": "2022-11-28"
34+
}
35+
response = requests.get(url, headers=headers, timeout=5)
36+
response.raise_for_status()
37+
data = response.json()
38+
return data.get("tag_name", "unknown")
2839

2940
@dashboard_router.get("/dashboard/messages")
3041
def get_messages(db_reader: DbReader = Depends(get_db_reader)) -> List[Conversation]:
@@ -61,6 +72,40 @@ async def stream_sse():
6172
"""
6273
return StreamingResponse(generate_sse_events(), media_type="text/event-stream")
6374

75+
@dashboard_router.get("/dashboard/version")
76+
def version_check():
77+
try:
78+
latest_version = fetch_latest_version()
79+
80+
# normalize the versions as github will return them with a 'v' prefix
81+
current_version = __version__.lstrip('v')
82+
latest_version_stripped = latest_version.lstrip('v')
83+
84+
is_latest: bool = latest_version_stripped == current_version
85+
86+
return {
87+
"current_version": current_version,
88+
"latest_version": latest_version_stripped,
89+
"is_latest": is_latest,
90+
"error": None,
91+
}
92+
except requests.RequestException as e:
93+
logger.error(f"RequestException: {str(e)}")
94+
return {
95+
"current_version": __version__,
96+
"latest_version": "unknown",
97+
"is_latest": None,
98+
"error": "An error occurred while fetching the latest version"
99+
}
100+
except Exception as e:
101+
logger.error(f"Unexpected error: {str(e)}")
102+
return {
103+
"current_version": __version__,
104+
"latest_version": "unknown",
105+
"is_latest": None,
106+
"error": "An unexpected error occurred"
107+
}
108+
64109

65110
def generate_openapi():
66111
# Create a temporary FastAPI app instance

tests/test_server.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ def test_health_check(test_client: TestClient) -> None:
8181
assert response.status_code == 200
8282
assert response.json() == {"status": "healthy"}
8383

84+
@patch("codegate.dashboard.dashboard.fetch_latest_version", return_value="foo")
85+
def test_version_endpoint(mock_fetch_latest_version, test_client: TestClient) -> None:
86+
"""Test the version endpoint."""
87+
response = test_client.get("/dashboard/version")
88+
assert response.status_code == 200
89+
90+
response_data = response.json()
91+
92+
assert response_data["current_version"] == __version__.lstrip('v')
93+
assert response_data["latest_version"] == "foo"
94+
assert isinstance(response_data["is_latest"], bool)
95+
assert response_data["is_latest"] is False
8496

8597
@patch("codegate.pipeline.secrets.manager.SecretsManager")
8698
@patch("codegate.server.ProviderRegistry")

0 commit comments

Comments
 (0)