66import os
77from dataclasses import dataclass
88from pathlib import Path
9- from urllib . parse import urlparse
9+ from typing import Iterable
1010
1111
12- CONTRIBUTION_THRESHOLD = 15
13- IGDB_HOST = 'igdb.com'
14- TMDB_HOST = 'themoviedb.org'
15-
16- CATEGORY_BY_HOST_AND_PATH = {
17- (IGDB_HOST , 'games' ): 'games' ,
18- (IGDB_HOST , 'collections' ): 'game_collections' ,
19- (IGDB_HOST , 'franchises' ): 'game_franchises' ,
20- (TMDB_HOST , 'movie' ): 'movies' ,
21- (TMDB_HOST , 'collection' ): 'movie_collections' ,
22- (TMDB_HOST , 'tv' ): 'tv_shows' ,
23- }
12+ AUTO_APPROVED_USERS_FILE = 'auto_approved_users.json'
2413
2514
2615@dataclass (frozen = True )
@@ -32,169 +21,102 @@ class QueueEligibilityResult:
3221 ----------
3322 queue_eligible : bool
3423 Whether the submission should receive the queue label.
35- category : str
36- Database category derived from the submission URL.
37- contribution_count : int
38- Existing contribution count for the submitter in the derived category.
24+ user_id : str
25+ GitHub user id of the issue author.
3926 reason : str
4027 Machine-readable reason for the eligibility decision.
4128 """
4229
4330 queue_eligible : bool
44- category : str
45- contribution_count : int
31+ user_id : str
4632 reason : str
4733
4834
49- def get_submission_category ( database_url : str ) -> str :
35+ def normalize_user_id ( user_id : object ) -> str :
5036 """
51- Return the database category for a submission URL .
37+ Normalize a GitHub user id for matching .
5238
5339 Parameters
5440 ----------
55- database_url : str
56- Database URL from the issue submission .
41+ user_id : object
42+ GitHub user id to normalize .
5743
5844 Returns
5945 -------
6046 str
61- Top-level database category directory.
62-
63- Raises
64- ------
65- ValueError
66- If the URL cannot be mapped to a known database category.
67- """
68- parsed_url = urlparse (database_url .strip ())
69- hostname = parsed_url .hostname or ''
70- hostname = hostname .removeprefix ('www.' )
71- path_parts = [part for part in parsed_url .path .split ('/' ) if part ]
72-
73- if not path_parts :
74- raise ValueError (f'Unsupported database URL: { database_url } ' )
75-
76- category = CATEGORY_BY_HOST_AND_PATH .get ((hostname , path_parts [0 ]))
77- if not category :
78- raise ValueError (f'Unsupported database URL: { database_url } ' )
79-
80- return category
81-
82-
83- def get_contribution_count (contributor_data : dict , user_id : str ) -> int :
84- """
85- Return a contributor's total contributions from contributor metadata.
86-
87- Parameters
88- ----------
89- contributor_data : dict
90- Parsed contents of a category ``contributors.json`` file.
91- user_id : str
92- GitHub user ID to look up.
93-
94- Returns
95- -------
96- int
97- Sum of the contributor's added and edited item counts, or zero when the
98- metadata is missing or malformed.
47+ Trimmed user id string.
9948 """
100- if not isinstance ( contributor_data , dict ) :
101- return 0
49+ if user_id is None :
50+ return ''
10251
103- contributor = contributor_data .get (str (user_id ), {})
104- if not isinstance (contributor , dict ):
105- return 0
52+ return str (user_id ).strip ()
10653
107- try :
108- return int (contributor .get ('items_added' , 0 )) + int (contributor .get ('items_edited' , 0 ))
109- except (TypeError , ValueError ):
110- return 0
11154
112-
113- def load_contribution_count (database_root : Path , category : str , user_id : str ) -> int :
55+ def load_auto_approved_user_ids (auto_approved_users_file : Path ) -> frozenset [str ]:
11456 """
115- Load a contributor's category contribution count from disk .
57+ Load auto-approved GitHub user ids from a JSON file .
11658
11759 Parameters
11860 ----------
119- database_root : pathlib.Path
120- Root directory containing category database folders.
121- category : str
122- Category directory to inspect.
123- user_id : str
124- GitHub user ID to look up.
61+ auto_approved_users_file : pathlib.Path
62+ JSON file containing auto-approved user objects.
12563
12664 Returns
12765 -------
128- int
129- Contributor count for the category, or zero when the contributors file
130- is absent or unreadable.
66+ frozenset[str]
67+ Normalized GitHub user ids.
13168 """
132- contributors_file = database_root / category / 'contributors.json'
133- if not contributors_file .exists ():
134- return 0
135-
13669 try :
137- with contributors_file .open () as contributor_f :
138- contributor_data = json .load (contributor_f )
70+ with auto_approved_users_file .open (encoding = 'utf-8' ) as auto_approved_users_f :
71+ auto_approved_users = json .load (auto_approved_users_f )
13972 except (OSError , json .JSONDecodeError ):
140- return 0
73+ return frozenset ()
74+
75+ if not isinstance (auto_approved_users , list ):
76+ return frozenset ()
14177
142- return get_contribution_count (contributor_data = contributor_data , user_id = user_id )
78+ return frozenset (
79+ normalized_user_id
80+ for user in auto_approved_users
81+ if isinstance (user , dict )
82+ if (normalized_user_id := normalize_user_id (user .get ('user_id' , '' )))
83+ )
14384
14485
145- def evaluate_queue_eligibility (submission : dict ,
146- database_root : Path ,
147- user_id : str ,
148- threshold : int = CONTRIBUTION_THRESHOLD ) -> QueueEligibilityResult :
86+ def evaluate_queue_eligibility (user_id : object ,
87+ auto_approved_user_ids : Iterable [object ]) -> QueueEligibilityResult :
14988 """
15089 Evaluate whether a submission is eligible to be queued automatically.
15190
15291 Parameters
15392 ----------
154- submission : dict
155- Parsed issue submission data.
156- database_root : pathlib.Path
157- Root directory containing category database folders.
158- user_id : str
159- GitHub user ID of the issue author.
160- threshold : int, optional
161- Minimum prior category contribution count that must be exceeded.
93+ user_id : object
94+ GitHub user id of the issue author.
95+ auto_approved_user_ids : Iterable[object]
96+ GitHub user ids eligible for automatic queueing.
16297
16398 Returns
16499 -------
165100 QueueEligibilityResult
166101 Eligibility decision and supporting metadata.
167102 """
168- if not user_id :
103+ normalized_user_id = normalize_user_id (user_id = user_id )
104+ if not normalized_user_id :
169105 return QueueEligibilityResult (
170106 queue_eligible = False ,
171- category = '' ,
172- contribution_count = 0 ,
107+ user_id = '' ,
173108 reason = 'missing-user-id' ,
174109 )
175110
176- try :
177- category = get_submission_category (database_url = submission ['database_url' ])
178- except (KeyError , ValueError ):
179- return QueueEligibilityResult (
180- queue_eligible = False ,
181- category = '' ,
182- contribution_count = 0 ,
183- reason = 'unsupported-category' ,
184- )
185-
186- contribution_count = load_contribution_count (
187- database_root = database_root ,
188- category = category ,
189- user_id = user_id ,
190- )
191- queue_eligible = contribution_count > threshold
192- reason = 'eligible' if queue_eligible else 'below-threshold'
111+ queue_eligible = normalized_user_id in {
112+ normalize_user_id (user_id = auto_approved_user_id )
113+ for auto_approved_user_id in auto_approved_user_ids
114+ }
115+ reason = 'auto-approved-user' if queue_eligible else 'not-auto-approved-user'
193116
194117 return QueueEligibilityResult (
195118 queue_eligible = queue_eligible ,
196- category = category ,
197- contribution_count = contribution_count ,
119+ user_id = normalized_user_id ,
198120 reason = reason ,
199121 )
200122
@@ -214,8 +136,7 @@ def write_github_outputs(result: QueueEligibilityResult) -> None:
214136 """
215137 outputs = {
216138 'queue_eligible' : str (result .queue_eligible ).lower (),
217- 'category' : result .category ,
218- 'contribution_count' : str (result .contribution_count ),
139+ 'user_id' : result .user_id ,
219140 'reason' : result .reason ,
220141 }
221142 output_lines = [f'{ key } ={ value } ' for key , value in outputs .items ()]
@@ -239,9 +160,7 @@ def parse_args() -> argparse.Namespace:
239160 Parsed command-line arguments.
240161 """
241162 parser = argparse .ArgumentParser (description = 'Check whether a submission is eligible for queueing.' )
242- parser .add_argument ('--submission-file' , default = 'submission.json' )
243- parser .add_argument ('--database-root' , default = 'database' )
244- parser .add_argument ('--threshold' , type = int , default = CONTRIBUTION_THRESHOLD )
163+ parser .add_argument ('--auto-approved-users-file' , default = AUTO_APPROVED_USERS_FILE )
245164 parser .add_argument ('--user-id' , default = os .environ .get ('ISSUE_AUTHOR_USER_ID' , '' ))
246165 return parser .parse_args ()
247166
@@ -255,24 +174,13 @@ def main() -> None:
255174 None
256175 """
257176 args = parse_args ()
258-
259- try :
260- with open (args .submission_file ) as submission_f :
261- submission = json .load (submission_f )
262- except (OSError , json .JSONDecodeError ):
263- result = QueueEligibilityResult (
264- queue_eligible = False ,
265- category = '' ,
266- contribution_count = 0 ,
267- reason = 'submission-read-error' ,
268- )
269- else :
270- result = evaluate_queue_eligibility (
271- submission = submission ,
272- database_root = Path (args .database_root ),
273- user_id = args .user_id ,
274- threshold = args .threshold ,
275- )
177+ auto_approved_user_ids = load_auto_approved_user_ids (
178+ auto_approved_users_file = Path (args .auto_approved_users_file ),
179+ )
180+ result = evaluate_queue_eligibility (
181+ user_id = args .user_id ,
182+ auto_approved_user_ids = auto_approved_user_ids ,
183+ )
276184 write_github_outputs (result = result )
277185
278186
0 commit comments