Skip to content

feat: version endpoint #612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jan 17, 2025
Merged
47 changes: 46 additions & 1 deletion src/codegate/dashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
import json
from typing import AsyncGenerator, List, Optional

import requests
import structlog
from fastapi import APIRouter, Depends, FastAPI
from fastapi.responses import StreamingResponse
from codegate import __version__

from codegate.dashboard.post_processing import (
parse_get_alert_conversation,
Expand All @@ -18,13 +20,22 @@
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"
}
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]:
Expand Down Expand Up @@ -61,6 +72,40 @@ 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')

is_latest: bool = latest_version_stripped == current_version

return {
"current_version": current_version,
"latest_version": latest_version_stripped,
"is_latest": is_latest,
"error": None,
}
except requests.RequestException as e:
logger.error(f"RequestException: {str(e)}")
return {
"current_version": __version__,
"latest_version": "unknown",
"is_latest": None,
"error": "An error occurred while fetching the latest version"
}
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
return {
"current_version": __version__,
"latest_version": "unknown",
"is_latest": None,
"error": "An unexpected error occurred"
}


def generate_openapi():
# Create a temporary FastAPI app instance
Expand Down
12 changes: 12 additions & 0 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ 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."""
response = test_client.get("/dashboard/version")
assert response.status_code == 200

response_data = response.json()

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")
Expand Down
Loading