6262
6363
6464def graphql_query (query : str , token : Optional [str ] = None ) -> dict :
65- headers = {'Authorization' : 'Bearer {}' . format ( token ) } if token else None
65+ headers = {'Authorization' : f 'Bearer { token } ' } if token else None
6666 request = requests .post (
6767 'https://api.github.com/graphql' ,
6868 json = {'query' : query },
6969 headers = headers )
7070 if request .status_code == 200 :
7171 return request .json ()
7272 else :
73- raise RuntimeError ('Query failed with code {}' . format ( request .status_code ) )
73+ raise RuntimeError (f 'Query failed with code { request .status_code } ' )
7474
7575
7676def query_contributions (
7777 token : Optional [str ],
7878 authors : List [str ],
7979 orgs : List [str ],
80+ repos : List [str ],
8081 since : datetime .date ,
8182 until : Optional [datetime .date ] = None ,
8283) -> List [dict ]:
8384 if until :
84- date_range = '{}..{}' . format ( since .isoformat (), until .isoformat ())
85+ date_range = f' { since .isoformat ()} .. { until .isoformat ()} '
8586 else :
86- date_range = '>={}' . format ( since .isoformat ())
87+ date_range = f '>={ since .isoformat ()} '
8788
8889 search_query = ' ' .join ([
8990 'sort:updated-desc' ,
9091 'is:pr is:merged' ,
91- ' ' .join (['author:{}' .format (a ) for a in authors ]),
92- ' ' .join (['org:{}' .format (o ) for o in orgs ]),
93- 'merged:{}' .format (date_range ),
92+ ' ' .join ([f'author:{ a } ' for a in authors ]),
93+ ' ' .join ([f'org:{ o } ' for o in orgs ]),
94+ ' ' .join ([f'repo:{ r } ' for r in repos ]),
95+ f'merged:{ date_range } ' ,
9496 ])
9597
9698 cursor = 'null'
@@ -128,7 +130,7 @@ def format_github_time_to_date(value: str) -> str:
128130def line_format_contribution (node : dict ) -> str :
129131 """Format an individual GitHub PR into our contribution line format."""
130132 title = node ['title' ]
131- author = node ['author' ][ 'name' ]
133+ author = node ['author' ]. get ( 'name' )
132134 link = node ['permalink' ]
133135 merged = format_github_time_to_date (node ['mergedAt' ])
134136 return f'[{ title } ]({ link } ) - { author } (merged { merged } )'
@@ -145,7 +147,8 @@ def line_format_contributions(
145147
146148 :returns: A list of markdown lines
147149 """
148- contrib_authors = set (node ['node' ]['author' ]['login' ] for node in contributions )
150+ contrib_authors = {node ['node' ].get ('author' , {}).get ('login' , 'None' ) for node in contributions }
151+ print (f'Authos: { contrib_authors } ' )
149152 lines = [
150153 '* By Authors: {}' .format (', ' .join (contrib_authors )),
151154 '* To Repositories in Organizations: {}' .format (', ' .join (orgs )), '' ,
@@ -159,12 +162,15 @@ def line_format_contributions(
159162 for contrib_json in contributions :
160163 node = contrib_json ['node' ]
161164 repo = node ['repository' ]['nameWithOwner' ]
165+ # skip bots
166+ if node ['author' ].get ('login' ) is None :
167+ continue
162168 byrepo .setdefault (repo , []).append (line_format_contribution (node ))
163169
164170 for repo , contribs in sorted (byrepo .items ()):
165- lines .append ('* {}' . format ( repo ) )
171+ lines .append (f '* { repo } ' )
166172 for contrib_str in contribs :
167- lines .append (' * {}' . format ( contrib_str ) )
173+ lines .append (f ' * { contrib_str } ' )
168174
169175 return lines
170176
@@ -215,6 +221,7 @@ class ContributionReportOptions(NamedTuple):
215221 until : Optional [datetime .date ]
216222 authors : List [str ]
217223 orgs : List [str ]
224+ repos : List [str ]
218225 token : str
219226 formatter : Callable
220227 render_html : bool
@@ -270,6 +277,12 @@ def parse_args(args=None) -> ContributionReportOptions:
270277 required = False ,
271278 default = [],
272279 help = 'Report contributions only to repos these github organizations' )
280+ parser .add_argument (
281+ '--repos' ,
282+ nargs = '+' ,
283+ required = False ,
284+ default = [],
285+ help = 'Report contributions to these specific repositories (in addition to --orgs)' )
273286 parser .add_argument (
274287 '-f' , '--format' ,
275288 type = str ,
@@ -288,9 +301,9 @@ def parse_args(args=None) -> ContributionReportOptions:
288301 parsed = parser .parse_args (args )
289302
290303 if not parsed .authors and not parsed .authors_from_org :
291- parser . error (
304+ print (
292305 'Neither --authors nor --authors-from-org specified, '
293- 'at least one is required to narrow the potentially huge search results .' )
306+ 'the results might be huge.. .' )
294307
295308 authors = all_authors (parsed .authors , parsed .authors_from_org , parsed .token )
296309
@@ -300,14 +313,15 @@ def parse_args(args=None) -> ContributionReportOptions:
300313 authors = authors ,
301314 token = parsed .token ,
302315 orgs = parsed .orgs ,
316+ repos = parsed .repos ,
303317 formatter = formatters [parsed .format ],
304318 render_html = parsed .render_html )
305319
306320
307321def main (args = None ):
308322 options = parse_args (args )
309323 contributions = query_contributions (
310- options .token , options .authors , options .orgs , options .since , options .until )
324+ options .token , options .authors , options .orgs , options .repos , options . since , options .until )
311325 lines = options .formatter (
312326 contributions , options .since , options .authors , options .orgs )
313327 md_content = '\n ' .join (lines )
0 commit comments