1010
1111from ci_tools .functions import discover_targeted_packages
1212from ci_tools .variables import in_ci
13- from ci_tools .scenario .generation import build_whl_for_req
13+ from ci_tools .scenario .generation import build_whl_for_req , replace_dev_reqs
1414from ci_tools .logging import configure_logging , logger
1515from ci_tools .environment_exclusions import is_check_enabled , CHECK_DEFAULTS
1616
@@ -73,9 +73,7 @@ async def run_check(
7373 stderr = stderr_b .decode (errors = "replace" )
7474 exit_code = proc .returncode or 0
7575 status = "OK" if exit_code == 0 else f"FAIL({ exit_code } )"
76- logger .info (
77- f"[END { idx } /{ total } ] { check } :: { package } -> { status } in { duration :.2f} s"
78- )
76+ logger .info (f"[END { idx } /{ total } ] { check } :: { package } -> { status } in { duration :.2f} s" )
7977 # Print captured output after completion to avoid interleaving
8078 header = f"===== OUTPUT: { check } :: { package } (exit { exit_code } ) ====="
8179 trailer = "=" * len (header )
@@ -96,9 +94,7 @@ async def run_check(
9694 try :
9795 shutil .rmtree (isolate_dir )
9896 except :
99- logger .warning (
100- f"Failed to remove isolate dir { isolate_dir } for { package } / { check } "
101- )
97+ logger .warning (f"Failed to remove isolate dir { isolate_dir } for { package } / { check } " )
10298 return CheckResult (package , check , exit_code , duration , stdout , stderr )
10399
104100
@@ -122,18 +118,14 @@ def summarize(results: List[CheckResult]) -> int:
122118 print ("-" * len (header ))
123119 for r in sorted (results , key = lambda x : (x .exit_code != 0 , x .package , x .check )):
124120 status = "OK" if r .exit_code == 0 else f"FAIL({ r .exit_code } )"
125- print (
126- f"{ r .package .ljust (pkg_w )} { r .check .ljust (chk_w )} { status .ljust (8 )} { r .duration :>10.2f} "
127- )
121+ print (f"{ r .package .ljust (pkg_w )} { r .check .ljust (chk_w )} { status .ljust (8 )} { r .duration :>10.2f} " )
128122 worst = max ((r .exit_code for r in results ), default = 0 )
129123 failed = [r for r in results if r .exit_code != 0 ]
130- print (
131- f"\n Total checks: { len (results )} | Failed: { len (failed )} | Worst exit code: { worst } "
132- )
124+ print (f"\n Total checks: { len (results )} | Failed: { len (failed )} | Worst exit code: { worst } " )
133125 return worst
134126
135127
136- async def run_all_checks (packages , checks , max_parallel ):
128+ async def run_all_checks (packages , checks , max_parallel , wheel_dir ):
137129 """Run all checks for all packages concurrently and return the worst exit code.
138130
139131 :param packages: Iterable of package paths to run checks against.
@@ -142,6 +134,9 @@ async def run_all_checks(packages, checks, max_parallel):
142134 :type checks: List[str]
143135 :param max_parallel: Maximum number of concurrent checks to run.
144136 :type max_parallel: int
137+ :param wheel_dir: The directory where wheels should be located and stored when built.
138+ In CI should correspond to `$(Build.ArtifactStagingDirectory)`.
139+ :type wheel_dir: str
145140 :returns: The worst exit code from all checks (0 if all passed).
146141 :rtype: int
147142 """
@@ -150,17 +145,33 @@ async def run_all_checks(packages, checks, max_parallel):
150145 semaphore = asyncio .Semaphore (max_parallel )
151146 combos = [(p , c ) for p in packages for c in checks ]
152147 total = len (combos )
148+
149+ test_tools_path = os .path .join (root_dir , "eng" , "test_tools.txt" )
150+ dependency_tools_path = os .path .join (root_dir , "eng" , "dependency_tools.txt" )
151+
152+ if in_ci ():
153+ logger .info ("Replacing relative requirements in eng/test_tools.txt with prebuilt wheels." )
154+ replace_dev_reqs (test_tools_path , root_dir , wheel_dir )
155+
156+ logger .info ("Replacing relative requirements in eng/dependency_tools.txt with prebuilt wheels." )
157+ replace_dev_reqs (dependency_tools_path , root_dir , wheel_dir )
158+
159+ for pkg in packages :
160+ destination_dev_req = os .path .join (pkg , "dev_requirements.txt" )
161+
162+ logger .info (f"Replacing dev requirements w/ path { destination_dev_req } " )
163+ if not os .path .exists (destination_dev_req ):
164+ logger .info ("No dev_requirements present." )
165+ with open (destination_dev_req , "w+" ) as file :
166+ file .write ("\n " )
167+
168+ replace_dev_reqs (destination_dev_req , pkg , wheel_dir )
169+
153170 for idx , (package , check ) in enumerate (combos , start = 1 ):
154171 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- )
172+ logger .warning (f"Skipping disabled check { check } ({ idx } /{ total } ) for package { package } " )
158173 continue
159- tasks .append (
160- asyncio .create_task (
161- run_check (semaphore , package , check , base_args , idx , total )
162- )
163- )
174+ tasks .append (asyncio .create_task (run_check (semaphore , package , check , base_args , idx , total )))
164175
165176 # Handle Ctrl+C gracefully
166177 pending = set (tasks )
@@ -179,9 +190,7 @@ async def run_all_checks(packages, checks, max_parallel):
179190 elif isinstance (res , Exception ):
180191 norm_results .append (CheckResult (package , check , 99 , 0.0 , "" , str (res )))
181192 else :
182- norm_results .append (
183- CheckResult (package , check , 98 , 0.0 , "" , f"Unknown result type: { res } " )
184- )
193+ norm_results .append (CheckResult (package , check , 98 , 0.0 , "" , f"Unknown result type: { res } " ))
185194 return summarize (norm_results )
186195
187196
@@ -257,15 +266,11 @@ def handler(signum, frame):
257266 ),
258267 )
259268
260- parser .add_argument (
261- "--disablecov" , help = ("Flag. Disables code coverage." ), action = "store_true"
262- )
269+ parser .add_argument ("--disablecov" , help = ("Flag. Disables code coverage." ), action = "store_true" )
263270
264271 parser .add_argument (
265272 "--service" ,
266- help = (
267- "Name of service directory (under sdk/) to test. Example: --service applicationinsights"
268- ),
273+ help = ("Name of service directory (under sdk/) to test. Example: --service applicationinsights" ),
269274 )
270275
271276 parser .add_argument (
@@ -325,9 +330,7 @@ def handler(signum, frame):
325330 else :
326331 target_dir = root_dir
327332
328- logger .info (
329- f"Beginning discovery for { args .service } and root dir { root_dir } . Resolving to { target_dir } ."
330- )
333+ logger .info (f"Beginning discovery for { args .service } and root dir { root_dir } . Resolving to { target_dir } ." )
331334
332335 # ensure that recursive virtual envs aren't messed with by this call
333336 os .environ .pop ("VIRTUAL_ENV" , None )
@@ -344,26 +347,21 @@ def handler(signum, frame):
344347 )
345348
346349 if len (targeted_packages ) == 0 :
347- logger .info (
348- f"No packages collected for targeting string { args .glob_string } and root dir { root_dir } . Exit 0."
349- )
350+ logger .info (f"No packages collected for targeting string { args .glob_string } and root dir { root_dir } . Exit 0." )
350351 exit (0 )
351352
352353 logger .info (f"Executing checks with the executable { sys .executable } ." )
353354 logger .info (f"Packages targeted: { targeted_packages } " )
354355
356+ temp_wheel_dir = args .wheel_dir or os .path .join (root_dir , ".wheels" )
355357 if args .wheel_dir :
356358 os .environ ["PREBUILT_WHEEL_DIR" ] = args .wheel_dir
357-
358- if not os .path .exists (os . path . join ( root_dir , ".wheels" ) ):
359- os .makedirs (os . path . join ( root_dir , ".wheels" ) )
359+ else :
360+ if not os .path .exists (temp_wheel_dir ):
361+ os .makedirs (temp_wheel_dir )
360362
361363 if in_ci ():
362- # prepare a build of eng/tools/azure-sdk-tools
363- # todo: ensure that we honor this .wheels directory when replacing for dev reqs
364- build_whl_for_req (
365- "eng/tools/azure-sdk-tools" , root_dir , os .path .join (root_dir , ".wheels" )
366- )
364+ build_whl_for_req ("eng/tools/azure-sdk-tools" , root_dir , temp_wheel_dir )
367365
368366 # so if we have checks whl,import_all and selected package paths `sdk/core/azure-core`, `sdk/storage/azure-storage-blob` we should
369367 # shell out to `azypysdk <checkname>` with cwd of the package directory, which is what is in `targeted_packages` array
@@ -382,9 +380,7 @@ def handler(signum, frame):
382380
383381 configure_interrupt_handling ()
384382 try :
385- exit_code = asyncio .run (
386- run_all_checks (targeted_packages , checks , args .max_parallel )
387- )
383+ exit_code = asyncio .run (run_all_checks (targeted_packages , checks , args .max_parallel , temp_wheel_dir ))
388384 except KeyboardInterrupt :
389385 logger .error ("Aborted by user." )
390386 exit_code = 130
0 commit comments