-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Enforce Conda pyproject.toml metadata in CI #45012
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,4 @@ | ||||||||||||||||
| import argparse | ||||||||||||||||
| import logging | ||||||||||||||||
| import os | ||||||||||||||||
| import sys | ||||||||||||||||
| import glob | ||||||||||||||||
|
|
@@ -77,7 +76,7 @@ def verify_whl_root_directory( | |||||||||||||||
| non_azure_folders = [d for d in root_folders if d != expected_top_level_module and not d.endswith(".dist-info")] | ||||||||||||||||
|
|
||||||||||||||||
| if non_azure_folders: | ||||||||||||||||
| logging.error( | ||||||||||||||||
| logger.error( | ||||||||||||||||
| "whl has following incorrect directory at root level [%s]", | ||||||||||||||||
| non_azure_folders, | ||||||||||||||||
| ) | ||||||||||||||||
|
|
@@ -99,6 +98,43 @@ def should_verify_package(package_name): | |||||||||||||||
| return package_name not in EXCLUDED_PACKAGES and "nspkg" not in package_name and "-mgmt" not in package_name | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def has_stable_version_on_pypi(package_name: str) -> bool: | ||||||||||||||||
| """Check if the package has any stable (non-prerelease) version on PyPI.""" | ||||||||||||||||
| try: | ||||||||||||||||
| all_versions = retrieve_versions_from_pypi(package_name) | ||||||||||||||||
| stable_versions = [Version(v) for v in all_versions if not Version(v).is_prerelease] | ||||||||||||||||
| return len(stable_versions) > 0 | ||||||||||||||||
| except Exception: | ||||||||||||||||
| return False | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def verify_conda_section(package_dir: str, package_name: str) -> bool: | ||||||||||||||||
| """Verify that packages with stable versions on PyPI have [tool.azure-sdk-conda] section in pyproject.toml.""" | ||||||||||||||||
| if not has_stable_version_on_pypi(package_name): | ||||||||||||||||
JennyPng marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
| logger.info(f"Package {package_name} has no stable version on PyPI, skipping conda section check") | ||||||||||||||||
| return True | ||||||||||||||||
|
|
||||||||||||||||
| pyproject_path = os.path.join(package_dir, "pyproject.toml") | ||||||||||||||||
| if not os.path.exists(pyproject_path): | ||||||||||||||||
| logger.error(f"Package {package_name} has a stable version on PyPI but is missing pyproject.toml") | ||||||||||||||||
| return False | ||||||||||||||||
|
|
||||||||||||||||
| try: | ||||||||||||||||
| with open(pyproject_path, "r", encoding="utf-8") as f: | ||||||||||||||||
| content = f.read() | ||||||||||||||||
|
|
||||||||||||||||
| if "[tool.azure-sdk-conda]" not in content: | ||||||||||||||||
|
||||||||||||||||
| logger.error( | ||||||||||||||||
| f"Package {package_name} has a stable version on PyPI but is missing " | ||||||||||||||||
| "[tool.azure-sdk-conda] section in pyproject.toml" | ||||||||||||||||
| ) | ||||||||||||||||
| return False | ||||||||||||||||
| return True | ||||||||||||||||
|
Comment on lines
+126
to
+132
|
||||||||||||||||
| except Exception as e: | ||||||||||||||||
| logger.error(f"Failed to read pyproject.toml for {package_name}: {e}") | ||||||||||||||||
| return False | ||||||||||||||||
|
Comment on lines
+101
to
+135
|
||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
| def get_prior_version(package_name: str, current_version: str) -> Optional[str]: | ||||||||||||||||
| """Get prior stable version if it exists, otherwise get prior preview version, else return None.""" | ||||||||||||||||
| try: | ||||||||||||||||
|
|
@@ -179,7 +215,7 @@ def verify_metadata_compatibility(current_metadata: Dict[str, Any], prior_metada | |||||||||||||||
| repo_urls = ["homepage", "repository"] | ||||||||||||||||
| current_keys_lower = {k.lower() for k in current_metadata.keys()} | ||||||||||||||||
| if not any(key in current_keys_lower for key in repo_urls): | ||||||||||||||||
| logging.error(f"Current metadata must contain at least one of: {repo_urls}") | ||||||||||||||||
| logger.error(f"Current metadata must contain at least one of: {repo_urls}") | ||||||||||||||||
| return False | ||||||||||||||||
|
|
||||||||||||||||
| if not prior_metadata: | ||||||||||||||||
|
|
@@ -192,7 +228,7 @@ def verify_metadata_compatibility(current_metadata: Dict[str, Any], prior_metada | |||||||||||||||
| is_compatible = prior_keys_filtered.issubset(current_keys) | ||||||||||||||||
| if not is_compatible: | ||||||||||||||||
| missing_keys = prior_keys_filtered - current_keys | ||||||||||||||||
| logging.error("Metadata compatibility failed. Missing keys: %s", missing_keys) | ||||||||||||||||
| logger.error("Metadata compatibility failed. Missing keys: %s", missing_keys) | ||||||||||||||||
| return is_compatible | ||||||||||||||||
|
|
||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -255,4 +291,11 @@ def run(self, args: argparse.Namespace) -> int: | |||||||||||||||
| logger.error(f"Failed to verify whl for package {package_name}") | ||||||||||||||||
| results.append(1) | ||||||||||||||||
|
|
||||||||||||||||
| # Verify conda section for packages with stable versions on PyPI | ||||||||||||||||
| if not verify_conda_section(package_dir, package_name): | ||||||||||||||||
| logger.error( | ||||||||||||||||
| "As part of releasing stable packages to Conda, the pyproject.toml must include a [tool.azure-sdk-conda] section and specify if the package should be released individually or bundled." | ||||||||||||||||
|
||||||||||||||||
| "As part of releasing stable packages to Conda, the pyproject.toml must include a [tool.azure-sdk-conda] section and specify if the package should be released individually or bundled." | |
| "As part of releasing stable packages to Conda, the pyproject.toml must include a [tool.azure-sdk-conda] " | |
| "section and specify if the package should be released individually or bundled. For configuration guidance, " | |
| "see https://aka.ms/azsdk/python/conda-config, for example:\n" | |
| "[tool.azure-sdk-conda]\n" | |
| 'publish = "individual" # or "bundle"\n' | |
| 'bundle_group = "azure-ai" # optional, when using bundle' |
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.
Similar to verify_conda_section, the bare Exception catch here is too broad and could hide bugs. The function returns False for any exception (including network errors, JSON parsing errors, etc.), which makes debugging difficult. Consider either catching specific exceptions or logging the exception before returning False so that failures are visible in CI logs.