11import traceback
2+ from typing import AsyncGenerator
23
34import structlog
4- from fastapi import APIRouter , FastAPI , Request
5+ from fastapi import APIRouter , Depends , FastAPI , HTTPException , Request
56from fastapi .middleware .cors import CORSMiddleware
67from fastapi .responses import JSONResponse
78from starlette .middleware .errors import ServerErrorMiddleware
9+ from httpx import AsyncClient , HTTPStatusError
810
911from codegate import __description__ , __version__
1012from codegate .dashboard .dashboard import dashboard_router
@@ -27,6 +29,23 @@ async def custom_error_handler(request, exc: Exception):
2729 logger .error (traceback .print_list (extracted_traceback [- 3 :]))
2830 return JSONResponse ({"error" : str (exc )}, status_code = 500 )
2931
32+ async def get_http_client () -> AsyncGenerator [AsyncClient , None ]:
33+ async with AsyncClient () as client :
34+ yield client
35+
36+ async def fetch_latest_version (client : AsyncClient ) -> str :
37+ url = "https://api.github.com/repos/stacklok/codegate/releases/latest"
38+ headers = {
39+ "Accept" : "application/vnd.github+json" ,
40+ "X-GitHub-Api-Version" : "2022-11-28"
41+ }
42+ try :
43+ response = await client .get (url , headers = headers )
44+ response .raise_for_status ()
45+ data = response .json ()
46+ return data .get ("tag_name" , "unknown" )
47+ except HTTPStatusError as e :
48+ raise HTTPException (status_code = e .response .status_code , detail = str (e ))
3049
3150def init_app (pipeline_factory : PipelineFactory ) -> FastAPI :
3251 """Create the FastAPI application."""
@@ -94,6 +113,26 @@ async def log_user_agent(request: Request, call_next):
94113 async def health_check ():
95114 return {"status" : "healthy" }
96115
116+ @system_router .get ("/version" )
117+ async def version_check (client : AsyncClient = Depends (get_http_client )):
118+ try :
119+ latest_version = await fetch_latest_version (client )
120+
121+ # normalize the versions as github will return them with a 'v' prefix
122+ current_version = __version__ .lstrip ('v' )
123+ latest_version_stripped = latest_version .lstrip ('v' )
124+
125+ is_latest : bool = latest_version_stripped == current_version
126+
127+ return {
128+ "current_version" : current_version ,
129+ "latest_version" : latest_version_stripped ,
130+ "is_latest" : is_latest ,
131+ }
132+ except HTTPException as e :
133+ return {"current_version" : __version__ , "latest_version" : "unknown" , "error" : e .detail }
134+
135+
97136 app .include_router (system_router )
98137 app .include_router (dashboard_router )
99138
0 commit comments