Skip to content

Commit 715a40a

Browse files
dev-altclaude
andcommitted
Fix GitHub repository functionality and add bulk repo loading
Features Added: - ✅ Fix GitHub repo analysis using GitHub API instead of local files - ✅ Add comprehensive GitHub repository metadata extraction - ✅ Add "Load My Repos" button to load all user repositories - ✅ Add loading dialog with progress indicator for bulk operations - ✅ Support GitHub-specific fields (stars, forks, topics, etc.) Technical Improvements: - Enhanced ProjectMetadata with GitHub-specific fields - Implemented proper GitHub API integration for repository analysis - Added robust error handling for GitHub operations - Fixed license field access with try-catch protection - Updated repository references to new GitHub URL UI Enhancements: - Added "📚 Load My Repos" button for authenticated users - Loading dialog with progress bar for long operations - Better error messages for GitHub connectivity issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 64aa86a commit 715a40a

5 files changed

Lines changed: 188 additions & 9 deletions

File tree

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Thank you for your interest in contributing to RepoReadme! This project uses mod
66

77
1. **Fork and Clone**
88
```bash
9-
git clone https://github.com/yourusername/reporeadme.git
9+
git clone https://github.com/dev-alt/RepoReadme.git
1010
cd reporeadme
1111
```
1212

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
> Professional README generation for your repositories with intelligent analysis and beautiful templates
44
5-
[![Version](https://img.shields.io/badge/version-1.0.0-blue.svg?style=flat)](https://github.com/yourusername/reporeadme)
5+
[![Version](https://img.shields.io/badge/version-1.0.0-blue.svg?style=flat)](https://github.com/dev-alt/RepoReadme)
66
[![Language](https://img.shields.io/badge/language-python-blue.svg?style=flat)](https://python.org)
77
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](LICENSE)
88

@@ -57,7 +57,7 @@
5757

5858
1. **Clone the repository**
5959
```bash
60-
git clone https://github.com/yourusername/reporeadme.git
60+
git clone https://github.com/dev-alt/RepoReadme.git
6161
cd reporeadme
6262
```
6363

src/analyzers/repository_analyzer.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ class ProjectMetadata:
8080
created_date: Optional[str] = None
8181
last_updated: Optional[str] = None
8282

83+
# GitHub-specific information
84+
stars_count: int = 0
85+
forks_count: int = 0
86+
open_issues: int = 0
87+
default_branch: str = "main"
88+
topics: List[str] = field(default_factory=list)
89+
commits_count: int = 0 # Alias for commits
90+
has_readme: bool = False
91+
8392
# Features and capabilities
8493
features: List[str] = field(default_factory=list)
8594
installation_commands: List[str] = field(default_factory=list)

src/gui.py

Lines changed: 175 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ def create_repository_panel(self):
158158
command=self.add_local_repository, style='Action.TButton').pack(side='left', padx=5)
159159
ttk.Button(button_frame, text="🐙 Add GitHub Repo",
160160
command=self.add_github_repository, style='Action.TButton').pack(side='left', padx=5)
161+
ttk.Button(button_frame, text="📚 Load My Repos",
162+
command=self.load_user_repositories, style='Action.TButton').pack(side='left', padx=5)
161163
ttk.Button(button_frame, text="🗑️ Remove",
162164
command=self.remove_repository, style='Action.TButton').pack(side='left', padx=5)
163165

@@ -400,6 +402,58 @@ def add_github_repository(self):
400402
self.update_repository_list()
401403
self.logger.info(f"Added GitHub repository: {repo_name}", "GUI")
402404

405+
def load_user_repositories(self):
406+
"""Load all repositories from the authenticated user."""
407+
if self.github_client is None:
408+
messagebox.showerror("GitHub Unavailable",
409+
"GitHub client not available. Please ensure PyGithub is installed.")
410+
return
411+
412+
# Show loading dialog
413+
loading_dialog = LoadingDialog(self.root, "Loading your GitHub repositories...")
414+
415+
def load_repos_thread():
416+
try:
417+
# Get user's repositories
418+
user = self.github_client.get_user()
419+
repos = list(user.get_repos(type='owner', sort='updated'))
420+
421+
# Add repositories to the list
422+
for repo in repos:
423+
repo_item = RepositoryItem(
424+
name=f"{repo.owner.login}/{repo.name}",
425+
path="",
426+
url=repo.html_url,
427+
repo_type="github"
428+
)
429+
# Check if repo already exists
430+
if not any(r.url == repo.html_url for r in self.repositories):
431+
self.repositories.append(repo_item)
432+
433+
# Update UI on main thread
434+
self.root.after(0, lambda: self._finish_load_repos(loading_dialog, len(repos)))
435+
436+
except Exception as e:
437+
self.root.after(0, lambda: self._handle_load_repos_error(loading_dialog, str(e)))
438+
439+
# Start loading in background thread
440+
threading.Thread(target=load_repos_thread, daemon=True).start()
441+
442+
def _finish_load_repos(self, loading_dialog, repo_count):
443+
"""Finish loading user repositories."""
444+
loading_dialog.close()
445+
self.update_repository_list()
446+
messagebox.showinfo("Repositories Loaded",
447+
f"Successfully loaded {repo_count} repositories from your GitHub account!")
448+
self.logger.info(f"Loaded {repo_count} user repositories from GitHub", "GUI")
449+
450+
def _handle_load_repos_error(self, loading_dialog, error_msg):
451+
"""Handle error during repository loading."""
452+
loading_dialog.close()
453+
messagebox.showerror("Loading Failed",
454+
f"Failed to load repositories from GitHub:\n{error_msg}")
455+
self.logger.error(f"Failed to load user repositories: {error_msg}", "GUI")
456+
403457
def remove_repository(self):
404458
"""Remove selected repository."""
405459
selection = self.repo_tree.selection()
@@ -529,10 +583,8 @@ def _analyze_repository_thread(self, repo_item: RepositoryItem):
529583
if repo_item.repo_type == "local":
530584
metadata = self.analyzer.analyze_repository(repo_item.path, repo_item.name)
531585
else:
532-
# For GitHub repos, would need to clone or use API
533-
# Simplified for this example
534-
metadata = ProjectMetadata()
535-
metadata.name = repo_item.name
586+
# For GitHub repos, use GitHub API to analyze
587+
metadata = self._analyze_github_repository(repo_item)
536588

537589
repo_item.metadata = metadata
538590
repo_item.status = "completed"
@@ -548,6 +600,93 @@ def _analyze_repository_thread(self, repo_item: RepositoryItem):
548600
finally:
549601
self.is_analyzing = False
550602

603+
def _analyze_github_repository(self, repo_item: RepositoryItem) -> ProjectMetadata:
604+
"""Analyze a GitHub repository using the GitHub API."""
605+
try:
606+
# Parse repository owner and name from URL
607+
url_parts = repo_item.url.rstrip('/').split('/')
608+
if len(url_parts) >= 2:
609+
owner = url_parts[-2]
610+
repo_name = url_parts[-1]
611+
else:
612+
raise ValueError(f"Invalid GitHub URL format: {repo_item.url}")
613+
614+
# Get repository information from GitHub API
615+
github_repo = self.github_client.get_repo(f"{owner}/{repo_name}")
616+
617+
# Create metadata from GitHub API data
618+
metadata = ProjectMetadata()
619+
metadata.name = github_repo.name
620+
metadata.description = github_repo.description or ""
621+
metadata.repository_url = github_repo.html_url
622+
metadata.author = github_repo.owner.login
623+
try:
624+
metadata.license = github_repo.license.name if github_repo.license else ""
625+
except:
626+
metadata.license = ""
627+
metadata.created_date = github_repo.created_at.strftime("%Y-%m-%d")
628+
metadata.last_updated = github_repo.updated_at.strftime("%Y-%m-%d")
629+
630+
# Get language information
631+
languages = github_repo.get_languages()
632+
total_bytes = sum(languages.values())
633+
if total_bytes > 0:
634+
metadata.languages = {
635+
lang: round((bytes_count / total_bytes) * 100, 1)
636+
for lang, bytes_count in languages.items()
637+
}
638+
metadata.primary_language = max(languages.items(), key=lambda x: x[1])[0]
639+
640+
# Get repository statistics
641+
metadata.total_files = github_repo.size # Approximation
642+
metadata.total_lines = 0 # Not directly available via API
643+
metadata.commits_count = github_repo.get_commits().totalCount
644+
645+
# Get additional repository information
646+
metadata.stars_count = github_repo.stargazers_count
647+
metadata.forks_count = github_repo.forks_count
648+
metadata.open_issues = github_repo.open_issues_count
649+
metadata.default_branch = github_repo.default_branch
650+
651+
# Detect project type from language and topics
652+
topics = list(github_repo.get_topics())
653+
metadata.topics = topics
654+
655+
# Basic project type detection
656+
if metadata.primary_language:
657+
lang_lower = metadata.primary_language.lower()
658+
if lang_lower in ['python']:
659+
metadata.project_type = "python"
660+
elif lang_lower in ['javascript', 'typescript']:
661+
metadata.project_type = "web"
662+
elif lang_lower in ['java']:
663+
metadata.project_type = "java"
664+
elif lang_lower in ['c', 'c++', 'cpp']:
665+
metadata.project_type = "cpp"
666+
elif lang_lower in ['go']:
667+
metadata.project_type = "go"
668+
else:
669+
metadata.project_type = "other"
670+
671+
# Set has_readme based on GitHub repo data
672+
try:
673+
github_repo.get_readme()
674+
metadata.has_readme = True
675+
except:
676+
metadata.has_readme = False
677+
678+
self.logger.info(f"Successfully analyzed GitHub repository: {metadata.name}", "GITHUB_ANALYSIS")
679+
return metadata
680+
681+
except Exception as e:
682+
self.logger.error(f"Failed to analyze GitHub repository {repo_item.url}: {e}", "GITHUB_ANALYSIS")
683+
# Return basic metadata on error
684+
metadata = ProjectMetadata()
685+
metadata.name = repo_item.name
686+
metadata.repository_url = repo_item.url
687+
metadata.description = f"GitHub repository (analysis failed: {str(e)})"
688+
return metadata
689+
551690
def _update_analysis_ui(self, repo_item: RepositoryItem, status: str, error_msg: str = ""):
552691
"""Update analysis UI elements."""
553692
repo_item.status = status
@@ -1032,4 +1171,35 @@ def on_add(self):
10321171

10331172
def on_cancel(self):
10341173
"""Handle cancel button click."""
1035-
self.dialog.destroy()
1174+
self.dialog.destroy()
1175+
1176+
1177+
class LoadingDialog:
1178+
"""Simple loading dialog with progress indicator."""
1179+
1180+
def __init__(self, parent, message="Loading..."):
1181+
self.dialog = tk.Toplevel(parent)
1182+
self.dialog.title("Loading")
1183+
self.dialog.geometry("300x100")
1184+
self.dialog.transient(parent)
1185+
self.dialog.grab_set()
1186+
1187+
# Center dialog
1188+
self.dialog.update_idletasks()
1189+
x = parent.winfo_x() + (parent.winfo_width() // 2) - 150
1190+
y = parent.winfo_y() + (parent.winfo_height() // 2) - 50
1191+
self.dialog.geometry(f"+{x}+{y}")
1192+
1193+
# Content
1194+
ttk.Label(self.dialog, text=message).pack(pady=20)
1195+
1196+
# Progress bar
1197+
self.progress = ttk.Progressbar(self.dialog, mode='indeterminate')
1198+
self.progress.pack(pady=10, padx=20, fill='x')
1199+
self.progress.start()
1200+
1201+
def close(self):
1202+
"""Close the loading dialog."""
1203+
if self.dialog.winfo_exists():
1204+
self.progress.stop()
1205+
self.dialog.destroy()

src/templates/readme_templates.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ def _generate_modern_template(self, metadata: ProjectMetadata, config: TemplateC
300300
# Footer
301301
content.append("---")
302302
content.append("")
303-
content.append(f"**{metadata.name}** - Generated with ❤️ by [RepoReadme](https://github.com/yourusername/reporeadme)")
303+
content.append(f"**{metadata.name}** - Generated with ❤️ by [RepoReadme](https://github.com/dev-alt/RepoReadme)")
304304

305305
return "\n".join(content)
306306

0 commit comments

Comments
 (0)