From 6e044bae0ba013ee14c9a19853ec157bdcc8af26 Mon Sep 17 00:00:00 2001 From: Dominic Ayre Date: Wed, 12 Nov 2025 15:38:38 +0000 Subject: [PATCH 1/3] Test built wheel of changed extensions runs at all --- scripts/ci/test_source.py | 43 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/scripts/ci/test_source.py b/scripts/ci/test_source.py index c4bc8e47af2..721105b120a 100755 --- a/scripts/ci/test_source.py +++ b/scripts/ci/test_source.py @@ -9,6 +9,8 @@ import logging import os +from pathlib import Path +import subprocess import sys import tempfile import shutil @@ -64,7 +66,7 @@ def run_command(cmd, check_return_code=False, cwd=None): raise RuntimeError(f"{cmd} failed") -def test_extension(): +def test_extension(whl_dir: Path): for pkg_name, ext_path in ALL_TESTS: ext_name = ext_path.split('/')[-1] logger.info(f'installing extension: {ext_name}') @@ -86,22 +88,45 @@ def test_extension(): cmd = ['azdev', 'extension', 'remove', ext_name] run_command(cmd, check_return_code=True) - -def test_source_wheels(): + logger.info(f'installing extension wheel: {ext_name}') + wheel_path = next(whl_dir.glob(f"{ext_name}*.whl")) + subprocess.run( + f"az extension add -y -s {wheel_path}".split(" "), + check=True, + ) + subprocess.run( + f"az {ext_name} --help".split(" "), + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + subprocess.run( + f"az extension remove -n {ext_name}".split(" "), + check=True, + ) + + +def test_source_wheels(whl_dir: Path): # Test we can build all sources into wheels and that metadata from the wheel is valid built_whl_dir = tempfile.mkdtemp() source_extensions = [os.path.join(SRC_PATH, n) for n in os.listdir(SRC_PATH) if os.path.isdir(os.path.join(SRC_PATH, n))] for s in source_extensions: + ext_name = s.split('/')[-1] if not os.path.isfile(os.path.join(s, 'setup.py')): continue try: - check_output(['python', 'setup.py', 'bdist_wheel', '-q', '-d', built_whl_dir], cwd=s) + check_output(['azdev', 'extension', 'build', ext_name, '--dist-dir', built_whl_dir]) except CalledProcessError as err: raise("Unable to build extension {} : {}".format(s, err)) # Export built wheels so CI can publish them as artifacts - wheels_out_dir = os.environ.get('WHEELS_OUTPUT_DIR') - if wheels_out_dir: + wheels_out_dirs = [ + os.environ.get('WHEELS_OUTPUT_DIR'), + str(whl_dir), + ] + for wheels_out_dir in wheels_out_dirs: + if not wheels_out_dir: + continue try: os.makedirs(wheels_out_dir, exist_ok=True) for fname in os.listdir(built_whl_dir): @@ -115,5 +140,7 @@ def test_source_wheels(): if __name__ == '__main__': - test_extension() - test_source_wheels() + with tempfile.TemporaryDirectory() as whl_dir: + whl_dir = Path(whl_dir) + test_source_wheels(whl_dir=whl_dir) + test_extension(whl_dir=whl_dir) From 119cc9042f12e5bd53dbb8b71f054e0104938b6b Mon Sep 17 00:00:00 2001 From: Dominic Ayre Date: Wed, 12 Nov 2025 16:00:41 +0000 Subject: [PATCH 2/3] Make the wheel testing optional --- scripts/ci/test_source.py | 42 ++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/scripts/ci/test_source.py b/scripts/ci/test_source.py index 721105b120a..dac6b62261a 100755 --- a/scripts/ci/test_source.py +++ b/scripts/ci/test_source.py @@ -17,6 +17,7 @@ import shlex from subprocess import check_output, CalledProcessError, run +from typing import Optional from util import SRC_PATH logger = logging.getLogger(__name__) @@ -66,7 +67,7 @@ def run_command(cmd, check_return_code=False, cwd=None): raise RuntimeError(f"{cmd} failed") -def test_extension(whl_dir: Path): +def test_extension(whl_dir: Optional[Path] = None): for pkg_name, ext_path in ALL_TESTS: ext_name = ext_path.split('/')[-1] logger.info(f'installing extension: {ext_name}') @@ -88,25 +89,26 @@ def test_extension(whl_dir: Path): cmd = ['azdev', 'extension', 'remove', ext_name] run_command(cmd, check_return_code=True) - logger.info(f'installing extension wheel: {ext_name}') - wheel_path = next(whl_dir.glob(f"{ext_name}*.whl")) - subprocess.run( - f"az extension add -y -s {wheel_path}".split(" "), - check=True, - ) - subprocess.run( - f"az {ext_name} --help".split(" "), - check=True, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - ) - subprocess.run( - f"az extension remove -n {ext_name}".split(" "), - check=True, - ) - - -def test_source_wheels(whl_dir: Path): + if whl_dir is not None: + logger.info(f'installing extension wheel: {ext_name}') + wheel_path = next(whl_dir.glob(f"{ext_name}*.whl")) + subprocess.run( + f"az extension add -y -s {wheel_path}".split(" "), + check=True, + ) + subprocess.run( + f"az {ext_name} --help".split(" "), + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + subprocess.run( + f"az extension remove -n {ext_name}".split(" "), + check=True, + ) + + +def test_source_wheels(whl_dir: Optional[Path] = None): # Test we can build all sources into wheels and that metadata from the wheel is valid built_whl_dir = tempfile.mkdtemp() source_extensions = [os.path.join(SRC_PATH, n) for n in os.listdir(SRC_PATH) From 11e0a077d8ce67f6904a3ae1564f898ccda44b4b Mon Sep 17 00:00:00 2001 From: Dominic Ayre Date: Thu, 13 Nov 2025 11:08:44 +0000 Subject: [PATCH 3/3] Minor fixes and docs --- scripts/ci/test_source.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/ci/test_source.py b/scripts/ci/test_source.py index dac6b62261a..a965ebce9e5 100755 --- a/scripts/ci/test_source.py +++ b/scripts/ci/test_source.py @@ -89,21 +89,25 @@ def test_extension(whl_dir: Optional[Path] = None): cmd = ['azdev', 'extension', 'remove', ext_name] run_command(cmd, check_return_code=True) + # This catches code missing in the final wheel package, but until the full + # set of extension tests can be run against the wheel, it will not catch + # missing files required at runtime. if whl_dir is not None: logger.info(f'installing extension wheel: {ext_name}') - wheel_path = next(whl_dir.glob(f"{ext_name}*.whl")) + wheel_path = next(whl_dir.glob(f"{ext_name}*.whl"), None) + assert wheel_path is not None, f"Wheel for extension {ext_name} not found in {whl_dir}" subprocess.run( - f"az extension add -y -s {wheel_path}".split(" "), + ["az", "extension", "add", "-y", "-s", wheel_path], check=True, ) subprocess.run( - f"az {ext_name} --help".split(" "), + ["az", ext_name, "--help"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) subprocess.run( - f"az extension remove -n {ext_name}".split(" "), + ["az", "extension", "remove", "-n", ext_name], check=True, ) @@ -124,7 +128,7 @@ def test_source_wheels(whl_dir: Optional[Path] = None): # Export built wheels so CI can publish them as artifacts wheels_out_dirs = [ os.environ.get('WHEELS_OUTPUT_DIR'), - str(whl_dir), + str(whl_dir) if whl_dir else None, ] for wheels_out_dir in wheels_out_dirs: if not wheels_out_dir: