MCPcopy Create free account
hub / github.com/tirth8205/code-review-graph / analyze_changes

Function analyze_changes

code_review_graph/changes.py:277–409  ·  view source on GitHub ↗

Analyze changes and produce risk-scored review guidance. Args: store: The graph store. changed_files: List of changed file paths. changed_ranges: Optional pre-parsed diff ranges. If not provided and ``repo_root`` is given, they are computed via the detected V

(
    store: GraphStore,
    changed_files: list[str],
    changed_ranges: dict[str, list[tuple[int, int]]] | None = None,
    repo_root: str | None = None,
    base: str = "HEAD~1",
)

Source from the content-addressed store, hash-verified

275
276
277def analyze_changes(
278 store: GraphStore,
279 changed_files: list[str],
280 changed_ranges: dict[str, list[tuple[int, int]]] | None = None,
281 repo_root: str | None = None,
282 base: str = "HEAD~1",
283) -> dict[str, Any]:
284 """Analyze changes and produce risk-scored review guidance.
285
286 Args:
287 store: The graph store.
288 changed_files: List of changed file paths.
289 changed_ranges: Optional pre-parsed diff ranges. If not provided and
290 ``repo_root`` is given, they are computed via the detected VCS
291 (Git or SVN).
292 repo_root: Repository root (for git/svn diff).
293 base: Git ref or SVN revision range to diff against.
294
295 Returns:
296 Dict with ``summary``, ``risk_score``, ``changed_functions``,
297 ``affected_flows``, ``test_gaps``, and ``review_priorities``.
298 """
299 # Compute changed ranges if not provided.
300 if changed_ranges is None and repo_root is not None:
301 # Diff keys are forward-slash paths relative to the repo root, but
302 # the graph stores absolute native paths. Remap so lookups work on
303 # Windows, where the LIKE-suffix fallback cannot bridge
304 # "src/app.py" to "C:\repo\src\app.py" (#528). Keys that are
305 # already absolute pass through pathlib joining unchanged. The
306 # explicit changed_ranges path (MCP) is untouched — tools/review.py
307 # remaps before calling, and remapping twice would corrupt keys.
308 root_path = Path(repo_root)
309 changed_ranges = {
310 str(root_path / key): ranges
311 for key, ranges in parse_diff_ranges(repo_root, base).items()
312 }
313
314 # Map changes to nodes.
315 if changed_ranges:
316 changed_nodes = map_changes_to_nodes(store, changed_ranges)
317 else:
318 # Fallback: all nodes in changed files.
319 changed_nodes = []
320 for fp in changed_files:
321 changed_nodes.extend(store.get_nodes_by_file(fp))
322
323 # Filter to functions/tests for risk scoring (skip File nodes).
324 changed_funcs = [
325 n for n in changed_nodes
326 if n.kind in ("Function", "Test", "Class")
327 ]
328
329 # Cap to prevent O(N*M) query explosion on large PRs.
330 _max_funcs = int(os.environ.get("CRG_MAX_CHANGED_FUNCS", "500"))
331 funcs_truncated = len(changed_funcs) > _max_funcs
332 if funcs_truncated:
333 changed_funcs = changed_funcs[:_max_funcs]
334

Calls 9

parse_diff_rangesFunction · 0.85
map_changes_to_nodesFunction · 0.85
compute_risk_scoreFunction · 0.85
node_to_dictFunction · 0.85
get_affected_flowsFunction · 0.85
_sanitize_nameFunction · 0.85
get_nodes_by_fileMethod · 0.80
getMethod · 0.80
get_edges_by_targetMethod · 0.80