Skip to content

Commit 249a999

Browse files
committed
Refactored FileConfig to FileChange.
This better describes what the class does: describe a file change. Also moved `get_search_pattern` to the class, since it is specific to each instance
1 parent a4c90b2 commit 249a999

File tree

8 files changed

+119
-101
lines changed

8 files changed

+119
-101
lines changed

bumpversion/bump.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def commit_and_tag(
115115

116116
extra_args = shlex.split(config.commit_args) if config.commit_args else []
117117

118-
commit_files = {f.path for f in configured_files}
118+
commit_files = {f.file_change.filename for f in configured_files}
119119
if config_file:
120120
commit_files |= {str(config_file)}
121121

bumpversion/config/files.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def update_config_file(
116116
context: The context to use for serialization.
117117
dry_run: True if the update should be a dry run.
118118
"""
119-
from bumpversion.config.models import FileConfig
119+
from bumpversion.config.models import FileChange
120120
from bumpversion.files import DataFileUpdater
121121

122122
if not config_file:
@@ -129,7 +129,7 @@ def update_config_file(
129129
return
130130

131131
# TODO: Eventually this should be transformed into another default "files_to_modify" entry
132-
datafile_config = FileConfig(
132+
datafile_config = FileChange(
133133
filename=str(config_path),
134134
key_path="tool.bumpversion.current_version",
135135
search=config.search,

bumpversion/config/models.py

+40-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
"""Bump My Version configuration models."""
22
from __future__ import annotations
33

4-
from typing import TYPE_CHECKING, Dict, List, Optional, Union
4+
import logging
5+
import re
6+
from typing import TYPE_CHECKING, Dict, List, MutableMapping, Optional, Tuple, Union
57

68
from pydantic import BaseModel, Field
79
from pydantic_settings import BaseSettings, SettingsConfigDict
@@ -10,6 +12,8 @@
1012
from bumpversion.scm import SCMInfo
1113
from bumpversion.version_part import VersionConfig
1214

15+
logger = logging.getLogger(__name__)
16+
1317

1418
class VersionPartConfig(BaseModel):
1519
"""Configuration of a part of the version."""
@@ -21,8 +25,8 @@ class VersionPartConfig(BaseModel):
2125
independent: bool = False
2226

2327

24-
class FileConfig(BaseModel):
25-
"""Search and replace file config."""
28+
class FileChange(BaseModel):
29+
"""A change to make to a file."""
2630

2731
parse: str
2832
serialize: List[str]
@@ -34,6 +38,35 @@ class FileConfig(BaseModel):
3438
glob: Optional[str] = None # Conflicts with filename. If both are specified, glob wins
3539
key_path: Optional[str] = None # If specified, and has an appropriate extension, will be treated as a data file
3640

41+
def get_search_pattern(self, context: MutableMapping) -> Tuple[re.Pattern, str]:
42+
"""
43+
Render the search pattern and return the compiled regex pattern and the raw pattern.
44+
45+
Args:
46+
context: The context to use for rendering the search pattern
47+
48+
Returns:
49+
A tuple of the compiled regex pattern and the raw pattern as a string.
50+
"""
51+
# the default search pattern is escaped, so we can still use it in a regex
52+
raw_pattern = self.search.format(**context)
53+
default = re.compile(re.escape(raw_pattern), re.MULTILINE | re.DOTALL)
54+
if not self.regex:
55+
logger.debug("No RegEx flag detected. Searching for the default pattern: '%s'", default.pattern)
56+
return default, raw_pattern
57+
58+
re_context = {key: re.escape(str(value)) for key, value in context.items()}
59+
regex_pattern = self.search.format(**re_context)
60+
try:
61+
search_for_re = re.compile(regex_pattern, re.MULTILINE | re.DOTALL)
62+
logger.debug("Searching for the regex: '%s'", search_for_re.pattern)
63+
return search_for_re, raw_pattern
64+
except re.error as e:
65+
logger.error("Invalid regex '%s': %s.", default, e)
66+
67+
logger.debug("Invalid regex. Searching for the default pattern: '%s'", raw_pattern)
68+
return default, raw_pattern
69+
3770

3871
class Config(BaseSettings):
3972
"""Bump Version configuration."""
@@ -55,7 +88,7 @@ class Config(BaseSettings):
5588
commit_args: Optional[str]
5689
scm_info: Optional["SCMInfo"]
5790
parts: Dict[str, VersionPartConfig]
58-
files: List[FileConfig]
91+
files: List[FileChange]
5992
included_paths: List[str] = Field(default_factory=list)
6093
excluded_paths: List[str] = Field(default_factory=list)
6194
model_config = SettingsConfigDict(env_prefix="bumpversion_")
@@ -67,7 +100,7 @@ def add_files(self, filename: Union[str, List[str]]) -> None:
67100
if name in self.resolved_filemap:
68101
continue
69102
self.files.append(
70-
FileConfig(
103+
FileChange(
71104
filename=name,
72105
glob=None,
73106
key_path=None,
@@ -81,7 +114,7 @@ def add_files(self, filename: Union[str, List[str]]) -> None:
81114
)
82115

83116
@property
84-
def resolved_filemap(self) -> Dict[str, FileConfig]:
117+
def resolved_filemap(self) -> Dict[str, FileChange]:
85118
"""Return a map of filenames to file configs, expanding any globs."""
86119
from bumpversion.config.utils import resolve_glob_files
87120

@@ -95,7 +128,7 @@ def resolved_filemap(self) -> Dict[str, FileConfig]:
95128
return {file_cfg.filename: file_cfg for file_cfg in new_files}
96129

97130
@property
98-
def files_to_modify(self) -> List[FileConfig]:
131+
def files_to_modify(self) -> List[FileChange]:
99132
"""Return a list of files to modify."""
100133
files_not_excluded = [
101134
file_cfg.filename

bumpversion/config/utils.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
import itertools
66
from typing import Dict, List
77

8-
from bumpversion.config.models import FileConfig, VersionPartConfig
8+
from bumpversion.config.models import FileChange, VersionPartConfig
99
from bumpversion.utils import labels_for_format
1010

1111

12-
def get_all_file_configs(config_dict: dict) -> List[FileConfig]:
12+
def get_all_file_configs(config_dict: dict) -> List[FileChange]:
1313
"""Make sure all version parts are included."""
1414
defaults = {
1515
"parse": config_dict["parse"],
@@ -22,7 +22,7 @@ def get_all_file_configs(config_dict: dict) -> List[FileConfig]:
2222
files = [{k: v for k, v in filecfg.items() if v is not None} for filecfg in config_dict["files"]]
2323
for f in files:
2424
f.update({k: v for k, v in defaults.items() if k not in f})
25-
return [FileConfig(**f) for f in files]
25+
return [FileChange(**f) for f in files]
2626

2727

2828
def get_all_part_configs(config_dict: dict) -> Dict[str, VersionPartConfig]:
@@ -36,7 +36,7 @@ def get_all_part_configs(config_dict: dict) -> Dict[str, VersionPartConfig]:
3636
}
3737

3838

39-
def resolve_glob_files(file_cfg: FileConfig) -> List[FileConfig]:
39+
def resolve_glob_files(file_cfg: FileChange) -> List[FileChange]:
4040
"""
4141
Return a list of file configurations that match the glob pattern.
4242

0 commit comments

Comments
 (0)