1212from ci_tools .variables import in_ci
1313from ci_tools .scenario .generation import build_whl_for_req
1414from ci_tools .logging import configure_logging , logger
15- from ci_tools .environment_exclusions import is_check_enabled
15+ from ci_tools .environment_exclusions import is_check_enabled , CHECK_DEFAULTS
1616
1717root_dir = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." ))
1818
19+
1920@dataclass
2021class CheckResult :
2122 package : str
@@ -26,7 +27,14 @@ class CheckResult:
2627 stderr : str
2728
2829
29- async def run_check (semaphore : asyncio .Semaphore , package : str , check : str , base_args : List [str ], idx : int , total : int ) -> CheckResult :
30+ async def run_check (
31+ semaphore : asyncio .Semaphore ,
32+ package : str ,
33+ check : str ,
34+ base_args : List [str ],
35+ idx : int ,
36+ total : int ,
37+ ) -> CheckResult :
3038 """Run a single check (subprocess) within a concurrency semaphore, capturing output and timing.
3139
3240 :param semaphore: Concurrency limiter used to bound concurrent checks.
@@ -65,7 +73,9 @@ async def run_check(semaphore: asyncio.Semaphore, package: str, check: str, base
6573 stderr = stderr_b .decode (errors = "replace" )
6674 exit_code = proc .returncode or 0
6775 status = "OK" if exit_code == 0 else f"FAIL({ exit_code } )"
68- logger .info (f"[END { idx } /{ total } ] { check } :: { package } -> { status } in { duration :.2f} s" )
76+ logger .info (
77+ f"[END { idx } /{ total } ] { check } :: { package } -> { status } in { duration :.2f} s"
78+ )
6979 # Print captured output after completion to avoid interleaving
7080 header = f"===== OUTPUT: { check } :: { package } (exit { exit_code } ) ====="
7181 trailer = "=" * len (header )
@@ -74,7 +84,7 @@ async def run_check(semaphore: asyncio.Semaphore, package: str, check: str, base
7484 print (stdout .rstrip ())
7585 print (trailer )
7686 if stderr :
77- print (header .replace (' OUTPUT' , ' STDERR' ))
87+ print (header .replace (" OUTPUT" , " STDERR" ))
7888 print (stderr .rstrip ())
7989 print (trailer )
8090
@@ -86,7 +96,9 @@ async def run_check(semaphore: asyncio.Semaphore, package: str, check: str, base
8696 try :
8797 shutil .rmtree (isolate_dir )
8898 except :
89- logger .warning (f"Failed to remove isolate dir { isolate_dir } for { package } / { check } " )
99+ logger .warning (
100+ f"Failed to remove isolate dir { isolate_dir } for { package } / { check } "
101+ )
90102 return CheckResult (package , check , exit_code , duration , stdout , stderr )
91103
92104
@@ -110,10 +122,14 @@ def summarize(results: List[CheckResult]) -> int:
110122 print ("-" * len (header ))
111123 for r in sorted (results , key = lambda x : (x .exit_code != 0 , x .package , x .check )):
112124 status = "OK" if r .exit_code == 0 else f"FAIL({ r .exit_code } )"
113- print (f"{ r .package .ljust (pkg_w )} { r .check .ljust (chk_w )} { status .ljust (8 )} { r .duration :>10.2f} " )
125+ print (
126+ f"{ r .package .ljust (pkg_w )} { r .check .ljust (chk_w )} { status .ljust (8 )} { r .duration :>10.2f} "
127+ )
114128 worst = max ((r .exit_code for r in results ), default = 0 )
115129 failed = [r for r in results if r .exit_code != 0 ]
116- print (f"\n Total checks: { len (results )} | Failed: { len (failed )} | Worst exit code: { worst } " )
130+ print (
131+ f"\n Total checks: { len (results )} | Failed: { len (failed )} | Worst exit code: { worst } "
132+ )
117133 return worst
118134
119135
@@ -135,10 +151,16 @@ async def run_all_checks(packages, checks, max_parallel):
135151 combos = [(p , c ) for p in packages for c in checks ]
136152 total = len (combos )
137153 for idx , (package , check ) in enumerate (combos , start = 1 ):
138- if not is_check_enabled (package , check ):
139- logger .warning (f"Skipping disabled check { check } ({ idx } /{ total } ) for package { package } " )
154+ if not is_check_enabled (package , check , CHECK_DEFAULTS .get (check , True )):
155+ logger .warning (
156+ f"Skipping disabled check { check } ({ idx } /{ total } ) for package { package } "
157+ )
140158 continue
141- tasks .append (asyncio .create_task (run_check (semaphore , package , check , base_args , idx , total )))
159+ tasks .append (
160+ asyncio .create_task (
161+ run_check (semaphore , package , check , base_args , idx , total )
162+ )
163+ )
142164
143165 # Handle Ctrl+C gracefully
144166 pending = set (tasks )
@@ -157,7 +179,9 @@ async def run_all_checks(packages, checks, max_parallel):
157179 elif isinstance (res , Exception ):
158180 norm_results .append (CheckResult (package , check , 99 , 0.0 , "" , str (res )))
159181 else :
160- norm_results .append (CheckResult (package , check , 98 , 0.0 , "" , f"Unknown result type: { res } " ))
182+ norm_results .append (
183+ CheckResult (package , check , 98 , 0.0 , "" , f"Unknown result type: { res } " )
184+ )
161185 return summarize (norm_results )
162186
163187
@@ -233,11 +257,15 @@ def handler(signum, frame):
233257 ),
234258 )
235259
236- parser .add_argument ("--disablecov" , help = ("Flag. Disables code coverage." ), action = "store_true" )
260+ parser .add_argument (
261+ "--disablecov" , help = ("Flag. Disables code coverage." ), action = "store_true"
262+ )
237263
238264 parser .add_argument (
239265 "--service" ,
240- help = ("Name of service directory (under sdk/) to test. Example: --service applicationinsights" ),
266+ help = (
267+ "Name of service directory (under sdk/) to test. Example: --service applicationinsights"
268+ ),
241269 )
242270
243271 parser .add_argument (
@@ -297,7 +325,9 @@ def handler(signum, frame):
297325 else :
298326 target_dir = root_dir
299327
300- logger .info (f"Beginning discovery for { args .service } and root dir { root_dir } . Resolving to { target_dir } ." )
328+ logger .info (
329+ f"Beginning discovery for { args .service } and root dir { root_dir } . Resolving to { target_dir } ."
330+ )
301331
302332 # ensure that recursive virtual envs aren't messed with by this call
303333 os .environ .pop ("VIRTUAL_ENV" , None )
@@ -314,7 +344,9 @@ def handler(signum, frame):
314344 )
315345
316346 if len (targeted_packages ) == 0 :
317- logger .info (f"No packages collected for targeting string { args .glob_string } and root dir { root_dir } . Exit 0." )
347+ logger .info (
348+ f"No packages collected for targeting string { args .glob_string } and root dir { root_dir } . Exit 0."
349+ )
318350 exit (0 )
319351
320352 logger .info (f"Executing checks with the executable { sys .executable } ." )
@@ -329,7 +361,9 @@ def handler(signum, frame):
329361 if in_ci ():
330362 # prepare a build of eng/tools/azure-sdk-tools
331363 # todo: ensure that we honor this .wheels directory when replacing for dev reqs
332- build_whl_for_req ("eng/tools/azure-sdk-tools" , root_dir , os .path .join (root_dir , ".wheels" ))
364+ build_whl_for_req (
365+ "eng/tools/azure-sdk-tools" , root_dir , os .path .join (root_dir , ".wheels" )
366+ )
333367
334368 # so if we have checks whl,import_all and selected package paths `sdk/core/azure-core`, `sdk/storage/azure-storage-blob` we should
335369 # shell out to `azypysdk <checkname>` with cwd of the package directory, which is what is in `targeted_packages` array
@@ -342,11 +376,15 @@ def handler(signum, frame):
342376 logger .error ("No valid checks provided via -c/--checks." )
343377 sys .exit (2 )
344378
345- logger .info (f"Running { len (checks )} check(s) across { len (targeted_packages )} packages (max_parallel={ args .max_parallel } )." )
379+ logger .info (
380+ f"Running { len (checks )} check(s) across { len (targeted_packages )} packages (max_parallel={ args .max_parallel } )."
381+ )
346382
347383 configure_interrupt_handling ()
348384 try :
349- exit_code = asyncio .run (run_all_checks (targeted_packages , checks , args .max_parallel ))
385+ exit_code = asyncio .run (
386+ run_all_checks (targeted_packages , checks , args .max_parallel )
387+ )
350388 except KeyboardInterrupt :
351389 logger .error ("Aborted by user." )
352390 exit_code = 130
0 commit comments