| from typing import Any |
|
|
| import requests |
|
|
| from config import GITHUB_API, GITHUB_TOKEN |
|
|
|
|
| def _github_headers() -> dict[str, str]: |
| """ |
| GitHub API isteklerinde kullanılacak HTTP başlıklarını oluşturur. |
| Token tanımlıysa Authorization başlığını da ekler. |
| """ |
|
|
| headers = { |
| "Accept": "application/vnd.github+json", |
| "X-GitHub-Api-Version": "2022-11-28", |
| "User-Agent": "AI-Developer-Assistant", |
| } |
|
|
| if GITHUB_TOKEN: |
| headers["Authorization"] = f"Bearer {GITHUB_TOKEN}" |
|
|
| return headers |
|
|
|
|
| def _request_github( |
| endpoint: str, |
| params: dict[str, Any] | None = None, |
| ) -> tuple[requests.Response | None, str | None]: |
| """ |
| GitHub API isteğini gerçekleştirir. |
| |
| Başarısız bağlantı durumunda response yerine None, |
| hata açıklaması döndürür. |
| """ |
|
|
| url = f"{GITHUB_API}{endpoint}" |
|
|
| try: |
| response = requests.get( |
| url, |
| headers=_github_headers(), |
| params=params, |
| timeout=20, |
| ) |
| return response, None |
|
|
| except requests.RequestException as exc: |
| return None, f"GitHub API isteği başarısız oldu: {exc}" |
|
|
|
|
| def search_github_repo( |
| owner: str, |
| repo: str, |
| ) -> dict[str, Any]: |
| """ |
| Belirli bir GitHub repository'sinin temel bilgilerini getirir. |
| """ |
|
|
| owner = owner.strip() |
| repo = repo.strip() |
|
|
| if not owner: |
| raise ValueError("GitHub kullanıcı veya organizasyon adı boş olamaz.") |
|
|
| if not repo: |
| raise ValueError("Repository adı boş olamaz.") |
|
|
| response, request_error = _request_github( |
| endpoint=f"/repos/{owner}/{repo}" |
| ) |
|
|
| if request_error: |
| return { |
| "success": False, |
| "owner": owner, |
| "repo": repo, |
| "error": request_error, |
| } |
|
|
| if response is None: |
| return { |
| "success": False, |
| "owner": owner, |
| "repo": repo, |
| "error": "GitHub API yanıtı alınamadı.", |
| } |
|
|
| if response.status_code == 404: |
| return { |
| "success": False, |
| "owner": owner, |
| "repo": repo, |
| "error": "Repository bulunamadı veya erişim izni yok.", |
| } |
|
|
| if response.status_code == 403: |
| return { |
| "success": False, |
| "owner": owner, |
| "repo": repo, |
| "status_code": response.status_code, |
| "error": ( |
| "GitHub API erişimi reddetti. " |
| "Rate limit aşılmış veya token yetkisiz olabilir." |
| ), |
| } |
|
|
| if response.status_code != 200: |
| return { |
| "success": False, |
| "owner": owner, |
| "repo": repo, |
| "status_code": response.status_code, |
| "error": "GitHub API beklenmeyen bir yanıt döndürdü.", |
| } |
|
|
| try: |
| data = response.json() |
| except ValueError: |
| return { |
| "success": False, |
| "owner": owner, |
| "repo": repo, |
| "error": "GitHub API geçerli bir JSON yanıtı döndürmedi.", |
| } |
|
|
| license_data = data.get("license") or {} |
| owner_data = data.get("owner") or {} |
|
|
| return { |
| "success": True, |
| "full_name": data.get("full_name"), |
| "name": data.get("name"), |
| "owner": owner_data.get("login"), |
| "description": data.get("description"), |
| "html_url": data.get("html_url"), |
| "stars": data.get("stargazers_count"), |
| "forks": data.get("forks_count"), |
| "watchers": data.get("subscribers_count"), |
| "open_issues": data.get("open_issues_count"), |
| "language": data.get("language"), |
| "license": license_data.get("spdx_id"), |
| "topics": data.get("topics", []), |
| "default_branch": data.get("default_branch"), |
| "created_at": data.get("created_at"), |
| "updated_at": data.get("updated_at"), |
| "pushed_at": data.get("pushed_at"), |
| "archived": data.get("archived"), |
| "visibility": data.get("visibility"), |
| } |
|
|
|
|
| def search_github_repositories( |
| keyword: str, |
| limit: int = 5, |
| ) -> dict[str, Any]: |
| """ |
| GitHub üzerinde anahtar kelimeye göre repository arar. |
| Sonuçları yıldız sayısına göre azalan biçimde getirir. |
| """ |
|
|
| keyword = keyword.strip() |
|
|
| if not keyword: |
| raise ValueError("GitHub arama ifadesi boş olamaz.") |
|
|
| limit = max(1, min(limit, 10)) |
|
|
| response, request_error = _request_github( |
| endpoint="/search/repositories", |
| params={ |
| "q": keyword, |
| "sort": "stars", |
| "order": "desc", |
| "per_page": limit, |
| }, |
| ) |
|
|
| if request_error: |
| return { |
| "success": False, |
| "keyword": keyword, |
| "error": request_error, |
| } |
|
|
| if response is None: |
| return { |
| "success": False, |
| "keyword": keyword, |
| "error": "GitHub API yanıtı alınamadı.", |
| } |
|
|
| if response.status_code == 403: |
| return { |
| "success": False, |
| "keyword": keyword, |
| "status_code": response.status_code, |
| "error": ( |
| "GitHub API erişimi reddetti. " |
| "Rate limit aşılmış veya token yetkisiz olabilir." |
| ), |
| } |
|
|
| if response.status_code != 200: |
| return { |
| "success": False, |
| "keyword": keyword, |
| "status_code": response.status_code, |
| "error": "GitHub repository araması başarısız oldu.", |
| } |
|
|
| try: |
| data = response.json() |
| except ValueError: |
| return { |
| "success": False, |
| "keyword": keyword, |
| "error": "GitHub API geçerli bir JSON yanıtı döndürmedi.", |
| } |
|
|
| repositories = [] |
|
|
| for item in data.get("items", []): |
| license_data = item.get("license") or {} |
|
|
| repositories.append( |
| { |
| "full_name": item.get("full_name"), |
| "description": item.get("description"), |
| "html_url": item.get("html_url"), |
| "stars": item.get("stargazers_count"), |
| "forks": item.get("forks_count"), |
| "open_issues": item.get("open_issues_count"), |
| "language": item.get("language"), |
| "license": license_data.get("spdx_id"), |
| "updated_at": item.get("updated_at"), |
| "topics": item.get("topics", []), |
| } |
| ) |
|
|
| return { |
| "success": True, |
| "keyword": keyword, |
| "total_count": data.get("total_count", 0), |
| "returned_count": len(repositories), |
| "repositories": repositories, |
| } |