@@ -96,49 +96,71 @@ async def get_repos(
9696 Uses /user/repos which returns repos the user has explicit access to,
9797 including personal repos and org repos where user is a member
9898 """
99- async with httpx .AsyncClient () as client :
100- params = {
101- "visibility" : "all" if include_private else "public" ,
102- "affiliation" : "owner,organization_member" ,
103- "sort" : "updated" ,
104- "direction" : "desc" ,
105- "per_page" : per_page ,
106- "page" : page
107- }
108- response = await client .get (
109- f"{ GITHUB_API_BASE } /user/repos" ,
110- headers = self .headers ,
111- params = params ,
112- timeout = 30.0
113- )
114- if response .status_code != 200 :
115- raise Exception (f"GitHub API error: { response .status_code } " )
99+ try :
100+ async with httpx .AsyncClient () as client :
101+ params = {
102+ "visibility" : "all" if include_private else "public" ,
103+ "affiliation" : "owner,organization_member" ,
104+ "sort" : "updated" ,
105+ "direction" : "desc" ,
106+ "per_page" : per_page ,
107+ "page" : page
108+ }
109+ response = await client .get (
110+ f"{ GITHUB_API_BASE } /user/repos" ,
111+ headers = self .headers ,
112+ params = params ,
113+ timeout = 30.0
114+ )
115+ if response .status_code != 200 :
116+ logger .error (
117+ "GitHub API error fetching repos" ,
118+ status_code = response .status_code ,
119+ page = page
120+ )
121+ return []
116122
117- repos = []
118- for repo in response .json ():
119- if not include_forks and repo .get ("fork" , False ):
120- continue
121- repos .append (GitHubRepo (
122- id = repo ["id" ],
123- name = repo ["name" ],
124- full_name = repo ["full_name" ],
125- description = repo .get ("description" ),
126- html_url = repo ["html_url" ],
127- clone_url = repo ["clone_url" ],
128- ssh_url = repo ["ssh_url" ],
129- default_branch = repo .get ("default_branch" , "main" ),
130- private = repo ["private" ],
131- fork = repo .get ("fork" , False ),
132- stargazers_count = repo .get ("stargazers_count" , 0 ),
133- language = repo .get ("language" ),
134- size = repo .get ("size" , 0 ),
135- owner_login = repo ["owner" ]["login" ],
136- owner_avatar = repo ["owner" ]["avatar_url" ]
137- ))
138- return repos
123+ repos = []
124+ for repo in response .json ():
125+ if not include_forks and repo .get ("fork" , False ):
126+ continue
127+ repos .append (GitHubRepo (
128+ id = repo .get ("id" , 0 ),
129+ name = repo .get ("name" , "" ),
130+ full_name = repo .get ("full_name" , "" ),
131+ description = repo .get ("description" ),
132+ html_url = repo .get ("html_url" , "" ),
133+ clone_url = repo .get ("clone_url" , "" ),
134+ ssh_url = repo .get ("ssh_url" , "" ),
135+ default_branch = repo .get ("default_branch" , "main" ),
136+ private = repo .get ("private" , False ),
137+ fork = repo .get ("fork" , False ),
138+ stargazers_count = repo .get ("stargazers_count" , 0 ),
139+ language = repo .get ("language" ),
140+ size = repo .get ("size" , 0 ),
141+ owner_login = repo .get ("owner" , {}).get ("login" , "" ),
142+ owner_avatar = repo .get ("owner" , {}).get ("avatar_url" , "" )
143+ ))
144+ return repos
145+ except (httpx .RequestError , httpx .TimeoutException ) as e :
146+ logger .error ("Network error fetching GitHub repos" , error = str (e ), page = page )
147+ return []
148+ except (KeyError , ValueError , TypeError ) as e :
149+ logger .error ("Failed to parse GitHub repos response" , error = str (e ), page = page )
150+ return []
139151
140- async def get_all_repos (self , include_forks : bool = False ) -> list [GitHubRepo ]:
141- """Fetch all repos with pagination"""
152+ async def get_all_repos (
153+ self ,
154+ include_forks : bool = False ,
155+ max_pages : Optional [int ] = 10
156+ ) -> list [GitHubRepo ]:
157+ """
158+ Fetch all repos with pagination
159+
160+ Args:
161+ include_forks: Whether to include forked repos
162+ max_pages: Maximum pages to fetch (None for no limit, default 10)
163+ """
142164 all_repos = []
143165 page = 1
144166 while True :
@@ -153,7 +175,13 @@ async def get_all_repos(self, include_forks: bool = False) -> list[GitHubRepo]:
153175 if len (repos ) < 100 :
154176 break
155177 page += 1
156- # Safety limit to prevent infinite loops
157- if page > 10 :
178+
179+ if max_pages is not None and page > max_pages :
180+ logger .warning (
181+ "GitHub repo pagination stopped at limit" ,
182+ max_pages = max_pages ,
183+ total_repos_fetched = len (all_repos ),
184+ stopped_at_page = page
185+ )
158186 break
159187 return all_repos
0 commit comments