Skip to content

Commit 79e2f33

Browse files
committed
air: upload: try to wait for builder with the AI reviews
Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 520432e commit 79e2f33

File tree

1 file changed

+87
-21
lines changed

1 file changed

+87
-21
lines changed

nipa-air-upload.py

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,62 @@
2121
from pw import Patchwork
2222

2323

24+
class PatchworkSeries:
25+
"""Represents a Patchwork series with its patches"""
26+
27+
def __init__(self, patchwork: Patchwork, series_id: int, check_name: str):
28+
"""Initialize series
29+
30+
Args:
31+
patchwork: Patchwork client
32+
series_id: Series ID
33+
check_name: Check name to look for
34+
"""
35+
self.patchwork = patchwork
36+
self.series_id = series_id
37+
self.check_name = check_name
38+
self.series_data = None
39+
self.patches = []
40+
self.patches_ready = []
41+
42+
# Fetch series and patch data
43+
self._fetch()
44+
45+
def _fetch(self):
46+
"""Fetch series and check which patches are ready"""
47+
self.series_data = self.patchwork.get('series', self.series_id)
48+
self.patches = self.series_data.get('patches', [])
49+
50+
# Check each patch for existing check
51+
self.patches_ready = []
52+
for i, patch in enumerate(self.patches):
53+
patch_id = patch['id']
54+
try:
55+
# Fetch checks for this patch
56+
existing_checks = self.patchwork.get_all(f'patches/{patch_id}/checks')
57+
check_exists = any(c.get('context') == self.check_name for c in existing_checks)
58+
self.patches_ready.append(check_exists)
59+
except Exception as e:
60+
print(f" Warning: Error fetching checks for patch {i+1} (id={patch_id}): {e}")
61+
self.patches_ready.append(False)
62+
63+
def all_patches_ready(self) -> bool:
64+
"""Check if all patches have the check entry
65+
66+
Returns:
67+
True if all patches have the check entry
68+
"""
69+
return all(self.patches_ready)
70+
71+
def ready_count(self) -> int:
72+
"""Get count of patches that are ready
73+
74+
Returns:
75+
Number of patches with check entry
76+
"""
77+
return sum(self.patches_ready)
78+
79+
2480
class AirPatchworkSync:
2581
"""Synchronize AIR reviews to Patchwork checks"""
2682

@@ -132,12 +188,12 @@ def get_review_details(self, review_id: str) -> Optional[Dict]:
132188
print(f"Error fetching review {review_id}: {e}")
133189
return None
134190

135-
def post_patchwork_check(self, series_id: int, review_id: str,
191+
def post_patchwork_check(self, pw_series: PatchworkSeries, review_id: str,
136192
review_data: Dict) -> bool:
137193
"""Post check result to Patchwork
138194
139195
Args:
140-
series_id: Patchwork series ID
196+
pw_series: PatchworkSeries object with patches
141197
review_id: AIR review ID
142198
review_data: Review data with 'review' field containing per-patch results
143199
@@ -147,22 +203,14 @@ def post_patchwork_check(self, series_id: int, review_id: str,
147203
# Build check URL
148204
check_url = f"{self.air_server}/ai-review.html?id={review_id}"
149205

150-
try:
151-
# Fetch series to get individual patches
152-
series = self.patchwork.get('series', series_id)
153-
patches = series.get('patches', [])
154-
155-
if not patches:
156-
print(f" Warning: Series {series_id} has no patches")
157-
return False
206+
# Get review results (one per patch)
207+
reviews = review_data.get('review', [])
158208

159-
# Get review results (one per patch)
160-
reviews = review_data.get('review', [])
161-
162-
print(f" Posting checks to {len(patches)} patches in series {series_id}")
209+
print(f" Posting checks to {len(pw_series.patches)} patches in series {pw_series.series_id}")
163210

211+
try:
164212
# Post check to each patch in the series
165-
for i, patch in enumerate(patches):
213+
for i, patch in enumerate(pw_series.patches):
166214
patch_id = patch['id']
167215

168216
# Check if this patch has review comments
@@ -174,7 +222,7 @@ def post_patchwork_check(self, series_id: int, review_id: str,
174222
state = 'warning' if patch_has_comments else 'success'
175223
desc = 'AI review found issues' if patch_has_comments else 'AI review completed'
176224

177-
print(f" Patch {i+1}/{len(patches)} (id={patch_id}): {state}")
225+
print(f" Patch {i+1}/{len(pw_series.patches)} (id={patch_id}): {state}")
178226

179227
self.patchwork.post_check(patch=patch_id, name=self.check_name,
180228
state=state, url=check_url, desc=desc)
@@ -191,7 +239,7 @@ def process_review(self, review: Dict) -> bool:
191239
review: Review summary from AIR
192240
193241
Returns:
194-
True if processed (whether matched or not)
242+
True if processed successfully (checks posted to all patches)
195243
"""
196244
review_id = review.get('review_id')
197245
status = review.get('status')
@@ -217,13 +265,31 @@ def process_review(self, review: Dict) -> bool:
217265

218266
print(f" Patchwork series ID: {pw_series_id}")
219267

220-
# Post check to Patchwork (will check each patch individually)
221-
success = self.post_patchwork_check(pw_series_id, review_id, review_data)
268+
# Fetch series and check if patches are ready
269+
try:
270+
pw_series = PatchworkSeries(self.patchwork, pw_series_id, self.check_name)
271+
except Exception as e:
272+
print(f" Error fetching series: {e}")
273+
return False
274+
275+
if not pw_series.patches:
276+
print(f" Warning: Series has no patches")
277+
return True
278+
279+
# Check if all patches have the check entry (prevents race with initial scan)
280+
if not pw_series.all_patches_ready():
281+
ready = pw_series.ready_count()
282+
total = len(pw_series.patches)
283+
print(f" Not ready: only {ready}/{total} patches have check '{self.check_name}' (will retry later)")
284+
return False
285+
286+
# Post check to Patchwork
287+
success = self.post_patchwork_check(pw_series, review_id, review_data)
222288

223289
if success:
224-
print(f" Successfully posted check to Patchwork")
290+
print(f" Successfully posted checks to all patches")
225291

226-
return True
292+
return success
227293

228294
def run_once(self):
229295
"""Run one sync iteration"""

0 commit comments

Comments
 (0)