22"""Fetch all issues (open and closed) from a GitHub repository via GraphQL and store as structured JSON."""
33
44import argparse
5+ from datetime import datetime , timezone
56import json
7+ from pathlib import Path
68import subprocess
79import sys
810import time
9- from datetime import datetime , timezone
10- from pathlib import Path
1111
1212GRAPHQL_QUERY = """
1313query($owner: String!, $repo: String!, $cursor: String, $states: [IssueState!]) {
@@ -72,7 +72,9 @@ def gh_graphql(query: str, variables: dict) -> dict:
7272 payload = json .dumps ({"query" : query , "variables" : clean_vars })
7373 result = subprocess .run (
7474 ["gh" , "api" , "graphql" , "--input" , "-" ],
75- input = payload , capture_output = True , text = True ,
75+ input = payload ,
76+ capture_output = True ,
77+ text = True ,
7678 )
7779 if result .returncode != 0 :
7880 raise RuntimeError (f"gh api graphql failed: { result .stderr } " )
@@ -121,13 +123,15 @@ def transform_issue(raw: dict) -> dict:
121123 """Transform a raw GraphQL issue node into our clean structure."""
122124 comments = []
123125 for c in raw ["comments" ]["nodes" ]:
124- comments .append ({
125- "author" : c ["author" ]["login" ] if c .get ("author" ) else None ,
126- "body" : c ["body" ],
127- "created_at" : c ["createdAt" ],
128- "updated_at" : c ["updatedAt" ],
129- "reactions" : transform_reactions (c .get ("reactionGroups" , [])),
130- })
126+ comments .append (
127+ {
128+ "author" : c ["author" ]["login" ] if c .get ("author" ) else None ,
129+ "body" : c ["body" ],
130+ "created_at" : c ["createdAt" ],
131+ "updated_at" : c ["updatedAt" ],
132+ "reactions" : transform_reactions (c .get ("reactionGroups" , [])),
133+ }
134+ )
131135
132136 timeline = []
133137 for t in raw ["timelineItems" ]["nodes" ]:
@@ -145,7 +149,7 @@ def transform_issue(raw: dict) -> dict:
145149 "updated_at" : raw ["updatedAt" ],
146150 "closed_at" : raw ["closedAt" ],
147151 "assignees" : [a ["login" ] for a in raw ["assignees" ]["nodes" ]],
148- "labels" : [l ["name" ] for l in raw ["labels" ]["nodes" ]],
152+ "labels" : [label ["name" ] for label in raw ["labels" ]["nodes" ]],
149153 "milestone" : raw .get ("milestone" ),
150154 "reactions" : transform_reactions (raw .get ("reactionGroups" , [])),
151155 "comment_count" : raw ["comments" ]["totalCount" ],
@@ -168,12 +172,18 @@ def fetch_all_issues(owner: str, repo: str, states: list[str] | None = None) ->
168172 for attempt in range (max_retries ):
169173 try :
170174 print (f"Fetching { label } issues page { page } ..." , file = sys .stderr )
171- data = gh_graphql (GRAPHQL_QUERY , {
172- "owner" : owner , "repo" : repo , "cursor" : cursor , "states" : states ,
173- })
175+ data = gh_graphql (
176+ GRAPHQL_QUERY ,
177+ {
178+ "owner" : owner ,
179+ "repo" : repo ,
180+ "cursor" : cursor ,
181+ "states" : states ,
182+ },
183+ )
174184 break
175185 except RuntimeError as e :
176- wait = min (2 ** attempt , 60 )
186+ wait = min (2 ** attempt , 60 )
177187 print (f"Error on attempt { attempt + 1 } : { e } " , file = sys .stderr )
178188 if attempt < max_retries - 1 :
179189 print (f"Retrying in { wait } s..." , file = sys .stderr )
@@ -215,8 +225,9 @@ def main():
215225 parser .add_argument ("--owner" , default = "bitsandbytes-foundation" , help = "Repository owner" )
216226 parser .add_argument ("--repo" , default = "bitsandbytes" , help = "Repository name" )
217227 parser .add_argument ("--open-only" , action = "store_true" , help = "Only fetch open issues" )
218- parser .add_argument ("-o" , "--output" , default = None ,
219- help = "Output JSON file path (default: <repo>_issues.json in script dir)" )
228+ parser .add_argument (
229+ "-o" , "--output" , default = None , help = "Output JSON file path (default: <repo>_issues.json in script dir)"
230+ )
220231 args = parser .parse_args ()
221232
222233 output_path = args .output or str (Path (__file__ ).parent / f"{ args .repo } _issues.json" )
@@ -242,8 +253,7 @@ def main():
242253 with open (output_path , "w" ) as f :
243254 json .dump (result , f , indent = 2 , ensure_ascii = False )
244255
245- print (f"Wrote { len (open_issues )} open + { len (closed_issues )} closed issues to { output_path } " ,
246- file = sys .stderr )
256+ print (f"Wrote { len (open_issues )} open + { len (closed_issues )} closed issues to { output_path } " , file = sys .stderr )
247257
248258
249259if __name__ == "__main__" :
0 commit comments