Add reports, integrations, and utils modules
This commit is contained in:
135
vibeguard/integrations/github.py
Normal file
135
vibeguard/integrations/github.py
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
"""GitHub integration for VibeGuard."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class GitHubIntegration:
|
||||||
|
"""GitHub API integration for VibeGuard."""
|
||||||
|
|
||||||
|
def __init__(self, token: str | None = None) -> None:
|
||||||
|
"""Initialize GitHub integration."""
|
||||||
|
self.token = token or os.environ.get("VIBEGUARD_GITHUB_TOKEN")
|
||||||
|
self.base_url = "https://api.github.com"
|
||||||
|
|
||||||
|
def _get_headers(self) -> dict[str, str]:
|
||||||
|
"""Get headers for API requests."""
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/vnd.github.v3+json",
|
||||||
|
}
|
||||||
|
if self.token:
|
||||||
|
headers["Authorization"] = f"Bearer {self.token}"
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def create_check_run(
|
||||||
|
self,
|
||||||
|
repo: str,
|
||||||
|
name: str,
|
||||||
|
conclusion: str,
|
||||||
|
details_url: str | None = None,
|
||||||
|
output: dict[str, Any] | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Create a check run for a GitHub repository."""
|
||||||
|
url = f"{self.base_url}/repos/{repo}/check-runs"
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"name": name,
|
||||||
|
"head_sha": self._get_head_sha(),
|
||||||
|
"status": "completed",
|
||||||
|
"conclusion": conclusion,
|
||||||
|
}
|
||||||
|
|
||||||
|
if details_url:
|
||||||
|
data["details_url"] = details_url
|
||||||
|
|
||||||
|
if output:
|
||||||
|
data["output"] = output
|
||||||
|
|
||||||
|
response = requests.post(url, headers=self._get_headers(), json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def update_check_run(
|
||||||
|
self,
|
||||||
|
repo: str,
|
||||||
|
check_run_id: int,
|
||||||
|
conclusion: str,
|
||||||
|
output: dict[str, Any] | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Update an existing check run."""
|
||||||
|
url = f"{self.base_url}/repos/{repo}/check-runs/{check_run_id}"
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"status": "completed",
|
||||||
|
"conclusion": conclusion,
|
||||||
|
}
|
||||||
|
|
||||||
|
if output:
|
||||||
|
data["output"] = output
|
||||||
|
|
||||||
|
response = requests.patch(url, headers=self._get_headers(), json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def create_pull_request_comment(
|
||||||
|
self, repo: str, pull_number: int, body: str
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Create a comment on a pull request."""
|
||||||
|
url = f"{self.base_url}/repos/{repo}/issues/{pull_number}/comments"
|
||||||
|
|
||||||
|
data = {"body": body}
|
||||||
|
|
||||||
|
response = requests.post(url, headers=self._get_headers(), json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def upload_sarif(
|
||||||
|
self, repo: str, sarif_content: dict[str, Any], commit_oid: str
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Upload SARIF results to GitHub Code Scanning."""
|
||||||
|
url = f"{self.base_url}/repos/{repo}/code-scanning/sarifs"
|
||||||
|
|
||||||
|
data = {"sarif": sarif_content, "commit_oid": commit_oid}
|
||||||
|
|
||||||
|
response = requests.post(url, headers=self._get_headers(), json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def _get_head_sha(self) -> str:
|
||||||
|
"""Get the head SHA from environment or git."""
|
||||||
|
sha = os.environ.get("GITHUB_SHA")
|
||||||
|
if sha:
|
||||||
|
return sha
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
["git", "rev-parse", "HEAD"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
return result.stdout.strip()
|
||||||
|
|
||||||
|
def get_pull_request_files(self, repo: str, pull_number: int) -> list[dict[str, Any]]:
|
||||||
|
"""Get files changed in a pull request."""
|
||||||
|
url = f"{self.base_url}/repos/{repo}/pulls/{pull_number}/files"
|
||||||
|
|
||||||
|
response = requests.get(url, headers=self._get_headers())
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_check_runs(self, repo: str, ref: str) -> dict[str, Any]:
|
||||||
|
"""Get check runs for a ref."""
|
||||||
|
url = f"{self.base_url}/repos/{repo}/commits/{ref}/check-runs"
|
||||||
|
|
||||||
|
response = requests.get(url, headers=self._get_headers())
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
return response.json()
|
||||||
Reference in New Issue
Block a user