summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGavin Mak <gavinmak@google.com>2025-08-13 23:42:00 -0700
committerLUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2025-08-14 09:54:15 -0700
commitd534a5537fd317cd769fed54eceb8248777db701 (patch)
tree2c036f9540f0eb723ab48ba28549758033ecc269
parenta64149a7a77814132629bbb4c07d922c2222df25 (diff)
downloadgit-repo-d534a5537fd317cd769fed54eceb8248777db701.tar.gz
sync: Fix missing error details in interleaved summary
When checkout errors occurred in interleaved sync, they were wrapped in a SyncError with no message, causing blank lines in the final summary. Refactor _SyncResult to hold a list of exceptions, ensuring the original error messages are propagated correctly. Bug: 438178765 Change-Id: Ic25e515068959829cb6290cfd9e4c2d3963bbbea Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/498342 Reviewed-by: Scott Lee <ddoman@google.com> Tested-by: Gavin Mak <gavinmak@google.com> Commit-Queue: Gavin Mak <gavinmak@google.com>
-rw-r--r--subcmds/sync.py42
-rw-r--r--tests/test_subcmds_sync.py14
2 files changed, 27 insertions, 29 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py
index ed2e516a..582bd057 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -204,14 +204,13 @@ class _SyncResult(NamedTuple):
204 relpath (str): The project's relative path from the repo client top. 204 relpath (str): The project's relative path from the repo client top.
205 remote_fetched (bool): True if the remote was actually queried. 205 remote_fetched (bool): True if the remote was actually queried.
206 fetch_success (bool): True if the fetch operation was successful. 206 fetch_success (bool): True if the fetch operation was successful.
207 fetch_error (Optional[Exception]): The Exception from a failed fetch, 207 fetch_errors (List[Exception]): The Exceptions from a failed fetch.
208 or None.
209 fetch_start (Optional[float]): The time.time() when fetch started. 208 fetch_start (Optional[float]): The time.time() when fetch started.
210 fetch_finish (Optional[float]): The time.time() when fetch finished. 209 fetch_finish (Optional[float]): The time.time() when fetch finished.
211 checkout_success (bool): True if the checkout operation was 210 checkout_success (bool): True if the checkout operation was
212 successful. 211 successful.
213 checkout_error (Optional[Exception]): The Exception from a failed 212 checkout_errors (List[Exception]): The Exceptions from a failed
214 checkout, or None. 213 checkout.
215 checkout_start (Optional[float]): The time.time() when checkout 214 checkout_start (Optional[float]): The time.time() when checkout
216 started. 215 started.
217 checkout_finish (Optional[float]): The time.time() when checkout 216 checkout_finish (Optional[float]): The time.time() when checkout
@@ -224,12 +223,12 @@ class _SyncResult(NamedTuple):
224 223
225 remote_fetched: bool 224 remote_fetched: bool
226 fetch_success: bool 225 fetch_success: bool
227 fetch_error: Optional[Exception] 226 fetch_errors: List[Exception]
228 fetch_start: Optional[float] 227 fetch_start: Optional[float]
229 fetch_finish: Optional[float] 228 fetch_finish: Optional[float]
230 229
231 checkout_success: bool 230 checkout_success: bool
232 checkout_error: Optional[Exception] 231 checkout_errors: List[Exception]
233 checkout_start: Optional[float] 232 checkout_start: Optional[float]
234 checkout_finish: Optional[float] 233 checkout_finish: Optional[float]
235 234
@@ -2210,7 +2209,7 @@ later is required to fix a server side protocol bug.
2210 """Syncs a single project for interleaved sync.""" 2209 """Syncs a single project for interleaved sync."""
2211 fetch_success = False 2210 fetch_success = False
2212 remote_fetched = False 2211 remote_fetched = False
2213 fetch_error = None 2212 fetch_errors = []
2214 fetch_start = None 2213 fetch_start = None
2215 fetch_finish = None 2214 fetch_finish = None
2216 network_output = "" 2215 network_output = ""
@@ -2243,16 +2242,17 @@ later is required to fix a server side protocol bug.
2243 ) 2242 )
2244 fetch_success = sync_result.success 2243 fetch_success = sync_result.success
2245 remote_fetched = sync_result.remote_fetched 2244 remote_fetched = sync_result.remote_fetched
2246 fetch_error = sync_result.error 2245 if sync_result.error:
2246 fetch_errors.append(sync_result.error)
2247 except KeyboardInterrupt: 2247 except KeyboardInterrupt:
2248 logger.error( 2248 logger.error(
2249 "Keyboard interrupt while processing %s", project.name 2249 "Keyboard interrupt while processing %s", project.name
2250 ) 2250 )
2251 except GitError as e: 2251 except GitError as e:
2252 fetch_error = e 2252 fetch_errors.append(e)
2253 logger.error("error.GitError: Cannot fetch %s", e) 2253 logger.error("error.GitError: Cannot fetch %s", e)
2254 except Exception as e: 2254 except Exception as e:
2255 fetch_error = e 2255 fetch_errors.append(e)
2256 logger.error( 2256 logger.error(
2257 "error: Cannot fetch %s (%s: %s)", 2257 "error: Cannot fetch %s (%s: %s)",
2258 project.name, 2258 project.name,
@@ -2264,7 +2264,7 @@ later is required to fix a server side protocol bug.
2264 network_output = network_output_capture.getvalue() 2264 network_output = network_output_capture.getvalue()
2265 2265
2266 checkout_success = False 2266 checkout_success = False
2267 checkout_error = None 2267 checkout_errors = []
2268 checkout_start = None 2268 checkout_start = None
2269 checkout_finish = None 2269 checkout_finish = None
2270 checkout_stderr = "" 2270 checkout_stderr = ""
@@ -2293,22 +2293,20 @@ later is required to fix a server side protocol bug.
2293 ) 2293 )
2294 checkout_success = syncbuf.Finish() 2294 checkout_success = syncbuf.Finish()
2295 if syncbuf.errors: 2295 if syncbuf.errors:
2296 checkout_error = SyncError( 2296 checkout_errors.extend(syncbuf.errors)
2297 aggregate_errors=syncbuf.errors
2298 )
2299 except KeyboardInterrupt: 2297 except KeyboardInterrupt:
2300 logger.error( 2298 logger.error(
2301 "Keyboard interrupt while processing %s", project.name 2299 "Keyboard interrupt while processing %s", project.name
2302 ) 2300 )
2303 except GitError as e: 2301 except GitError as e:
2304 checkout_error = e 2302 checkout_errors.append(e)
2305 logger.error( 2303 logger.error(
2306 "error.GitError: Cannot checkout %s: %s", 2304 "error.GitError: Cannot checkout %s: %s",
2307 project.name, 2305 project.name,
2308 e, 2306 e,
2309 ) 2307 )
2310 except Exception as e: 2308 except Exception as e:
2311 checkout_error = e 2309 checkout_errors.append(e)
2312 logger.error( 2310 logger.error(
2313 "error: Cannot checkout %s: %s: %s", 2311 "error: Cannot checkout %s: %s: %s",
2314 project.name, 2312 project.name,
@@ -2333,8 +2331,8 @@ later is required to fix a server side protocol bug.
2333 fetch_success=fetch_success, 2331 fetch_success=fetch_success,
2334 remote_fetched=remote_fetched, 2332 remote_fetched=remote_fetched,
2335 checkout_success=checkout_success, 2333 checkout_success=checkout_success,
2336 fetch_error=fetch_error, 2334 fetch_errors=fetch_errors,
2337 checkout_error=checkout_error, 2335 checkout_errors=checkout_errors,
2338 stderr_text=stderr_text.strip(), 2336 stderr_text=stderr_text.strip(),
2339 fetch_start=fetch_start, 2337 fetch_start=fetch_start,
2340 fetch_finish=fetch_finish, 2338 fetch_finish=fetch_finish,
@@ -2429,14 +2427,14 @@ later is required to fix a server side protocol bug.
2429 if not success: 2427 if not success:
2430 ret = False 2428 ret = False
2431 err_event.set() 2429 err_event.set()
2432 if result.fetch_error: 2430 if result.fetch_errors:
2433 errors.append(result.fetch_error) 2431 errors.extend(result.fetch_errors)
2434 self._interleaved_err_network = True 2432 self._interleaved_err_network = True
2435 self._interleaved_err_network_results.append( 2433 self._interleaved_err_network_results.append(
2436 result.relpath 2434 result.relpath
2437 ) 2435 )
2438 if result.checkout_error: 2436 if result.checkout_errors:
2439 errors.append(result.checkout_error) 2437 errors.extend(result.checkout_errors)
2440 self._interleaved_err_checkout = True 2438 self._interleaved_err_checkout = True
2441 self._interleaved_err_checkout_results.append( 2439 self._interleaved_err_checkout_results.append(
2442 result.relpath 2440 result.relpath
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py
index 940c69fc..6c9cc9ab 100644
--- a/tests/test_subcmds_sync.py
+++ b/tests/test_subcmds_sync.py
@@ -810,8 +810,8 @@ class InterleavedSyncTest(unittest.TestCase):
810 result = result_obj.results[0] 810 result = result_obj.results[0]
811 self.assertTrue(result.fetch_success) 811 self.assertTrue(result.fetch_success)
812 self.assertTrue(result.checkout_success) 812 self.assertTrue(result.checkout_success)
813 self.assertIsNone(result.fetch_error) 813 self.assertEqual(result.fetch_errors, [])
814 self.assertIsNone(result.checkout_error) 814 self.assertEqual(result.checkout_errors, [])
815 project.Sync_NetworkHalf.assert_called_once() 815 project.Sync_NetworkHalf.assert_called_once()
816 project.Sync_LocalHalf.assert_called_once() 816 project.Sync_LocalHalf.assert_called_once()
817 817
@@ -833,8 +833,8 @@ class InterleavedSyncTest(unittest.TestCase):
833 833
834 self.assertFalse(result.fetch_success) 834 self.assertFalse(result.fetch_success)
835 self.assertFalse(result.checkout_success) 835 self.assertFalse(result.checkout_success)
836 self.assertEqual(result.fetch_error, fetch_error) 836 self.assertEqual(result.fetch_errors, [fetch_error])
837 self.assertIsNone(result.checkout_error) 837 self.assertEqual(result.checkout_errors, [])
838 project.Sync_NetworkHalf.assert_called_once() 838 project.Sync_NetworkHalf.assert_called_once()
839 project.Sync_LocalHalf.assert_not_called() 839 project.Sync_LocalHalf.assert_not_called()
840 840
@@ -871,7 +871,7 @@ class InterleavedSyncTest(unittest.TestCase):
871 871
872 self.assertFalse(result.fetch_success) 872 self.assertFalse(result.fetch_success)
873 self.assertFalse(result.checkout_success) 873 self.assertFalse(result.checkout_success)
874 self.assertEqual(result.fetch_error, fetch_error) 874 self.assertEqual(result.fetch_errors, [fetch_error])
875 project.Sync_NetworkHalf.assert_called_once() 875 project.Sync_NetworkHalf.assert_called_once()
876 project.Sync_LocalHalf.assert_not_called() 876 project.Sync_LocalHalf.assert_not_called()
877 877
@@ -893,8 +893,8 @@ class InterleavedSyncTest(unittest.TestCase):
893 893
894 self.assertTrue(result.fetch_success) 894 self.assertTrue(result.fetch_success)
895 self.assertFalse(result.checkout_success) 895 self.assertFalse(result.checkout_success)
896 self.assertIsNone(result.fetch_error) 896 self.assertEqual(result.fetch_errors, [])
897 self.assertEqual(result.checkout_error, checkout_error) 897 self.assertEqual(result.checkout_errors, [checkout_error])
898 project.Sync_NetworkHalf.assert_called_once() 898 project.Sync_NetworkHalf.assert_called_once()
899 project.Sync_LocalHalf.assert_called_once() 899 project.Sync_LocalHalf.assert_called_once()
900 900