| import requests |
| from typing import List, Optional |
|
|
| from config import settings |
| from schemas import RetrievedEvidence, SourceType |
|
|
|
|
| GITHUB_SEARCH_API = "https://api.github.com/search/issues" |
|
|
|
|
| def clean_text(text: Optional[str]) -> str: |
| if not text: |
| return "" |
| return str(text).strip() |
|
|
|
|
| def build_github_query( |
| message: str, |
| error_message: Optional[str] = None, |
| language: Optional[str] = None, |
| framework: Optional[str] = None, |
| ) -> str: |
| parts = [] |
|
|
| if framework: |
| parts.append(clean_text(framework)) |
|
|
| if language: |
| parts.append(clean_text(language)) |
|
|
| if error_message: |
| parts.append(f'"{clean_text(error_message)}"') |
|
|
| if message: |
| parts.append(clean_text(message)) |
|
|
| parts.append("is:issue") |
|
|
| return " ".join(part for part in parts if part).strip() |
|
|
|
|
| def search_github( |
| message: str, |
| error_message: Optional[str] = None, |
| language: Optional[str] = None, |
| framework: Optional[str] = None, |
| max_results: Optional[int] = None, |
| ) -> List[RetrievedEvidence]: |
| query = build_github_query( |
| message=message, |
| error_message=error_message, |
| language=language, |
| framework=framework, |
| ) |
|
|
| if not query: |
| return [] |
|
|
| headers = { |
| "Accept": "application/vnd.github+json", |
| } |
|
|
| if settings.GITHUB_TOKEN: |
| headers["Authorization"] = f"Bearer {settings.GITHUB_TOKEN}" |
|
|
| params = { |
| "q": query, |
| "sort": "reactions", |
| "order": "desc", |
| "per_page": max_results or settings.MAX_GITHUB_RESULTS, |
| } |
|
|
| try: |
| response = requests.get( |
| GITHUB_SEARCH_API, |
| headers=headers, |
| params=params, |
| timeout=settings.SEARCH_TIMEOUT_SECONDS, |
| ) |
| response.raise_for_status() |
| data = response.json() |
| except Exception as e: |
| print(f"GitHub search failed: {e}") |
| return [] |
|
|
| items = data.get("items", []) |
| evidence_list: List[RetrievedEvidence] = [] |
|
|
| for item in items: |
| title = clean_text(item.get("title")) |
| url = clean_text(item.get("html_url")) |
| score = item.get("score") |
| state = clean_text(item.get("state")) |
| repo_full_name = clean_text(item.get("repository_url", "").split("/repos/")[-1]) |
|
|
| snippet_parts = [] |
| if repo_full_name: |
| snippet_parts.append(f"Repo: {repo_full_name}") |
| if state: |
| snippet_parts.append(f"State: {state}") |
|
|
| comments = item.get("comments") |
| if comments is not None: |
| snippet_parts.append(f"Comments: {comments}") |
|
|
| snippet = " | ".join(snippet_parts) |
|
|
| if not title: |
| continue |
|
|
| evidence_list.append( |
| RetrievedEvidence( |
| source_type=SourceType.GITHUB, |
| title=title, |
| snippet=snippet or "GitHub issue/discussion result", |
| url=url or None, |
| score=float(score) if score is not None else None, |
| ) |
| ) |
|
|
| return evidence_list |