From 0d30fb56a311942bd540a6f5ea75d67896592a0f Mon Sep 17 00:00:00 2001 From: Kurt von Laven Date: Mon, 22 Aug 2022 01:43:48 -0700 Subject: [PATCH 1/3] style(bump): Add mypy typing for _bump_with_regex --- commitizen/bump.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 2314b8d0e..3a7f56b6e 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -2,7 +2,7 @@ from collections import OrderedDict from itertools import zip_longest from string import Template -from typing import List, Optional, Union +from typing import List, Optional, Tuple, Union from packaging.version import Version @@ -167,7 +167,9 @@ def update_version_in_files( file.write("".join(version_file)) -def _bump_with_regex(version_file_contents, current_version, new_version, regex): +def _bump_with_regex( + version_file_contents: str, current_version: str, new_version: str, regex: str +) -> Tuple[bool, str]: 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 From 1899bb571c63c63095ac422058082051c943c9d9 Mon Sep 17 00:00:00 2001 From: Kurt von Laven Date: Mon, 22 Aug 2022 01:47:58 -0700 Subject: [PATCH 2/3] fix(bump): Search for version number line by line Avoid the complexities of multiline regex matching and inconsistencies with the case where no regex is specified. Simplify the implementation by eliminating the need to track an offset into the file. Ensure that the version number will be found even if it is to the left of the portion of the line matching the regex. --- commitizen/bump.py | 58 +++++++------------ tests/data/sample_cargo.lock | 2 +- tests/test_bump_update_version_in_files.py | 2 +- ...t_duplicates_are_change_with_no_regex.lock | 2 +- .../test_random_location.lock | 2 +- 5 files changed, 26 insertions(+), 40 deletions(-) diff --git a/commitizen/bump.py b/commitizen/bump.py index 3a7f56b6e..0c821ce2d 100644 --- a/commitizen/bump.py +++ b/commitizen/bump.py @@ -142,18 +142,12 @@ def update_version_in_files( # TODO: separate check step and write step for location in files: filepath, _, regex = location.partition(":") + if not regex: + regex = _version_to_regex(current_version) - with open(filepath, "r") as f: - version_file = f.read() - - if 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) + current_version_found, version_file = _bump_with_regex( + filepath, current_version, new_version, regex + ) if check_consistency and not current_version_found: raise CurrentVersionNotFoundError( @@ -168,33 +162,25 @@ def update_version_in_files( def _bump_with_regex( - version_file_contents: str, current_version: str, new_version: str, regex: str + version_filepath: str, current_version: str, new_version: str, regex: str ) -> Tuple[bool, str]: 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 = right.find("\n") - middle = right[:line_break] - right = right[line_break:] - - if current_version in middle: - offset += len(new_version) - len(current_version) - current_version_found = True - version_file_contents = ( - left + middle.replace(current_version, new_version) + right - ) - return current_version_found, version_file_contents - - -def _version_to_regex(version: str): - clean_regex = version.replace(".", r"\.").replace("+", r"\+") - return re.compile(f"{clean_regex}") + lines = [] + pattern = re.compile(regex) + with open(version_filepath, "r") as f: + for line in f: + if pattern.search(line): + bumped_line = line.replace(current_version, new_version) + if bumped_line != line: + current_version_found = True + lines.append(bumped_line) + else: + lines.append(line) + return current_version_found, "".join(lines) + + +def _version_to_regex(version: str) -> str: + return version.replace(".", r"\.").replace("+", r"\+") def normalize_tag( diff --git a/tests/data/sample_cargo.lock b/tests/data/sample_cargo.lock index a3a0b1bb7..d9dbd792b 100644 --- a/tests/data/sample_cargo.lock +++ b/tests/data/sample_cargo.lock @@ -4,7 +4,7 @@ version = "1.2.3" [[package]] name = "there-i-fixed-it" -version = "1.2.3" +version = "1.2.3" # automatically bumped by Commitizen [[package]] name = "other-project" diff --git a/tests/test_bump_update_version_in_files.py b/tests/test_bump_update_version_in_files.py index a00286df7..311363800 100644 --- a/tests/test_bump_update_version_in_files.py +++ b/tests/test_bump_update_version_in_files.py @@ -125,7 +125,7 @@ def test_partial_update_of_file(version_repeated_file, file_regression): def test_random_location(random_location_version_file, file_regression): old_version = "1.2.3" new_version = "2.0.0" - location = f"{random_location_version_file}:there-i-fixed-it.+\nversion" + location = f"{random_location_version_file}:version.+Commitizen" bump.update_version_in_files(old_version, new_version, [location]) with open(random_location_version_file, "r") as f: diff --git a/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock b/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock index eed8f4c79..8fe75b80c 100644 --- a/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock +++ b/tests/test_bump_update_version_in_files/test_duplicates_are_change_with_no_regex.lock @@ -4,7 +4,7 @@ version = "2.0.0" [[package]] name = "there-i-fixed-it" -version = "2.0.0" +version = "2.0.0" # automatically bumped by Commitizen [[package]] name = "other-project" diff --git a/tests/test_bump_update_version_in_files/test_random_location.lock b/tests/test_bump_update_version_in_files/test_random_location.lock index 94422116a..20dfe7f65 100644 --- a/tests/test_bump_update_version_in_files/test_random_location.lock +++ b/tests/test_bump_update_version_in_files/test_random_location.lock @@ -4,7 +4,7 @@ version = "1.2.3" [[package]] name = "there-i-fixed-it" -version = "2.0.0" +version = "2.0.0" # automatically bumped by Commitizen [[package]] name = "other-project" From 7f7a6068754e0d05aee39d97b43f41de48dd9b41 Mon Sep 17 00:00:00 2001 From: Kurt von Laven Date: Mon, 22 Aug 2022 02:07:47 -0700 Subject: [PATCH 3/3] ci(pre-commit): Remove version_files lookahead Commitizen runs bump on itself to, among other things, manage the version it uses of its own pre-commit hooks. When searching .pre-commit-config.yaml for the version number of Commitizen, we search for "Commitizen," which is in a comment to the right of the version number. Remove the lookahead assertion for "Commitizen," and instead simply consume it when matching now that version_files regexes don't need to exclusively match to the left of the version number. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 43ba51525..c6fb3f5c4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ tag_format = "v$version" version_files = [ "pyproject.toml:version", "commitizen/__version__.py", - ".pre-commit-config.yaml:rev:.\\s+(?=[^\\n]+Commitizen)" + ".pre-commit-config.yaml:rev:.+Commitizen" ] [tool.black]