-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
223 lines (178 loc) · 6.87 KB
/
server.py
File metadata and controls
223 lines (178 loc) · 6.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
"""CodeFlow Server with GitHub App Integration and Dashboard.
FastAPI server that provides the CodeFlow Engine API and dashboard UI.
"""
import logging
import os
from pathlib import Path
from fastapi import FastAPI, Query
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, Response
from codeflow_engine.config.settings import CodeFlowSettings
from codeflow_engine.health.health_checker import HealthChecker
from codeflow_engine.utils.logging import get_logger, setup_logging
# Set up logging (will be configured properly in create_app)
logger = get_logger(__name__)
# Import dashboard router and version
try:
from codeflow_engine.dashboard.router import router as dashboard_router
from codeflow_engine.dashboard.router import __version__ as DASHBOARD_VERSION
DASHBOARD_AVAILABLE = True
logger.info("Dashboard module loaded successfully")
except ImportError as e:
DASHBOARD_AVAILABLE = False
DASHBOARD_VERSION = "1.0.1"
logger.warning(f"Dashboard module not available: {e}")
# Import GitHub App routers
try:
from codeflow_engine.integrations.github_app import (
install_router,
callback_router,
webhook_router,
setup_router,
)
GITHUB_APP_AVAILABLE = True
logger.info("GitHub App integration loaded successfully")
except ImportError as e:
GITHUB_APP_AVAILABLE = False
logger.warning(f"GitHub App integration not available: {e}")
# Use dashboard version as server version for consistency
__version__ = DASHBOARD_VERSION
# Shared health checker instance
_health_checker: HealthChecker | None = None
def get_health_checker() -> HealthChecker:
"""Get or create the shared HealthChecker instance."""
global _health_checker
if _health_checker is None:
_health_checker = HealthChecker()
return _health_checker
async def root_fallback():
"""Root endpoint fallback when dashboard is not available.
Returns API information and available endpoints.
"""
return {
"message": "CodeFlow Engine API",
"version": __version__,
"dashboard": "not available (import failed)",
"api_docs": "/docs",
"health": "/health",
"github_app": "available" if GITHUB_APP_AVAILABLE else "not configured",
}
# Use dashboard version as server version for consistency
__version__ = DASHBOARD_VERSION
# Shared health checker instance
_health_checker: HealthChecker | None = None
def get_health_checker() -> HealthChecker:
"""Get or create the shared HealthChecker instance."""
global _health_checker
if _health_checker is None:
_health_checker = HealthChecker()
return _health_checker
def create_app(settings: CodeFlowSettings | None = None) -> FastAPI:
"""Create FastAPI application with GitHub App integration.
Args:
settings: Optional CodeFlowSettings instance. If not provided, loads from environment.
Returns:
Configured FastAPI application
"""
# Load settings if not provided
if settings is None:
settings = CodeFlowSettings()
# Set up structured logging
setup_logging(settings)
logger.info("Structured logging configured", extra={"log_format": "json"})
app = FastAPI(
title="CodeFlow Engine",
description="AI-Powered GitHub PR Automation and Issue Management",
version=__version__,
)
# CORS middleware - restrict origins in production
cors_origins_env = os.getenv("CORS_ALLOWED_ORIGINS", "")
if cors_origins_env:
# Parse comma-separated list of allowed origins
cors_origins = [
origin.strip() for origin in cors_origins_env.split(",") if origin.strip()
]
allow_credentials = True # Safe with specific origins
else:
# Development fallback: allow all origins only when env var not set
# Note: credentials cannot be used with wildcard origin per CORS spec
cors_origins = ["*"]
allow_credentials = False
app.add_middleware(
CORSMiddleware,
allow_origins=cors_origins,
allow_credentials=allow_credentials,
allow_methods=["*"],
allow_headers=["*"],
)
# Include dashboard routes if available (must be first to handle "/" route)
if DASHBOARD_AVAILABLE:
app.include_router(dashboard_router)
else:
# Register fallback root route when dashboard is not available
app.get("/")(root_fallback)
# Include GitHub App routes if available
if GITHUB_APP_AVAILABLE:
app.include_router(install_router)
app.include_router(callback_router)
app.include_router(webhook_router)
app.include_router(setup_router)
# API info endpoint (when dashboard is not available or for API consumers)
@app.get("/api")
async def api_root():
"""API root endpoint."""
return {
"message": "CodeFlow Engine API",
"version": __version__,
"dashboard": "available" if DASHBOARD_AVAILABLE else "not configured",
"github_app": "available" if GITHUB_APP_AVAILABLE else "not configured",
}
@app.get("/favicon.ico")
async def favicon():
"""Serve favicon - returns empty response to prevent slow 404 lookups."""
# Check for favicon in common locations
repo_root = Path(__file__).resolve().parents[2].parent
favicon_paths = [
repo_root / "website" / "app" / "favicon.ico",
Path(__file__).parent / "static" / "favicon.ico",
]
for favicon_path in favicon_paths:
if favicon_path.exists():
return FileResponse(
favicon_path,
media_type="image/x-icon",
headers={"Cache-Control": "public, max-age=86400"},
)
# Return empty response with no-content status
return Response(status_code=204)
# Get shared health checker
health_checker = get_health_checker()
@app.get("/health")
async def health(
detailed: bool = Query(False, description="Return detailed health info")
):
"""
Health check endpoint.
Args:
detailed: If True, perform comprehensive health check with all components.
If False (default), perform quick check for low latency.
Returns:
Health status response with status and optional component details.
"""
if detailed:
result = await health_checker.check_all(use_cache=True)
else:
result = await health_checker.check_quick()
# Add version info for consistency
result["version"] = __version__
return result
return app
def main():
"""Run the server."""
import uvicorn
app = create_app()
host = os.getenv("HOST", "0.0.0.0")
port = int(os.getenv("PORT", "8080"))
uvicorn.run(app, host=host, port=port)
if __name__ == "__main__":
main()