Skip to content

Commit b5fbfb9

Browse files
authored
Ensure Dependency Analysis properly runs against all packages during analyze (#43892)
* ensure that running on an incompatible python version doesn't entirely ignore the package when validating dependencies * refactor of discover_targeted_packages to reduce a TON of the disk access + filter out problematic packages before every attempting to use them
1 parent 13c9e6b commit b5fbfb9

File tree

2 files changed

+43
-28
lines changed

2 files changed

+43
-28
lines changed

eng/tools/azure-sdk-tools/ci_tools/dependency_analysis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def record_dep(dependencies: Dict[str, Dict[str, Any]], req_name: str, spec: str
5858
def get_lib_deps(base_dir: str) -> Tuple[Dict[str, Dict[str, Any]], Dict[str, Dict[str, Any]]]:
5959
packages = {}
6060
dependencies = {}
61-
for lib_dir in discover_targeted_packages("azure*", base_dir):
61+
for lib_dir in discover_targeted_packages("azure*", base_dir, compatibility_filter=False):
6262
try:
6363
parsed = ParsedSetup.from_path(lib_dir)
6464
lib_name, version, requires = parsed.name, parsed.version, parsed.requires

eng/tools/azure-sdk-tools/ci_tools/functions.py

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def unzip_file_to_directory(path_to_zip_file: str, extract_location: str) -> str
104104
return os.path.join(extract_location, extracted_dir)
105105

106106

107-
def apply_compatibility_filter(package_set: List[str]) -> List[str]:
107+
def apply_compatibility_filter(package_set: List[ParsedSetup]) -> List[ParsedSetup]:
108108
"""
109109
This function takes in a set of paths to python packages. It returns the set filtered by compatibility with the currently running python executable.
110110
If a package is unsupported by the executable, it will be omitted from the returned list.
@@ -118,28 +118,25 @@ def apply_compatibility_filter(package_set: List[str]) -> List[str]:
118118
running_major_version = Version(".".join([str(v[0]), str(v[1]), str(v[2])]))
119119

120120
for pkg in package_set:
121-
try:
122-
spec_set = SpecifierSet(ParsedSetup.from_path(pkg).python_requires)
123-
except RuntimeError as e:
124-
logging.error(f"Unable to parse metadata for package {pkg}, omitting from build.")
125-
continue
121+
spec_set = SpecifierSet(pkg.python_requires)
126122

127-
pkg_specs_override = TEST_COMPATIBILITY_MAP.get(os.path.basename(pkg), None)
123+
pkg_specs_override = TEST_COMPATIBILITY_MAP.get(pkg.name, None)
128124

129125
if pkg_specs_override:
130126
spec_set = SpecifierSet(pkg_specs_override)
131127

132128
distro_compat = True
133-
distro_incompat = TEST_PYTHON_DISTRO_INCOMPATIBILITY_MAP.get(os.path.basename(pkg), None)
129+
distro_incompat = TEST_PYTHON_DISTRO_INCOMPATIBILITY_MAP.get(pkg.name, None)
134130
if distro_incompat and distro_incompat in platform.python_implementation().lower():
135131
distro_compat = False
136132

137133
if running_major_version in spec_set and distro_compat:
138134
collected_packages.append(pkg)
139135

140-
logging.debug("Target packages after applying compatibility filter: {}".format(collected_packages))
141136
logging.debug(
142-
"Package(s) omitted by compatibility filter: {}".format(generate_difference(package_set, collected_packages))
137+
"Package(s) omitted by compatibility filter: {}".format(
138+
generate_difference([origpkg.name for origpkg in package_set], [pkg.name for pkg in collected_packages])
139+
)
143140
)
144141

145142
return collected_packages
@@ -208,12 +205,17 @@ def glob_packages(glob_string: str, target_root_dir: str) -> List[str]:
208205
return list(set(collected_top_level_directories))
209206

210207

211-
def apply_business_filter(collected_packages: List[str], filter_type: str) -> List[str]:
212-
pkg_set_ci_filtered = list(filter(omit_function_dict.get(filter_type, omit_build), collected_packages))
208+
def apply_business_filter(collected_packages: List[ParsedSetup], filter_type: str) -> List[ParsedSetup]:
209+
pkg_set_ci_filtered = []
210+
211+
for pkg in collected_packages:
212+
if omit_function_dict.get(filter_type, omit_build)(pkg.folder):
213+
pkg_set_ci_filtered.append(pkg)
213214

214-
logging.debug("Target packages after applying business filter: {}".format(pkg_set_ci_filtered))
215215
logging.debug(
216-
"Package(s) omitted by business filter: {}".format(generate_difference(collected_packages, pkg_set_ci_filtered))
216+
"Package(s) omitted by business filter: {}".format(
217+
generate_difference([pkg.name for pkg in collected_packages], [pkg.name for pkg in pkg_set_ci_filtered])
218+
)
217219
)
218220

219221
return pkg_set_ci_filtered
@@ -248,41 +250,54 @@ def discover_targeted_packages(
248250
f'Results for glob_string "{glob_string}" and root directory "{target_root_dir}" are: {collected_packages}'
249251
)
250252

251-
# apply the additional contains filter
253+
# apply the additional contains filter (purely string based)
252254
collected_packages = [pkg for pkg in collected_packages if additional_contains_filter in pkg]
253255
logger.debug(f'Results after additional contains filter: "{additional_contains_filter}" {collected_packages}')
254256

257+
# now the have the initial package set, we need to walk the set and attempt to parse_setup each package
258+
# this will have the impact of cleaning out any packages that have been set to not buildable anymore (EG namespace packages)
259+
parsed_packages = []
260+
for pkg in collected_packages:
261+
try:
262+
parsed_packages.append(ParsedSetup.from_path(pkg))
263+
except RuntimeError as e:
264+
logging.error(f"Unable to parse metadata for package {pkg}, omitting from build.")
265+
continue
266+
255267
# filter for compatibility, this means excluding a package that doesn't support py36 when we are running a py36 executable
256268
if compatibility_filter:
257-
collected_packages = apply_compatibility_filter(collected_packages)
258-
logger.debug(f"Results after compatibility filter: {collected_packages}")
269+
parsed_packages = apply_compatibility_filter(parsed_packages)
270+
logger.debug(f"Results after compatibility filter: {','.join([p.name for p in parsed_packages])}")
259271

260272
if not include_inactive:
261-
collected_packages = apply_inactive_filter(collected_packages)
273+
parsed_packages = apply_inactive_filter(parsed_packages)
262274

263275
# Apply filter based on filter type. for e.g. Docs, Regression, Management
264-
collected_packages = apply_business_filter(collected_packages, filter_type)
265-
logger.debug(f"Results after business filter: {collected_packages}")
276+
parsed_packages = apply_business_filter(parsed_packages, filter_type)
277+
logger.debug(f"Results after business filter: {[pkg.name for pkg in parsed_packages]}")
266278

267-
return sorted(collected_packages)
279+
return sorted([pkg.folder for pkg in parsed_packages])
268280

269281

270-
def is_package_active(package_path: str):
271-
disabled = INACTIVE_CLASSIFIER in ParsedSetup.from_path(package_path).classifiers
282+
def is_package_active(pkg: ParsedSetup) -> bool:
283+
disabled = INACTIVE_CLASSIFIER in pkg.classifiers
272284

273-
override_value = os.getenv(f"ENABLE_{os.path.basename(package_path).upper().replace('-', '_')}", None)
285+
override_value = os.getenv(f"ENABLE_{pkg.name.upper().replace('-', '_')}", None)
274286

275287
if override_value:
276288
return str_to_bool(override_value)
277289
else:
278290
return not disabled
279291

280292

281-
def apply_inactive_filter(collected_packages: List[str]) -> List[str]:
293+
def apply_inactive_filter(collected_packages: List[ParsedSetup]) -> List[ParsedSetup]:
282294
packages = [pkg for pkg in collected_packages if is_package_active(pkg)]
283295

284-
logging.debug("Target packages after applying inactive filter: {}".format(collected_packages))
285-
logging.debug("Package(s) omitted by inactive filter: {}".format(generate_difference(collected_packages, packages)))
296+
logging.debug(
297+
"Package(s) omitted by inactive filter: {}".format(
298+
generate_difference([collected.name for collected in collected_packages], [pkg.name for pkg in packages])
299+
)
300+
)
286301

287302
return packages
288303

0 commit comments

Comments
 (0)