Spaces:
Running
Running
import gradio as gr | |
import requests | |
import git | |
import os | |
import subprocess | |
import zipfile | |
import io | |
from getpass import getpass | |
import radon.complexity as radon_complexity | |
import pylint.lint | |
from pylint.reporters.text import TextReporter | |
# Function to download repo as a zip file from GitHub API | |
def download_repo(github_url): | |
repo_name = github_url.split('/')[-1] | |
repo_owner = github_url.split('/')[-2] | |
api_url = f"https://github.com/{repo_owner}/{repo_name}/archive/refs/heads/main.zip" | |
# Download the zip file | |
response = requests.get(api_url) | |
# Extract the zip file | |
zip_file = zipfile.ZipFile(io.BytesIO(response.content)) | |
zip_file.extractall(f"/content/repos/{repo_name}") | |
return f"/content/repos/{repo_name}" | |
# Function to fetch the GitHub repo using SSH or token for private repos | |
def fetch_repo(github_url, token=None): | |
try: | |
# Check if the repository is private or public | |
if token: | |
repo_name = github_url.split('/')[-1] | |
repo_owner = github_url.split('/')[-2] | |
clone_url = f"https://{token}@github.com/{repo_owner}/{repo_name}.git" | |
else: | |
repo_name = github_url.split('/')[-1] | |
repo_owner = github_url.split('/')[-2] | |
clone_url = f"git@github.com:{repo_owner}/{repo_name}.git" | |
# Create a temporary directory to clone the repo | |
temp_dir = f"/content/repos/{repo_name}" | |
# Check if repo already exists | |
if not os.path.exists(temp_dir): | |
# If SSH method fails, fallback to downloading as a zip | |
try: | |
git.Repo.clone_from(clone_url, temp_dir) | |
except Exception as e: | |
return download_repo(github_url) | |
return temp_dir | |
except Exception as e: | |
return f"Error: {str(e)}" | |
# Function to calculate cyclomatic complexity using Radon | |
def analyze_complexity(repo_path): | |
result = subprocess.run(['radon', 'cc', repo_path, '--json'], stdout=subprocess.PIPE) | |
complexity_data = result.stdout.decode('utf-8') | |
return complexity_data | |
# Function to run pylint for linting | |
def analyze_linting(repo_path): | |
pylint_output = [] | |
pylint_runner = pylint.lint.Run([repo_path], reporter=TextReporter(pylint_output)) | |
return "\n".join(pylint_output) | |
# Function to check test coverage | |
def analyze_coverage(repo_path): | |
result = subprocess.run(['pytest', '--cov', repo_path], stdout=subprocess.PIPE) | |
coverage_data = result.stdout.decode('utf-8') | |
return coverage_data | |
# Function to check for code duplication with jscpd | |
def analyze_duplication(repo_path): | |
result = subprocess.run(['jscpd', repo_path, '--reporters', 'text'], stdout=subprocess.PIPE) | |
duplication_data = result.stdout.decode('utf-8') | |
return duplication_data | |
# Main function to analyze the repository | |
def analyze_code(github_url, token=None): | |
try: | |
repo_path = fetch_repo(github_url, token) | |
# Perform analysis | |
complexity = analyze_complexity(repo_path) | |
linting = analyze_linting(repo_path) | |
coverage = analyze_coverage(repo_path) | |
duplication = analyze_duplication(repo_path) | |
# Combine results | |
results = f"### Cyclomatic Complexity Analysis\n{complexity}\n\n" | |
results += f"### Linting Results\n{linting}\n\n" | |
results += f"### Test Coverage\n{coverage}\n\n" | |
results += f"### Code Duplication\n{duplication}\n" | |
return results | |
except Exception as e: | |
return f"Error: {str(e)}" | |
# Create Gradio Interface | |
def gradio_interface(): | |
gr.Interface( | |
fn=analyze_code, | |
inputs=[ | |
gr.Textbox(label="GitHub Repository URL", placeholder="Enter the URL of the GitHub repo"), | |
gr.Textbox(label="GitHub Token (Optional)", type="password") | |
], | |
outputs="text", | |
live=True, | |
title="GitHub Code Quality Analyzer", | |
description="Enter a GitHub repository URL to analyze its code quality (complexity, linting, coverage, duplication)." | |
).launch(share=True) | |
gradio_interface() | |