Skip to content

Commit a5bd008

Browse files
committed
Added --ignore-missing-version flag to bump and replace
1 parent 45c85be commit a5bd008

7 files changed

+140
-42
lines changed

bumpversion/cli.py

+16
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ def cli(ctx: Context) -> None:
148148
"ignoring the files from the configuration file."
149149
),
150150
)
151+
@click.option(
152+
"--ignore-missing-version",
153+
is_flag=True,
154+
envvar="BUMPVERSION_IGNORE_MISSING_VERSION",
155+
help="Ignore any Version Not Found errors when searching and replacing in files.",
156+
)
151157
@click.option(
152158
"--dry-run",
153159
"-n",
@@ -221,6 +227,7 @@ def bump(
221227
search: Optional[str],
222228
replace: Optional[str],
223229
no_configured_files: bool,
230+
ignore_missing_version: bool,
224231
dry_run: bool,
225232
commit: Optional[bool],
226233
tag: Optional[bool],
@@ -261,6 +268,7 @@ def bump(
261268
tag_message=tag_message,
262269
message=message,
263270
commit_args=commit_args,
271+
ignore_missing_version=ignore_missing_version,
264272
)
265273

266274
found_config_file = find_config_file(config_file)
@@ -408,6 +416,12 @@ def show(args: List[str], config_file: Optional[str], format_: str, increment: O
408416
"ignoring the files from the configuration file."
409417
),
410418
)
419+
@click.option(
420+
"--ignore-missing-version",
421+
is_flag=True,
422+
envvar="BUMPVERSION_IGNORE_MISSING_VERSION",
423+
help="Ignore any Version Not Found errors when searching and replacing in files.",
424+
)
411425
@click.option(
412426
"--dry-run",
413427
"-n",
@@ -427,6 +441,7 @@ def replace(
427441
search: Optional[str],
428442
replace: Optional[str],
429443
no_configured_files: bool,
444+
ignore_missing_version: bool,
430445
dry_run: bool,
431446
) -> None:
432447
"""
@@ -453,6 +468,7 @@ def replace(
453468
tag_message=None,
454469
message=None,
455470
commit_args=None,
471+
ignore_missing_version=ignore_missing_version,
456472
)
457473

458474
found_config_file = find_config_file(config_file)

bumpversion/files.py

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def __init__(
2626
self.serialize = file_cfg.serialize or version_config.serialize_formats
2727
self.search = search or file_cfg.search or version_config.search
2828
self.replace = replace or file_cfg.replace or version_config.replace
29+
self.ignore_missing_version = file_cfg.ignore_missing_version or False
2930
self.version_config = VersionConfig(
3031
self.parse, self.serialize, self.search, self.replace, version_config.part_configs
3132
)
@@ -63,6 +64,8 @@ def contains_version(self, version: Version, context: MutableMapping) -> bool:
6364
return True
6465

6566
# version not found
67+
if self.ignore_missing_version:
68+
return False
6669
raise VersionNotFoundError(f"Did not find '{search_expression}' in file: '{self.path}'")
6770

6871
def contains(self, search: str) -> bool:

tests/fixtures/basic_cfg_expected.txt

+17-10
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,29 @@
44
'current_version': '1.0.0',
55
'files': [{'filename': 'setup.py',
66
'glob': None,
7-
'parse': None,
8-
'replace': None,
9-
'search': None,
10-
'serialize': None},
7+
'ignore_missing_version': False,
8+
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
9+
'replace': '{new_version}',
10+
'search': '{current_version}',
11+
'serialize': ['{major}.{minor}.{patch}-{release}',
12+
'{major}.{minor}.{patch}']},
1113
{'filename': 'bumpversion/__init__.py',
1214
'glob': None,
13-
'parse': None,
14-
'replace': None,
15-
'search': None,
16-
'serialize': None},
15+
'ignore_missing_version': False,
16+
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
17+
'replace': '{new_version}',
18+
'search': '{current_version}',
19+
'serialize': ['{major}.{minor}.{patch}-{release}',
20+
'{major}.{minor}.{patch}']},
1721
{'filename': 'CHANGELOG.md',
1822
'glob': None,
19-
'parse': None,
23+
'ignore_missing_version': False,
24+
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
2025
'replace': '**unreleased**\n**v{new_version}**',
2126
'search': '**unreleased**',
22-
'serialize': None}],
27+
'serialize': ['{major}.{minor}.{patch}-{release}',
28+
'{major}.{minor}.{patch}']}],
29+
'ignore_missing_version': False,
2330
'message': 'Bump version: {current_version} → {new_version}',
2431
'parse': '(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?',
2532
'parts': {'major': {'first_value': None,

tests/fixtures/basic_cfg_expected.yaml

+20-10
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,32 @@ current_version: "1.0.0"
55
files:
66
- filename: "setup.py"
77
glob: null
8-
parse: null
9-
replace: null
10-
search: null
11-
serialize: null
8+
ignore_missing_version: false
9+
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
10+
replace: "{new_version}"
11+
search: "{current_version}"
12+
serialize:
13+
- "{major}.{minor}.{patch}-{release}"
14+
- "{major}.{minor}.{patch}"
1215
- filename: "bumpversion/__init__.py"
1316
glob: null
14-
parse: null
15-
replace: null
16-
search: null
17-
serialize: null
17+
ignore_missing_version: false
18+
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
19+
replace: "{new_version}"
20+
search: "{current_version}"
21+
serialize:
22+
- "{major}.{minor}.{patch}-{release}"
23+
- "{major}.{minor}.{patch}"
1824
- filename: "CHANGELOG.md"
1925
glob: null
20-
parse: null
26+
ignore_missing_version: false
27+
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
2128
replace: "**unreleased**\n**v{new_version}**"
2229
search: "**unreleased**"
23-
serialize: null
30+
serialize:
31+
- "{major}.{minor}.{patch}-{release}"
32+
- "{major}.{minor}.{patch}"
33+
ignore_missing_version: false
2434
message: "Bump version: {current_version} → {new_version}"
2535
parse: "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?"
2636
parts:

tests/fixtures/basic_cfg_expected_full.json

+23-10
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,41 @@
77
{
88
"filename": "setup.py",
99
"glob": null,
10-
"parse": null,
11-
"replace": null,
12-
"search": null,
13-
"serialize": null
10+
"ignore_missing_version": false,
11+
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
12+
"replace": "{new_version}",
13+
"search": "{current_version}",
14+
"serialize": [
15+
"{major}.{minor}.{patch}-{release}",
16+
"{major}.{minor}.{patch}"
17+
]
1418
},
1519
{
1620
"filename": "bumpversion/__init__.py",
1721
"glob": null,
18-
"parse": null,
19-
"replace": null,
20-
"search": null,
21-
"serialize": null
22+
"ignore_missing_version": false,
23+
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
24+
"replace": "{new_version}",
25+
"search": "{current_version}",
26+
"serialize": [
27+
"{major}.{minor}.{patch}-{release}",
28+
"{major}.{minor}.{patch}"
29+
]
2230
},
2331
{
2432
"filename": "CHANGELOG.md",
2533
"glob": null,
26-
"parse": null,
34+
"ignore_missing_version": false,
35+
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
2736
"replace": "**unreleased**\n**v{new_version}**",
2837
"search": "**unreleased**",
29-
"serialize": null
38+
"serialize": [
39+
"{major}.{minor}.{patch}-{release}",
40+
"{major}.{minor}.{patch}"
41+
]
3042
}
3143
],
44+
"ignore_missing_version": false,
3245
"message": "Bump version: {current_version} \u2192 {new_version}",
3346
"parse": "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
3447
"parts": {

tests/test_cli.py

+38-12
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,16 @@ def test_listing_with_version_part(tmp_path: Path, fixtures_path: Path):
196196

197197
assert result.exit_code == 0
198198
assert set(result.output.splitlines(keepends=False)) == {
199+
"WARNING:",
200+
"",
201+
"DEPRECATED: The --list option is deprecated and will be removed in a future version.",
199202
"new_version=1.0.1-dev",
200203
"current_version=1.0.0",
201204
"parse=(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
202205
"serialize=['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}']",
203206
"search={current_version}",
204207
"replace={new_version}",
208+
"ignore_missing_version=False",
205209
"tag=True",
206210
"sign_tags=False",
207211
"tag_name=v{new_version}",
@@ -210,12 +214,21 @@ def test_listing_with_version_part(tmp_path: Path, fixtures_path: Path):
210214
"commit=True",
211215
"message=Bump version: {current_version} → {new_version}",
212216
"commit_args=None",
213-
"files=[{'filename': 'setup.py', 'glob': None, 'parse': None, 'serialize': "
214-
"None, 'search': None, 'replace': None}, {'filename': "
215-
"'bumpversion/__init__.py', 'glob': None, 'parse': None, 'serialize': None, "
216-
"'search': None, 'replace': None}, {'filename': 'CHANGELOG.md', 'glob': None, "
217-
"'parse': None, 'serialize': None, 'search': '**unreleased**', 'replace': "
218-
"'**unreleased**\\n**v{new_version}**'}]",
217+
(
218+
"files=["
219+
"{'filename': 'setup.py', 'glob': None, 'parse': "
220+
"'(?P<major>\\\\d+)\\\\.(?P<minor>\\\\d+)\\\\.(?P<patch>\\\\d+)(\\\\-(?P<release>[a-z]+))?', 'serialize': "
221+
"['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'search': '{current_version}', "
222+
"'replace': '{new_version}', 'ignore_missing_version': False}, "
223+
"{'filename': 'bumpversion/__init__.py', 'glob': None, 'parse': "
224+
"'(?P<major>\\\\d+)\\\\.(?P<minor>\\\\d+)\\\\.(?P<patch>\\\\d+)(\\\\-(?P<release>[a-z]+))?', 'serialize': "
225+
"['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'search': '{current_version}', "
226+
"'replace': '{new_version}', 'ignore_missing_version': False}, "
227+
"{'filename': 'CHANGELOG.md', 'glob': None, 'parse': "
228+
"'(?P<major>\\\\d+)\\\\.(?P<minor>\\\\d+)\\\\.(?P<patch>\\\\d+)(\\\\-(?P<release>[a-z]+))?', 'serialize': "
229+
"['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'search': '**unreleased**', "
230+
"'replace': '**unreleased**\\n**v{new_version}**', 'ignore_missing_version': False}]"
231+
),
219232
}
220233

221234

@@ -236,11 +249,15 @@ def test_listing_without_version_part(tmp_path: Path, fixtures_path: Path):
236249

237250
assert result.exit_code == 0
238251
assert set(result.output.splitlines(keepends=False)) == {
252+
"WARNING:",
253+
"",
254+
"DEPRECATED: The --list option is deprecated and will be removed in a future version.",
239255
"current_version=1.0.0",
240256
"parse=(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)(\\-(?P<release>[a-z]+))?",
241257
"serialize=['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}']",
242258
"search={current_version}",
243259
"replace={new_version}",
260+
"ignore_missing_version=False",
244261
"tag=True",
245262
"sign_tags=False",
246263
"tag_name=v{new_version}",
@@ -249,12 +266,21 @@ def test_listing_without_version_part(tmp_path: Path, fixtures_path: Path):
249266
"commit=True",
250267
"message=Bump version: {current_version} → {new_version}",
251268
"commit_args=None",
252-
"files=[{'filename': 'setup.py', 'glob': None, 'parse': None, 'serialize': "
253-
"None, 'search': None, 'replace': None}, {'filename': "
254-
"'bumpversion/__init__.py', 'glob': None, 'parse': None, 'serialize': None, "
255-
"'search': None, 'replace': None}, {'filename': 'CHANGELOG.md', 'glob': None, "
256-
"'parse': None, 'serialize': None, 'search': '**unreleased**', 'replace': "
257-
"'**unreleased**\\n**v{new_version}**'}]",
269+
(
270+
"files=["
271+
"{'filename': 'setup.py', 'glob': None, 'parse': "
272+
"'(?P<major>\\\\d+)\\\\.(?P<minor>\\\\d+)\\\\.(?P<patch>\\\\d+)(\\\\-(?P<release>[a-z]+))?', 'serialize': "
273+
"['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'search': '{current_version}', "
274+
"'replace': '{new_version}', 'ignore_missing_version': False}, "
275+
"{'filename': 'bumpversion/__init__.py', 'glob': None, 'parse': "
276+
"'(?P<major>\\\\d+)\\\\.(?P<minor>\\\\d+)\\\\.(?P<patch>\\\\d+)(\\\\-(?P<release>[a-z]+))?', 'serialize': "
277+
"['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'search': '{current_version}', "
278+
"'replace': '{new_version}', 'ignore_missing_version': False}, "
279+
"{'filename': 'CHANGELOG.md', 'glob': None, 'parse': "
280+
"'(?P<major>\\\\d+)\\\\.(?P<minor>\\\\d+)\\\\.(?P<patch>\\\\d+)(\\\\-(?P<release>[a-z]+))?', 'serialize': "
281+
"['{major}.{minor}.{patch}-{release}', '{major}.{minor}.{patch}'], 'search': '**unreleased**', "
282+
"'replace': '**unreleased**\\n**v{new_version}**', 'ignore_missing_version': False}]"
283+
),
258284
}
259285

260286

tests/test_files.py

+23
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,26 @@ def test_multi_line_search_is_found(tmp_path: Path) -> None:
366366

367367
# Assert
368368
assert alphabet_path.read_text() == "A\nB\nC\n10.0.0\n"
369+
370+
371+
def test_ignore_missing_version(tmp_path: Path) -> None:
372+
"""If the version is not found in the file, do nothing."""
373+
# Arrange
374+
version_path = tmp_path / Path("VERSION")
375+
version_path.write_text("1.2.3")
376+
377+
overrides = {
378+
"current_version": "1.2.5",
379+
"ignore_missing_version": True,
380+
"files": [{"filename": str(version_path)}],
381+
}
382+
conf, version_config, current_version = get_config_data(overrides)
383+
assert conf.ignore_missing_version is True
384+
new_version = current_version.bump("patch", version_config.order)
385+
cfg_files = [files.ConfiguredFile(file_cfg, version_config) for file_cfg in conf.files]
386+
387+
# Act
388+
files.modify_files(cfg_files, current_version, new_version, get_context(conf))
389+
390+
# Assert
391+
assert version_path.read_text() == "1.2.3"

0 commit comments

Comments
 (0)