From 127d1b041648a7ba24eadbbf6a4068e2a599b6ca Mon Sep 17 00:00:00 2001 From: Jayson Reis Date: Sat, 17 Apr 2021 19:45:37 +0200 Subject: [PATCH] fix: fix multiple versions bumps when version changes the string size --- commitizen/bump.py | 38 ++++++++++++------- tests/test_bump_update_version_in_files.py | 43 ++++++++++++++++++++++ 2 files changed, 68 insertions(+), 13 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 5e2709255d..e6c9089bef 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -152,24 +152,15 @@ def update_version_in_files( for location in files: filepath, *regexes = location.split(":") regex = regexes[0] if regexes else None - current_version_found = False with open(filepath, "r") as f: version_file = f.read() if regex: - for match in re.finditer(regex, version_file, re.MULTILINE): - left = version_file[: match.end()] - right = version_file[match.end() :] - line_break = _get_line_break_position(right) - middle = right[:line_break] - current_version_found = current_version in middle - right = right[line_break:] - version_file = ( - left + middle.replace(current_version, new_version) + right - ) - - if not regex: + current_version_found, version_file = _bump_with_regex( + version_file, current_version, new_version, regex + ) + else: current_version_regex = _version_to_regex(current_version) current_version_found = bool(current_version_regex.search(version_file)) version_file = current_version_regex.sub(new_version, version_file) @@ -186,6 +177,27 @@ def update_version_in_files( file.write("".join(version_file)) +def _bump_with_regex(version_file_contents, current_version, new_version, regex): + current_version_found = False + # Bumping versions that change the string length move the offset on the file contents as finditer keeps a + # reference to the initial string that was used and calling search many times would lead in infinite loops + # e.g.: 1.1.9 -> 1.1.20 + offset = 0 + for match in re.finditer(regex, version_file_contents, re.MULTILINE): + left = version_file_contents[: match.end() + offset] + right = version_file_contents[match.end() + offset :] + line_break = _get_line_break_position(right) + middle = right[:line_break] + current_version_found_in_block = current_version in middle + offset += len(new_version) - len(current_version) + current_version_found |= current_version_found_in_block + right = right[line_break:] + version_file_contents = ( + left + middle.replace(current_version, new_version) + right + ) + return current_version_found, version_file_contents + + def _get_line_break_position(text: str) -> int: position = text.find("\n") return max(position, 0) diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index aebd87996f..0e0e8f5c30 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -50,6 +50,9 @@ version = "1.2.3" """ +MULTIPLE_VERSIONS_INCREASE_STRING = 'version = "1.2.9"\n' * 30 +MULTIPLE_VERSIONS_REDUCE_STRING = 'version = "1.2.10"\n' * 30 + @pytest.fixture(scope="function") def commitizen_config_file(tmpdir): @@ -86,6 +89,20 @@ def version_repeated_file(tmpdir): return str(tmp_file) +@pytest.fixture(scope="function") +def multiple_versions_increase_string(tmpdir): + tmp_file = tmpdir.join("anyfile") + tmp_file.write(MULTIPLE_VERSIONS_INCREASE_STRING) + return str(tmp_file) + + +@pytest.fixture(scope="function") +def multiple_versions_reduce_string(tmpdir): + tmp_file = tmpdir.join("anyfile") + tmp_file.write(MULTIPLE_VERSIONS_REDUCE_STRING) + return str(tmp_file) + + @pytest.fixture(scope="function") def version_files(commitizen_config_file, python_version_file, version_repeated_file): return [commitizen_config_file, python_version_file, version_repeated_file] @@ -138,6 +155,32 @@ def test_duplicates_are_change_with_no_regex(random_location_version_file): assert len(re.findall(new_version, data)) == 3 +def test_version_bump_increase_string_length(multiple_versions_increase_string): + old_version = "1.2.9" + new_version = "1.2.10" + version_bump_change_string_size( + multiple_versions_increase_string, old_version, new_version + ) + + +def test_version_bump_reduce_string_length(multiple_versions_reduce_string): + old_version = "1.2.10" + new_version = "2.0.0" + version_bump_change_string_size( + multiple_versions_reduce_string, old_version, new_version + ) + + +def version_bump_change_string_size(filename, old_version, new_version): + location = f"{filename}:version" + + bump.update_version_in_files(old_version, new_version, [location]) + with open(filename, "r") as f: + data = f.read() + assert len(re.findall(old_version, data)) == 0 + assert len(re.findall(new_version, data)) == 30 + + def test_file_version_inconsistent_error( commitizen_config_file, inconsistent_python_version_file, version_repeated_file ):