Skip to content
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

New improvements and fixes to pytest req updates plugin #16692

Merged
merged 3 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 64 additions & 10 deletions pytest_plugins/requirements/req_updater.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
from functools import cached_property
import subprocess
import sys


class UsageError(Exception):
"""The UsageError raised when the package manager is different from uv or pip"""

pass


class ReqUpdater:
# Installed package name as key and its counterpart in requirements file as value
package_deviates = {
'Betelgeuse': 'betelgeuse',
'broker': 'broker[docker]',
'broker': 'broker[docker,podman,hussh]',
'dynaconf': 'dynaconf[vault]',
'Jinja2': 'jinja2',
'Sphinx': 'sphinx',
'pyyaml': 'PyYAML',
}

@cached_property
Expand All @@ -18,9 +26,9 @@ def installed_packages(self):
This also normalizes any package names that deviates in requirements file vs installed names
"""
installed_pkges = subprocess.run(
'pip list --format=freeze', capture_output=True, shell=True
).stdout.decode()
installer_args = [sys.executable, '-m', 'list', '--format=freeze']
installer_args[2:2] = self.packagae_manager.split(' ')
installed_pkges = subprocess.run(installer_args, capture_output=True).stdout.decode()
for pkg in self.package_deviates:
if pkg in installed_pkges:
# Replacing the installed package names with their names in requirements file
Expand Down Expand Up @@ -56,16 +64,62 @@ def opt_deviation(self):
"""Returns new and updates available packages in requirements-optional file"""
return set(self.optional_packages).difference(self.installed_packages)

@cached_property
def packagae_manager(self):
if (
subprocess.run(
[sys.executable, '-m', 'pip', '--version'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
).returncode
== 0
):
_manager = 'pip'
elif (
subprocess.run(
[sys.executable, '-m', 'uv', '--version'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
).returncode
== 0
):
_manager = 'uv pip'
else:
raise UsageError(
'The package manager is not identifiable for performing package updates.'
'Currently only pip and uv is supported. Please manually update the packages '
'and rerun pytest command.'
)
return _manager

def install_req_deviations(self):
"""Installs new and updates available packages in requirements file"""
if self.req_deviation:
subprocess.run(
f"pip install {' '.join(self.req_deviation)}", shell=True, stdout=subprocess.PIPE
)
lst_of_reqs = ' '.join(f"'{req}'" for req in self.req_deviation)
if (
subprocess.run(
f"{self.packagae_manager} install {lst_of_reqs}",
shell=True,
stdout=subprocess.PIPE,
).returncode
== 0
):
print('Mandatory requirements are updated.')
else:
print('ERROR: Some issue occurred with updating the required requirements')

def install_opt_deviations(self):
"""Installs new and updates available packages in requirements-optional file"""
if self.opt_deviation:
subprocess.run(
f"pip install {' '.join(self.opt_deviation)}", shell=True, stdout=subprocess.PIPE
)
lst_of_reqs = ' '.join(f"'{req}'" for req in self.opt_deviation)
if (
subprocess.run(
f"{self.packagae_manager} install {lst_of_reqs}",
shell=True,
stdout=subprocess.PIPE,
).returncode
== 0
):
print('Optional requirements are updated.')
else:
print('ERROR: Some issue occurred with updating the optional requirements')
36 changes: 23 additions & 13 deletions pytest_plugins/requirements/update_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
updater = ReqUpdater()


def git_deviation_filter(deviation):
"""Packages installed from Git branch and the version cant be compared, so ignore them from reporting"""
git_packages = ['nailgun', 'airgun']
return all(git_pckg not in deviation for git_pckg in git_packages)


def pytest_addoption(parser):
"""Options to allow user to update the requirements"""
update_options = {
Expand All @@ -28,24 +34,28 @@ def pytest_report_header(config):
# Following will update the mandatory and optional requirements
# pytest tests/foreman --collect-only --update-all-reqs
"""
if updater.req_deviation:
print(f"Mandatory Requirements Mismatch: {' '.join(updater.req_deviation)}")
if config.getoption('update_required_reqs') or config.getoption('update_all_reqs'):
updater.install_req_deviations()
print('Mandatory requirements are installed to be up-to-date.')
req_deviations = updater.req_deviation
filtered_req_deviations = list(filter(git_deviation_filter, req_deviations))
if filtered_req_deviations:
print(f"Mandatory Requirements Mismatch: {' '.join(filtered_req_deviations)}")
else:
print('Mandatory Requirements are up to date.')

if updater.opt_deviation:
print(f"Optional Requirements Mismatch: {' '.join(updater.opt_deviation)}")
if config.getoption('update_all_reqs'):
updater.install_opt_deviations()
print('Optional requirements are installed to be up-to-date.')
if req_deviations and (
config.getoption('update_required_reqs') or config.getoption('update_all_reqs')
):
updater.install_req_deviations()

opt_deviations = updater.opt_deviation
filtered_opt_deviations = list(filter(git_deviation_filter, opt_deviations))
if filtered_opt_deviations:
print(f"Optional Requirements Mismatch: {' '.join(filtered_opt_deviations)}")
else:
print('Optional Requirements are up to date.')
if opt_deviations and config.getoption('update_all_reqs'):
updater.install_opt_deviations()

if updater.req_deviation or updater.opt_deviation:
if req_deviations or opt_deviations:
print(
"To update mismatched requirements, run the pytest command with "
"To update requirements, run the pytest with "
"'--update-required-reqs' OR '--update-all-reqs' option."
)