-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[confcom] Run testing against built extension #9429
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
️✔️Azure CLI Extensions Breaking Change Test
|
|
Hi @DomAyre, |
|
Thank you for your contribution! We will review the pull request and get back to you soon. |
|
The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR. Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions). pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new testing approach that runs tests against built extension wheels instead of local unbuilt code, ensuring tests validate what is actually shipped to customers.
Key Changes:
- Added a session-scoped pytest fixture that builds wheels for extensions being tested
- Implemented module swapping to replace non-test modules with wheel versions while preserving test modules that may rely on unshipped code
| # tests pick up the wheel code over the unbuilt code | ||
| sys.path.insert(0, build_dir.glob("*.whl").__next__().as_posix()) | ||
| for module in list(sys.modules.values()): | ||
| if extension in module.__name__ and module not in modules_to_test: |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable extension is referenced on line 73 outside the loop where it's defined (lines 44-67). This will only work correctly if there's exactly one extension in extensions_to_build. If there are multiple extensions, only modules from the last extension will be reloaded. Consider moving the module reloading logic inside the extension loop or storing all extension names to iterate over later.
| if extension in module.__name__ and module not in modules_to_test: | |
| if any(ext in module.__name__ for ext in extensions_to_build) and module not in modules_to_test: |
|
|
||
| # Add the wheel to the path and reload extension modules so the | ||
| # tests pick up the wheel code over the unbuilt code | ||
| sys.path.insert(0, build_dir.glob("*.whl").__next__().as_posix()) |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic on line 71 uses __next__() which will raise StopIteration if no wheel files are found in build_dir. This could happen if the build process fails silently or if the wheel files have unexpected names. Consider adding error handling or validation to ensure at least one wheel was built successfully.
| sys.path.insert(0, build_dir.glob("*.whl").__next__().as_posix()) | |
| wheel_files = list(build_dir.glob("*.whl")) | |
| if not wheel_files: | |
| raise RuntimeError(f"No wheel files found in {build_dir}. The build may have failed or produced unexpected file names.") | |
| sys.path.insert(0, wheel_files[0].as_posix()) |
| while not any(parent.cmdline()[0].endswith(i) for i in ["bash", "sh"]): | ||
| parent = parent.parent() | ||
| RUN_ID = parent.children()[0].pid |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition on line 36 assumes the parent process command line will end with "bash" or "sh", which may not be true in all environments (e.g., zsh, fish, Windows, or when run from other tools). This could cause an infinite loop or crash if no such parent is found. Consider adding a maximum depth check or handling other shell types.
| while not any(parent.cmdline()[0].endswith(i) for i in ["bash", "sh"]): | |
| parent = parent.parent() | |
| RUN_ID = parent.children()[0].pid | |
| # Recognize common shell process names | |
| shell_names = ["bash", "sh", "zsh", "fish", "cmd.exe", "powershell.exe"] | |
| max_depth = 10 | |
| depth = 0 | |
| while True: | |
| try: | |
| cmdline = parent.cmdline() | |
| if cmdline and any(cmdline[0].endswith(shell) for shell in shell_names): | |
| break | |
| parent = parent.parent() | |
| depth += 1 | |
| if parent is None or depth >= max_depth: | |
| # Could not find a shell parent, fallback to current process | |
| parent = psutil.Process(os.getpid()) | |
| break | |
| except (psutil.Error, IndexError): | |
| # Fallback if process info is unavailable | |
| parent = psutil.Process(os.getpid()) | |
| break | |
| # Use the first child PID if available, else fallback to current PID | |
| children = parent.children() | |
| RUN_ID = children[0].pid if children else parent.pid |
|
|
||
| if not any(build_dir.glob(f"{extension_name}*.whl")): | ||
| subprocess.run( | ||
| ["azdev", "extension", "build", extension.replace("azext_", ""), "--dist-dir", build_dir.as_posix()], |
Copilot
AI
Nov 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 62 duplicates the string replacement extension.replace("azext_", "") which was already computed on line 46 as extension_name. Use the extension_name variable instead to avoid duplication.
| ["azdev", "extension", "build", extension.replace("azext_", ""), "--dist-dir", build_dir.as_posix()], | |
| ["azdev", "extension", "build", extension_name, "--dist-dir", build_dir.as_posix()], |
Why
This repos CI uses azdev to run each extensions tests, however this means it's testing the local modules which might have breaking differences compared to what we ship to customers.
How
The modules actually running the tests are the only part not swapped for the built version to handle tests which rely on unshipped code/data
This checklist is used to make sure that common guidelines for a pull request are followed.
Related command
General Guidelines
azdev style <YOUR_EXT>locally? (pip install azdevrequired)python scripts/ci/test_index.py -qlocally? (pip install wheel==0.30.0required)Note: This is strictly a testing only change, so no version bump or history update is required