Skip to content

Commit 0034716

Browse files
committed
Changed the default regex search to non-regex.
Fixes #59 - Changed the flags to --regex/--no-regex - updated tests and docs
1 parent fda71b0 commit 0034716

9 files changed

+57
-53
lines changed

bumpversion/cli.py

+12-12
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,10 @@ def cli(ctx: Context) -> None:
141141
help="Template for complete string to replace",
142142
)
143143
@click.option(
144-
"--no-regex",
145-
is_flag=True,
146-
envvar="BUMPVERSION_NO_REGEX",
147-
help="Do not treat the search parameter as a regular expression",
144+
"--regex/--no-regex",
145+
default=False,
146+
envvar="BUMPVERSION_REGEX",
147+
help="Treat the search parameter as a regular expression or explicitly do not treat it as a regular expression.",
148148
)
149149
@click.option(
150150
"--no-configured-files",
@@ -233,7 +233,7 @@ def bump(
233233
serialize: Optional[List[str]],
234234
search: Optional[str],
235235
replace: Optional[str],
236-
no_regex: bool,
236+
regex: bool,
237237
no_configured_files: bool,
238238
ignore_missing_version: bool,
239239
dry_run: bool,
@@ -277,7 +277,7 @@ def bump(
277277
message=message,
278278
commit_args=commit_args,
279279
ignore_missing_version=ignore_missing_version,
280-
no_regex=no_regex,
280+
regex=regex,
281281
)
282282

283283
found_config_file = find_config_file(config_file)
@@ -418,10 +418,10 @@ def show(args: List[str], config_file: Optional[str], format_: str, increment: O
418418
help="Template for complete string to replace",
419419
)
420420
@click.option(
421-
"--no-regex",
422-
is_flag=True,
423-
envvar="BUMPVERSION_NO_REGEX",
424-
help="Do not treat the search parameter as a regular expression",
421+
"--regex/--no-regex",
422+
default=False,
423+
envvar="BUMPVERSION_REGEX",
424+
help="Treat the search parameter as a regular expression or explicitly do not treat it as a regular expression.",
425425
)
426426
@click.option(
427427
"--no-configured-files",
@@ -456,7 +456,7 @@ def replace(
456456
serialize: Optional[List[str]],
457457
search: Optional[str],
458458
replace: Optional[str],
459-
no_regex: bool,
459+
regex: bool,
460460
no_configured_files: bool,
461461
ignore_missing_version: bool,
462462
dry_run: bool,
@@ -486,7 +486,7 @@ def replace(
486486
message=None,
487487
commit_args=None,
488488
ignore_missing_version=ignore_missing_version,
489-
no_regex=no_regex,
489+
regex=regex,
490490
)
491491

492492
found_config_file = find_config_file(config_file)

bumpversion/config.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class FileConfig(BaseModel):
4343
serialize: Optional[List[str]] = None # If different from outer scope
4444
search: Optional[str] = None # If different from outer scope
4545
replace: Optional[str] = None # If different from outer scope
46-
no_regex: Optional[bool] = None # If different from outer scope
46+
regex: Optional[bool] = None # If different from outer scope
4747
ignore_missing_version: Optional[bool] = None
4848

4949

@@ -55,7 +55,7 @@ class Config(BaseSettings):
5555
serialize: List[str] = Field(min_length=1)
5656
search: str
5757
replace: str
58-
no_regex: bool
58+
regex: bool
5959
ignore_missing_version: bool
6060
tag: bool
6161
sign_tags: bool
@@ -86,7 +86,7 @@ def add_files(self, filename: Union[str, List[str]]) -> None:
8686
serialize=self.serialize,
8787
search=self.search,
8888
replace=self.replace,
89-
no_regex=self.no_regex,
89+
regex=self.regex,
9090
ignore_missing_version=self.ignore_missing_version,
9191
)
9292
)
@@ -128,7 +128,7 @@ def version_config(self) -> "VersionConfig":
128128
"serialize": ["{major}.{minor}.{patch}"],
129129
"search": "{current_version}",
130130
"replace": "{new_version}",
131-
"no_regex": False,
131+
"regex": False,
132132
"ignore_missing_version": False,
133133
"tag": False,
134134
"sign_tags": False,
@@ -159,7 +159,7 @@ def get_all_file_configs(config_dict: dict) -> List[FileConfig]:
159159
"search": config_dict["search"],
160160
"replace": config_dict["replace"],
161161
"ignore_missing_version": config_dict["ignore_missing_version"],
162-
"no_regex": config_dict["no_regex"],
162+
"regex": config_dict["regex"],
163163
}
164164
files = [{k: v for k, v in filecfg.items() if v is not None} for filecfg in config_dict["files"]]
165165
for f in files:

bumpversion/files.py

+14-13
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import re
44
from copy import deepcopy
55
from difflib import context_diff
6-
from typing import List, MutableMapping, Optional
6+
from typing import List, MutableMapping, Optional, Tuple
77

88
from bumpversion.config import FileConfig
99
from bumpversion.exceptions import VersionNotFoundError
@@ -27,7 +27,7 @@ def __init__(
2727
self.serialize = file_cfg.serialize or version_config.serialize_formats
2828
self.search = search or file_cfg.search or version_config.search
2929
self.replace = replace or file_cfg.replace or version_config.replace
30-
self.no_regex = file_cfg.no_regex or False
30+
self.regex = file_cfg.regex or False
3131
self.ignore_missing_version = file_cfg.ignore_missing_version or False
3232
self.version_config = VersionConfig(
3333
self.parse, self.serialize, self.search, self.replace, version_config.part_configs
@@ -63,7 +63,7 @@ def contains_version(self, version: Version, context: MutableMapping) -> bool:
6363
Returns:
6464
True if the version number is in fact present.
6565
"""
66-
search_expression = self.get_search_pattern(context)
66+
search_expression, raw_search_expression = self.get_search_pattern(context)
6767

6868
if self.contains(search_expression):
6969
return True
@@ -84,7 +84,7 @@ def contains_version(self, version: Version, context: MutableMapping) -> bool:
8484
# version not found
8585
if self.ignore_missing_version:
8686
return False
87-
raise VersionNotFoundError(f"Did not find '{search_expression.pattern}' in file: '{self.path}'")
87+
raise VersionNotFoundError(f"Did not find '{raw_search_expression}' in file: '{self.path}'")
8888

8989
def contains(self, search: re.Pattern) -> bool:
9090
"""Does the work of the contains_version method."""
@@ -115,15 +115,15 @@ def replace_version(
115115
if new_version:
116116
context["new_version"] = self.version_config.serialize(new_version, context)
117117

118-
search_for = self.get_search_pattern(context)
118+
search_for, raw_search_pattern = self.get_search_pattern(context)
119119
replace_with = self.version_config.replace.format(**context)
120120

121121
file_content_after = search_for.sub(replace_with, file_content_before)
122122

123123
if file_content_before == file_content_after and current_version.original:
124124
og_context = deepcopy(context)
125125
og_context["current_version"] = current_version.original
126-
search_for_og = self.get_search_pattern(og_context)
126+
search_for_og, og_raw_search_pattern = self.get_search_pattern(og_context)
127127
file_content_after = search_for_og.sub(replace_with, file_content_before)
128128

129129
if file_content_before != file_content_after:
@@ -147,25 +147,26 @@ def replace_version(
147147
if not dry_run: # pragma: no-coverage
148148
self.write_file_contents(file_content_after)
149149

150-
def get_search_pattern(self, context: MutableMapping) -> re.Pattern:
150+
def get_search_pattern(self, context: MutableMapping) -> Tuple[re.Pattern, str]:
151151
"""Compile and return the regex if it is valid, otherwise return the string."""
152152
# the default search pattern is escaped, so we can still use it in a regex
153-
default = re.compile(re.escape(self.version_config.search.format(**context)), re.MULTILINE | re.DOTALL)
154-
if self.no_regex:
153+
raw_pattern = self.version_config.search.format(**context)
154+
default = re.compile(re.escape(raw_pattern), re.MULTILINE | re.DOTALL)
155+
if not self.regex:
155156
logger.debug("No RegEx flag detected. Searching for the default pattern: '%s'", default.pattern)
156-
return default
157+
return default, raw_pattern
157158

158159
re_context = {key: re.escape(str(value)) for key, value in context.items()}
159160
regex_pattern = self.version_config.search.format(**re_context)
160161
try:
161162
search_for_re = re.compile(regex_pattern, re.MULTILINE | re.DOTALL)
162163
logger.debug("Searching for the regex: '%s'", search_for_re.pattern)
163-
return search_for_re
164+
return search_for_re, raw_pattern
164165
except re.error as e:
165166
logger.error("Invalid regex '%s' for file %s: %s.", default, self.path, e)
166167

167-
logger.debug("Searching for the default pattern: '%s'", default.pattern)
168-
return default
168+
logger.debug("Searching for the default pattern: '%s'", raw_pattern)
169+
return default, raw_pattern
169170

170171
def __str__(self) -> str: # pragma: no-coverage
171172
return self.path

docsrc/reference/search-and-replace-config.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Bump-my-version uses a combination of [template strings](https://docs.python.org/3/library/string.html#format-string-syntax) using a [formatting context](formatting-context.md) and regular expressions to search the configured files for the old or current version and replace the text with the new version.
44

5-
Bump My Version falls back to using a simple string search if the search template is not a valid regular expression or if the `no-regex` flag is `True`. The search template is always rendered using the formatting context. The basic logic is:
5+
Bump My Version defaults to using a simple string search. If the search template is not a valid regular expression or if the `no-regex` flag is `True`. The search template is always rendered using the formatting context. The basic logic is:
66

77
1. Escape the formatting context for use in a regular expression.
88
2. Render the search string using the escaped formatting context.

tests/fixtures/basic_cfg_expected.txt

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,33 @@
66
'files': [{'filename': 'setup.py',
77
'glob': None,
88
'ignore_missing_version': False,
9-
'no_regex': False,
109
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
10+
'regex': False,
1111
'replace': '{new_version}',
1212
'search': '{current_version}',
1313
'serialize': ['{major}.{minor}.{patch}-{release}',
1414
'{major}.{minor}.{patch}']},
1515
{'filename': 'bumpversion/__init__.py',
1616
'glob': None,
1717
'ignore_missing_version': False,
18-
'no_regex': False,
1918
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
19+
'regex': False,
2020
'replace': '{new_version}',
2121
'search': '{current_version}',
2222
'serialize': ['{major}.{minor}.{patch}-{release}',
2323
'{major}.{minor}.{patch}']},
2424
{'filename': 'CHANGELOG.md',
2525
'glob': None,
2626
'ignore_missing_version': False,
27-
'no_regex': False,
2827
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
28+
'regex': False,
2929
'replace': '**unreleased**\n**v{new_version}**',
3030
'search': '**unreleased**',
3131
'serialize': ['{major}.{minor}.{patch}-{release}',
3232
'{major}.{minor}.{patch}']}],
3333
'ignore_missing_version': False,
3434
'included_paths': [],
3535
'message': 'Bump version: {current_version} → {new_version}',
36-
'no_regex': False,
3736
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
3837
'parts': {'major': {'first_value': None,
3938
'independent': False,
@@ -51,6 +50,7 @@
5150
'independent': False,
5251
'optional_value': 'gamma',
5352
'values': ['dev', 'gamma']}},
53+
'regex': False,
5454
'replace': '{new_version}',
5555
'scm_info': {'branch_name': None,
5656
'commit_sha': None,

tests/fixtures/basic_cfg_expected.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ files:
88
- filename: "setup.py"
99
glob: null
1010
ignore_missing_version: false
11-
no_regex: false
1211
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
12+
regex: false
1313
replace: "{new_version}"
1414
search: "{current_version}"
1515
serialize:
@@ -18,8 +18,8 @@ files:
1818
- filename: "bumpversion/__init__.py"
1919
glob: null
2020
ignore_missing_version: false
21-
no_regex: false
2221
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
22+
regex: false
2323
replace: "{new_version}"
2424
search: "{current_version}"
2525
serialize:
@@ -28,8 +28,8 @@ files:
2828
- filename: "CHANGELOG.md"
2929
glob: null
3030
ignore_missing_version: false
31-
no_regex: false
3231
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
32+
regex: false
3333
replace: "**unreleased**\n**v{new_version}**"
3434
search: "**unreleased**"
3535
serialize:
@@ -39,7 +39,6 @@ ignore_missing_version: false
3939
included_paths:
4040

4141
message: "Bump version: {current_version} → {new_version}"
42-
no_regex: false
4342
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
4443
parts:
4544
major:
@@ -64,6 +63,7 @@ parts:
6463
values:
6564
- "dev"
6665
- "gamma"
66+
regex: false
6767
replace: "{new_version}"
6868
scm_info:
6969
branch_name: null

tests/fixtures/basic_cfg_expected_full.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
"filename": "setup.py",
1010
"glob": null,
1111
"ignore_missing_version": false,
12-
"no_regex": false,
1312
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
13+
"regex": false,
1414
"replace": "{new_version}",
1515
"search": "{current_version}",
1616
"serialize": [
@@ -22,8 +22,8 @@
2222
"filename": "bumpversion/__init__.py",
2323
"glob": null,
2424
"ignore_missing_version": false,
25-
"no_regex": false,
2625
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
26+
"regex": false,
2727
"replace": "{new_version}",
2828
"search": "{current_version}",
2929
"serialize": [
@@ -35,8 +35,8 @@
3535
"filename": "CHANGELOG.md",
3636
"glob": null,
3737
"ignore_missing_version": false,
38-
"no_regex": false,
3938
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
39+
"regex": false,
4040
"replace": "**unreleased**\n**v{new_version}**",
4141
"search": "**unreleased**",
4242
"serialize": [
@@ -48,7 +48,6 @@
4848
"ignore_missing_version": false,
4949
"included_paths": [],
5050
"message": "Bump version: {current_version} \u2192 {new_version}",
51-
"no_regex": false,
5251
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
5352
"parts": {
5453
"major": {
@@ -79,6 +78,7 @@
7978
]
8079
}
8180
},
81+
"regex": false,
8282
"replace": "{new_version}",
8383
"scm_info": {
8484
"branch_name": null,

0 commit comments

Comments
 (0)