-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathboot.py
More file actions
executable file
Β·186 lines (147 loc) Β· 5.24 KB
/
Copy pathboot.py
File metadata and controls
executable file
Β·186 lines (147 loc) Β· 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#!/usr/bin/env python3
"""Fleet Mechanic Boot Sequence."""
import sys
import json
import subprocess
from typing import List, Optional
sys.path.insert(0, 'src')
from mechanic import FleetMechanic, RepoHealth
def load_github_token(token_path: str = "/tmp/.mechanic_token") -> str:
"""Load GitHub token from file.
Args:
token_path: Path to the token file
Returns:
GitHub token string
Raises:
FileNotFoundError: If token file does not exist
ValueError: If token file is empty
"""
try:
with open(token_path, 'r') as f:
token = f.read().strip()
if not token:
raise ValueError("GitHub token file is empty")
return token
except FileNotFoundError:
raise FileNotFoundError(f"GitHub token file not found: {token_path}")
def fetch_user_repos(token: str, per_page: int = 30) -> List[dict]:
"""Fetch user's repositories from GitHub API.
Args:
token: GitHub authentication token
per_page: Number of repos per page
Returns:
List of repository dictionaries
Raises:
RuntimeError: If API request fails
"""
try:
result = subprocess.run(
['curl', '-s', '-H', f'Authorization: token {token}',
f'https://api.github.com/user/repos?sort=updated&per_page={per_page}'],
capture_output=True, text=True, timeout=30
)
if result.returncode != 0:
raise RuntimeError(f"curl failed: {result.stderr}")
return json.loads(result.stdout)
except json.JSONDecodeError as e:
raise RuntimeError(f"Failed to parse GitHub API response: {e}")
except subprocess.TimeoutExpired:
raise RuntimeError("GitHub API request timed out")
def filter_own_repos(repos: List[dict], min_size_kb: int = 10) -> List[str]:
"""Filter non-fork repos with minimum size.
Args:
repos: List of repository dictionaries
min_size_kb: Minimum repository size in KB
Returns:
List of repository names
"""
return [
r["name"] for r in repos
if not r.get("fork") and r.get("size", 0) > min_size_kb
]
def print_scan_results(reports: List[RepoHealth]) -> None:
"""Print scan results in a formatted table.
Args:
reports: List of RepoHealth objects
"""
print(f"{'Repo':35s} {'Score':>6s} {'Tests':>10s} {'README':>6s} {'CI':>4s} {'Lang':>6s}")
print("-" * 75)
for r in reports:
score = f"{r.health_score:.0%}"
tests = f"{r.test_pass}/{r.test_count}" if r.test_count > 0 else "-"
readme = "Y" if r.has_readme else "N"
ci = "Y" if r.has_ci else "N"
lang = (r.language or "?")[:6]
print(f"{r.repo:35s} {score:>6s} {tests:>10s} {readme:>6s} {ci:>4s} {lang:>6s}")
def print_summary(reports: List[RepoHealth]) -> None:
"""Print summary statistics.
Args:
reports: List of RepoHealth objects
"""
needs = [r for r in reports if r.health_score < 0.5]
healthy = [r for r in reports if r.health_score >= 0.5]
print(f"\nHealthy: {len(healthy)}/{len(reports)}, Needs attention: {len(needs)}/{len(reports)}")
def fix_repos_needing_docs(mechanic: FleetMechanic, reports: List[RepoHealth]) -> int:
"""Auto-fix repos missing gitignore or CI.
Args:
mechanic: FleetMechanic instance
reports: List of RepoHealth objects
Returns:
Number of repos successfully fixed
"""
fixed = 0
for r in reports:
if not r.has_gitignore or not r.has_ci:
print(f"\nFixing {r.repo}...")
try:
task = mechanic.execute_gen_docs(r.repo)
print(f" Result: {task.result.value} - {task.diagnosis}")
if task.result.value == "success":
fixed += 1
except Exception as e:
print(f" Error: {e}")
return fixed
def main() -> int:
"""Main boot sequence.
Returns:
Exit code (0 for success, non-zero for error)
"""
try:
# Load token and initialize mechanic
token = load_github_token()
mechanic = FleetMechanic(token, "SuperInstance")
print("π§ Fleet Mechanic Booted")
print("=" * 40)
# Fetch repositories
repos = fetch_user_repos(token)
own_repos = filter_own_repos(repos)
if not own_repos:
print("No repositories found to scan.")
return 0
print(f"Found {len(own_repos)} own repos with content")
print(f"Scanning top 20...\n")
# Scan fleet
reports = mechanic.fleet_scan(own_repos[:20])
reports.sort(key=lambda r: r.health_score)
# Print results
print_scan_results(reports)
print_summary(reports)
# Fix repos that need attention
fixed = fix_repos_needing_docs(mechanic, reports)
print(f"\nTotal fixes: {fixed}")
print("Mission complete.")
return 0
except FileNotFoundError as e:
print(f"Error: {e}")
return 1
except ValueError as e:
print(f"Error: {e}")
return 1
except RuntimeError as e:
print(f"Error: {e}")
return 1
except Exception as e:
print(f"Unexpected error: {e}")
return 1
if __name__ == "__main__":
sys.exit(main())