88)
99from services .input_validator import InputValidator
1010from middleware .auth import require_auth , AuthContext
11- from services .observability import logger , metrics
11+ from services .observability import logger , metrics , capture_exception
1212
1313router = APIRouter (prefix = "/repos" , tags = ["Analysis" ])
1414
@@ -26,21 +26,23 @@ async def get_dependency_graph(
2626 """Get dependency graph for repository."""
2727 try :
2828 repo = get_repo_or_404 (repo_id , auth .user_id )
29-
30- # Try cache first
29+
3130 cached_graph = dependency_analyzer .load_from_cache (repo_id )
3231 if cached_graph :
3332 logger .debug ("Using cached dependency graph" , repo_id = repo_id )
3433 return {** cached_graph , "cached" : True }
35-
36- # Build fresh
34+
3735 logger .info ("Building fresh dependency graph" , repo_id = repo_id )
3836 graph_data = dependency_analyzer .build_dependency_graph (repo ["local_path" ])
3937 dependency_analyzer .save_to_cache (repo_id , graph_data )
40-
38+
4139 return {** graph_data , "cached" : False }
40+ except HTTPException :
41+ raise
4242 except Exception as e :
43- raise HTTPException (status_code = 500 , detail = str (e ))
43+ logger .error ("Dependency graph failed" , repo_id = repo_id , error = str (e ))
44+ capture_exception (e , operation = "dependency_graph" , repo_id = repo_id )
45+ raise HTTPException (status_code = 500 , detail = "Failed to build dependency graph" )
4446
4547
4648@router .post ("/{repo_id}/impact" )
@@ -52,30 +54,32 @@ async def analyze_impact(
5254 """Analyze impact of changing a file."""
5355 try :
5456 repo = get_repo_or_404 (repo_id , auth .user_id )
55-
56- # Validate file path
57+
5758 valid_path , path_error = InputValidator .validate_file_path (
5859 request .file_path , repo ["local_path" ]
5960 )
6061 if not valid_path :
6162 raise HTTPException (status_code = 400 , detail = f"Invalid file path: { path_error } " )
62-
63- # Get or build graph
63+
6464 graph_data = dependency_analyzer .load_from_cache (repo_id )
6565 if not graph_data :
6666 logger .info ("Building dependency graph for impact analysis" , repo_id = repo_id )
6767 graph_data = dependency_analyzer .build_dependency_graph (repo ["local_path" ])
6868 dependency_analyzer .save_to_cache (repo_id , graph_data )
69-
69+
7070 impact = dependency_analyzer .get_file_impact (
7171 repo ["local_path" ],
7272 request .file_path ,
7373 graph_data
7474 )
75-
75+
7676 return impact
77+ except HTTPException :
78+ raise
7779 except Exception as e :
78- raise HTTPException (status_code = 500 , detail = str (e ))
80+ logger .error ("Impact analysis failed" , repo_id = repo_id , file_path = request .file_path , error = str (e ))
81+ capture_exception (e , operation = "impact_analysis" , repo_id = repo_id )
82+ raise HTTPException (status_code = 500 , detail = "Failed to analyze impact" )
7983
8084
8185@router .get ("/{repo_id}/insights" )
@@ -86,14 +90,13 @@ async def get_repository_insights(
8690 """Get comprehensive insights about repository."""
8791 try :
8892 repo = get_repo_or_404 (repo_id , auth .user_id )
89-
90- # Get or build graph
93+
9194 graph_data = dependency_analyzer .load_from_cache (repo_id )
9295 if not graph_data :
9396 logger .info ("Building dependency graph for insights" , repo_id = repo_id )
9497 graph_data = dependency_analyzer .build_dependency_graph (repo ["local_path" ])
9598 dependency_analyzer .save_to_cache (repo_id , graph_data )
96-
99+
97100 return {
98101 "repo_id" : repo_id ,
99102 "name" : repo ["name" ],
@@ -106,8 +109,12 @@ async def get_repository_insights(
106109 "functions_indexed" : repo ["file_count" ],
107110 "cached" : bool (graph_data )
108111 }
112+ except HTTPException :
113+ raise
109114 except Exception as e :
110- raise HTTPException (status_code = 500 , detail = str (e ))
115+ logger .error ("Repository insights failed" , repo_id = repo_id , error = str (e ))
116+ capture_exception (e , operation = "insights" , repo_id = repo_id )
117+ raise HTTPException (status_code = 500 , detail = "Failed to get repository insights" )
111118
112119
113120@router .get ("/{repo_id}/style-analysis" )
@@ -118,22 +125,23 @@ async def get_style_analysis(
118125 """Analyze code style and team patterns."""
119126 try :
120127 repo = get_repo_or_404 (repo_id , auth .user_id )
121-
122- # Try cache first
128+
123129 cached_style = style_analyzer .load_from_cache (repo_id )
124130 if cached_style :
125131 logger .debug ("Using cached code style" , repo_id = repo_id )
126132 return {** cached_style , "cached" : True }
127-
128- # Analyze fresh
133+
129134 logger .info ("Analyzing code style" , repo_id = repo_id )
130135 style_data = style_analyzer .analyze_repository_style (repo ["local_path" ])
131136 style_analyzer .save_to_cache (repo_id , style_data )
132-
137+
133138 return {** style_data , "cached" : False }
139+ except HTTPException :
140+ raise
134141 except Exception as e :
135- raise HTTPException (status_code = 500 , detail = str (e ))
136-
142+ logger .error ("Style analysis failed" , repo_id = repo_id , error = str (e ))
143+ capture_exception (e , operation = "style_analysis" , repo_id = repo_id )
144+ raise HTTPException (status_code = 500 , detail = "Failed to analyze code style" )
137145
138146
139147@router .get ("/{repo_id}/dna" )
@@ -144,39 +152,40 @@ async def get_codebase_dna(
144152):
145153 """
146154 Extract codebase DNA - architectural patterns, conventions, and constraints.
147-
155+
148156 This endpoint analyzes your codebase and returns a DNA profile that helps
149157 AI assistants understand how to write code consistent with your patterns.
150-
158+
151159 Args:
152160 repo_id: Repository identifier
153161 format: Output format - 'json' or 'markdown' (default: json)
154-
162+
155163 Returns:
156164 DNA profile with auth patterns, service patterns, database patterns, etc.
157165 """
158166 try :
159167 repo = get_repo_or_404 (repo_id , auth .user_id )
160-
161- # Try cache first
168+
162169 cached_dna = dna_extractor .load_from_cache (repo_id )
163170 if cached_dna :
164171 logger .debug ("Using cached DNA" , repo_id = repo_id )
165172 if format == "markdown" :
166173 return {"dna" : cached_dna .to_markdown (), "cached" : True }
167174 return {** cached_dna .to_dict (), "cached" : True }
168-
169- # Extract fresh DNA
175+
170176 logger .info ("Extracting codebase DNA" , repo_id = repo_id )
171177 metrics .increment ("dna_extractions" )
172-
178+
173179 dna = dna_extractor .extract_dna (repo ["local_path" ], repo_id )
174180 dna_extractor .save_to_cache (repo_id , dna )
175-
181+
176182 if format == "markdown" :
177183 return {"dna" : dna .to_markdown (), "cached" : False }
178184 return {** dna .to_dict (), "cached" : False }
179-
185+
186+ except HTTPException :
187+ raise
180188 except Exception as e :
181- logger .error ("Error extracting DNA" , repo_id = repo_id , error = str (e ))
182- raise HTTPException (status_code = 500 , detail = str (e ))
189+ logger .error ("DNA extraction failed" , repo_id = repo_id , error = str (e ))
190+ capture_exception (e , operation = "dna_extraction" , repo_id = repo_id )
191+ raise HTTPException (status_code = 500 , detail = "Failed to extract codebase DNA" )
0 commit comments