diff --git a/komodo/check_up_to_date_pypi.py b/komodo/check_up_to_date_pypi.py index 08f2bef0a..06afeaed1 100644 --- a/komodo/check_up_to_date_pypi.py +++ b/komodo/check_up_to_date_pypi.py @@ -1,6 +1,7 @@ import argparse import copy import pathlib +import re import sys import requests @@ -147,9 +148,17 @@ def run_check_up_to_date( f"{sys.version_info.micro}" ), propose_upgrade=False, + ignore=None, ): yaml = yaml_parser() - releases = load_from_file(yaml, release_file) + releases: dict = load_from_file(yaml, release_file) + + if ignore: + releases = { + package_name: package_version + for package_name, package_version in releases.items() + if re.search(ignore, f"{package_name} {package_version}") is None + } repository = load_from_file(yaml, repository_file) upgrade_proposals_from_pypi = get_upgrade_proposals_from_pypi( releases, @@ -161,7 +170,7 @@ def run_check_up_to_date( insert_upgrade_proposals(upgrade_proposals_from_pypi, repository, releases) print( "Writing upgrade proposals from pypi, " - "assuming nothing has changed with dependencies...", + "assuming nothing has changed with dependencies..." ) with open(propose_upgrade, mode="w", encoding="utf-8") as fout: yaml.dump(releases, fout) @@ -170,7 +179,11 @@ def run_check_up_to_date( major_upgrades, minor_upgrades, patch_upgrades, other_upgrades = [], [], [], [] for name, versions in upgrade_proposals_from_pypi.items(): pypi_latest = get_version.Version(versions["suggested"]) - current_version = get_version.Version(versions["previous"]) + try: + current_version = get_version.Version(versions["previous"]) + except get_version.InvalidVersion: + print(f"Could not parse version {versions['previous']}") + continue if pypi_latest.major > current_version.major: major_upgrades.append( f"{name} not at latest pypi version: {pypi_latest}, " @@ -194,15 +207,15 @@ def run_check_up_to_date( print( "\n".join( ["\nMajor upgrades:"] - + (major_upgrades if major_upgrades else ["None"]) + + major_upgrades + ["\nMinor upgrades:"] - + (minor_upgrades if minor_upgrades else ["None"]) + + minor_upgrades + ["\nPatch upgrades:"] - + (patch_upgrades if patch_upgrades else ["None"]) - + ["\nOther upgrades:"] - + (other_upgrades if other_upgrades else ["None"]) - + ["\n\nFound out of date packages!"] + + patch_upgrades + + ["\nOTHER UPGRADES:"] + + other_upgrades ) + + "\n\n\nFound out of date packages!" ) else: @@ -257,6 +270,13 @@ def get_args() -> argparse.Namespace: ), ) + parser.add_argument( + "--ignore", + help=( + "If given, will ignore packages with names that match the regex expression" + ), + ) + return parser.parse_args() @@ -273,6 +293,7 @@ def main(): args.repository_file, args.python_version, args.propose_upgrade, + args.ignore, ) diff --git a/tests/test_up_to_date_pypi.py b/tests/test_up_to_date_pypi.py index 00f825bc3..c36771592 100644 --- a/tests/test_up_to_date_pypi.py +++ b/tests/test_up_to_date_pypi.py @@ -424,9 +424,9 @@ def test_run_up_to_date( "new_file", ] monkeypatch.setattr(sys, "argv", arguments) - with open("repository_file", "w") as fout: + with open("repository_file", mode="w", encoding="utf-8") as fout: fout.write(str(repository)) - with open("release_file", "w") as fout: + with open("release_file", mode="w", encoding="utf-8") as fout: fout.write(str(release)) request_mock = MagicMock() request_mock.json.return_value = request_json @@ -500,9 +500,9 @@ def test_upgrade_type_grouping(release_file_content, tmpdir, monkeypatch, capsys """ with tmpdir.as_cwd(): - with open("repository_file.yml", "w") as fout: + with open("repository_file.yml", mode="w", encoding="utf-8") as fout: fout.write(repository_file_content) - with open("release_file.yml", "w") as fout: + with open("release_file.yml", mode="w", encoding="utf-8") as fout: fout.write(release_file_content) folder_name = os.getcwd() @@ -544,6 +544,129 @@ def side_effect(url: str, timeout): system_print = capsys.readouterr().out assert ( - "Major upgrades:\ndummy_package_major not at latest pypi version: 2.0.0, is at: 1.0.0\n\nMinor upgrades:\ndummy_package_minor not at latest pypi version: 1.1.0, is at: 1.0.0\n\nPatch upgrades:\ndummy_package_patch not at latest pypi version: 1.0.1, is at: 1.0.0" - in system_print + "Major upgrades:\ndummy_package_major not at latest pypi version: 2.0.0, is" + " at: 1.0.0\n\nMinor upgrades:\ndummy_package_minor not at latest pypi" + " version: 1.1.0, is at: 1.0.0\n\nPatch upgrades:\ndummy_package_patch not" + " at latest pypi version: 1.0.1, is at: 1.0.0" in system_print ) + + +@pytest.mark.parametrize( + "release_file_content, ignore_argument", + [ + pytest.param( + """ + dummy_package_patch: 1.0.0 + dummy_package_minor: 1.0.0 + dummy_package_major: 1.0.0 + dummy_package_should_not_update: main + """, + "main", + id="ignore_main_version", + ), + pytest.param( + """ + dummy_package_patch: 1.0.0 + dummy_package_minor: 1.0.0 + dummy_package_major: 1.0.0 + dummy_package_should_not_update: 1.0.0 + """, + "should_not_update", + id="ignore_semantic_version", + ), + ], +) +def test_upgrade_ignore_flag( + release_file_content, ignore_argument, tmpdir, monkeypatch, capsys +): + repository_file_content = """ + dummy_package_patch: + 1.0.0: + source: pypi + make: pip + maintainer: scout + + dummy_package_minor: + 1.0.0: + source: pypi + make: pip + maintainer: scout + + dummy_package_major: + 1.0.0: + source: pypi + make: pip + maintainer: scout + + dummy_package_should_not_update: + 1.0.0: + source: pypi + make: pip + maintainer: scout + + main: + source: pypi + make: pip + maintainer: scout + """ + + with tmpdir.as_cwd(): + with open("repository_file.yml", mode="w", encoding="utf-8") as fout: + fout.write(repository_file_content) + with open("release_file.yml", mode="w", encoding="utf-8") as fout: + fout.write(release_file_content) + folder_name = os.getcwd() + + def side_effect(url: str, timeout): + if "dummy_package_patch" in url.split("/"): + request_mock = MagicMock() + request_json = { + "releases": {"1.0.1": []}, + } + request_mock.json.return_value = request_json + return request_mock + elif "dummy_package_minor" in url.split("/"): + request_mock = MagicMock() + request_json = { + "releases": {"1.1.0": []}, + } + request_mock.json.return_value = request_json + return request_mock + elif "dummy_package_major" in url.split("/"): + request_mock = MagicMock() + request_json = { + "releases": {"2.0.0": []}, + } + request_mock.json.return_value = request_json + return request_mock + elif "dummy_package_main_should_not_update" in url.split("/"): + request_mock = MagicMock() + request_json = { + "releases": {"4.4.3": []}, + } + request_mock.json.return_value = request_json + return request_mock + elif "dummy_package_should_not_update" in url.split("/"): + request_mock = MagicMock() + request_json = { + "releases": {"2.0.0": []}, + } + request_mock.json.return_value = request_json + return request_mock + else: + raise ValueError("INCORRECT PACKAGE NAME ENTERED! " + str(url)) + + arguments = [ + "", + f"{folder_name}/release_file.yml", + f"{folder_name}/repository_file.yml", + "--ignore", + ignore_argument, + ] + monkeypatch.setattr(sys, "argv", arguments) + monkeypatch.setattr(requests, "get", MagicMock(side_effect=side_effect)) + + check_up_to_date_pypi.main() + system_exit_message = capsys.readouterr().out + assert "dummy_package_should_not_update" not in system_exit_message + assert "dummy_package_main_should_not_update" not in system_exit_message