n3mo 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
n3mo/__init__.py ADDED
File without changes
n3mo/api/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # N3MO Web API Package
@@ -0,0 +1,84 @@
1
+ import os
2
+ import logging
3
+ from fastapi import FastAPI, Request, Header, HTTPException
4
+
5
+ # Set up logging
6
+ logger = logging.getLogger("n3mo.api")
7
+ logging.basicConfig(level=logging.INFO)
8
+
9
+ app = FastAPI(
10
+ title="N3MO GitHub App Webhook API",
11
+ description="Listens to GitHub webhooks to run incremental impact analysis on Pull Requests.",
12
+ version="0.1.0"
13
+ )
14
+
15
+ # Configuration
16
+ GITHUB_WEBHOOK_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET", "")
17
+
18
+
19
+ @app.get("/health")
20
+ def health_check():
21
+ """Verify service health."""
22
+ return {"status": "healthy", "service": "n3mo-api"}
23
+
24
+
25
+ @app.post("/webhook")
26
+ async def github_webhook(
27
+ request: Request,
28
+ x_github_event: str = Header(None),
29
+ x_hub_signature_256: str = Header(None)
30
+ ):
31
+ """
32
+ Handle incoming GitHub App webhooks.
33
+ Filters for pull_request events to trigger blast-radius checks.
34
+ """
35
+ if not x_github_event:
36
+ raise HTTPException(status_code=400, detail="Missing X-GitHub-Event header")
37
+
38
+ # Verify webhook signature if secret is configured
39
+ if GITHUB_WEBHOOK_SECRET:
40
+ if not x_hub_signature_256:
41
+ raise HTTPException(status_code=401, detail="Missing X-Hub-Signature-256 header")
42
+ # Signature verification logic goes here
43
+ pass
44
+
45
+ payload = await request.json()
46
+ logger.info(f"Received GitHub event: {x_github_event}")
47
+
48
+ if x_github_event == "pull_request":
49
+ action = payload.get("action")
50
+ # Trigger on PR opening or adding new commits
51
+ if action in ["opened", "synchronize"]:
52
+ return handle_pull_request(payload)
53
+
54
+ return {"message": f"Event '{x_github_event}' ignored"}
55
+
56
+
57
+ def handle_pull_request(payload: dict) -> dict:
58
+ """
59
+ Extract diff details, run incremental indexing, and compute impact blast radius.
60
+ """
61
+ pr_number = payload.get("number")
62
+ repo_name = payload.get("repository", {}).get("full_name")
63
+ clone_url = payload.get("repository", {}).get("clone_url")
64
+ base_sha = payload.get("pull_request", {}).get("base", {}).get("sha")
65
+ head_sha = payload.get("pull_request", {}).get("head", {}).get("sha")
66
+
67
+ logger.info(f"Analyzing PR #{pr_number} for {repo_name} (from {base_sha} to {head_sha})")
68
+
69
+ # Placeholder logic for workflow:
70
+ # 1. Fetch changed files from GitHub API
71
+ # 2. Run AST parser incrementally for changed files
72
+ # 3. Compute blast radius CTE from database for changed symbols
73
+ # 4. Format PR Markdown comment and post to GitHub API
74
+
75
+ affected_symbols = ["predict_song_score", "get_recommendations"] # Example mockup
76
+
77
+ return {
78
+ "status": "processed",
79
+ "pr": pr_number,
80
+ "repo": repo_name,
81
+ "clone_url": clone_url,
82
+ "changed_symbols": affected_symbols,
83
+ "message": f"Successfully calculated blast radius for {len(affected_symbols)} symbols."
84
+ }