Skip to content

Commit fb5cb5e

Browse files
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.
1 parent c3acc75 commit fb5cb5e

File tree

1 file changed

+21
-36
lines changed

1 file changed

+21
-36
lines changed

commitizen/bump.py

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -142,18 +142,12 @@ def update_version_in_files(
142142
# TODO: separate check step and write step
143143
for location in files:
144144
filepath, _, regex = location.partition(":")
145+
if not regex:
146+
regex = _version_to_regex(current_version)
145147

146-
with open(filepath, "r") as f:
147-
version_file = f.read()
148-
149-
if regex:
150-
current_version_found, version_file = _bump_with_regex(
151-
version_file, current_version, new_version, regex
152-
)
153-
else:
154-
current_version_regex = _version_to_regex(current_version)
155-
current_version_found = bool(current_version_regex.search(version_file))
156-
version_file = current_version_regex.sub(new_version, version_file)
148+
current_version_found, version_file = _bump_with_regex(
149+
filepath, current_version, new_version, re.compile(regex)
150+
)
157151

158152
if check_consistency and not current_version_found:
159153
raise CurrentVersionNotFoundError(
@@ -168,33 +162,24 @@ def update_version_in_files(
168162

169163

170164
def _bump_with_regex(
171-
version_file_contents: str, current_version: str, new_version: str, regex: str
165+
version_filepath: str, current_version: str, new_version: str, regex: re.Pattern
172166
) -> Tuple[bool, str]:
173167
current_version_found = False
174-
# Bumping versions that change the string length move the offset on the file contents as finditer keeps a
175-
# reference to the initial string that was used and calling search many times would lead in infinite loops
176-
# e.g.: 1.1.9 -> 1.1.20
177-
offset = 0
178-
for match in re.finditer(regex, version_file_contents, re.MULTILINE):
179-
left = version_file_contents[: match.end() + offset]
180-
right = version_file_contents[match.end() + offset :]
181-
182-
line_break = right.find("\n")
183-
middle = right[:line_break]
184-
right = right[line_break:]
185-
186-
if current_version in middle:
187-
offset += len(new_version) - len(current_version)
188-
current_version_found = True
189-
version_file_contents = (
190-
left + middle.replace(current_version, new_version) + right
191-
)
192-
return current_version_found, version_file_contents
193-
194-
195-
def _version_to_regex(version: str) -> re.Pattern:
196-
clean_regex = version.replace(".", r"\.").replace("+", r"\+")
197-
return re.compile(f"{clean_regex}")
168+
lines = []
169+
with open(version_filepath, "r") as f:
170+
for line in f:
171+
if regex.search(line):
172+
bumped_line = line.replace(current_version, new_version)
173+
if bumped_line != line:
174+
current_version_found = True
175+
lines.append(bumped_line)
176+
else:
177+
lines.append(line)
178+
return current_version_found, "".join(lines)
179+
180+
181+
def _version_to_regex(version: str) -> str:
182+
return version.replace(".", r"\.").replace("+", r"\+")
198183

199184

200185
def normalize_tag(

0 commit comments

Comments
 (0)