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()