Coverage for /Users/OORDCOR/Documents/code/bump-my-version/bumpversion/config/files_legacy.py: 11%

56 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-15 09:15 -0600

1"""This module handles the legacy config file format.""" 

2from __future__ import annotations 

3 

4import re 

5from difflib import context_diff 

6from pathlib import Path 

7from typing import Any, Dict, Union 

8 

9from bumpversion.ui import get_indented_logger 

10 

11logger = get_indented_logger(__name__) 

12 

13 

14def read_ini_file(file_path: Path) -> Dict[str, Any]: # noqa: C901 

15 """ 

16 Parse an INI file and return a dictionary of sections and their options. 

17 

18 Args: 

19 file_path: The path to the INI file. 

20 

21 Returns: 

22 dict: A dictionary of sections and their options. 

23 """ 

24 import configparser 

25 

26 from bumpversion import autocast 

27 

28 # Create a ConfigParser object and read the INI file 

29 config_parser = configparser.RawConfigParser() 

30 if file_path.name == "setup.cfg": 

31 config_parser = configparser.ConfigParser() 

32 

33 config_parser.read(file_path) 

34 

35 # Create an empty dictionary to hold the parsed sections and options 

36 bumpversion_options: Dict[str, Any] = {"files": [], "parts": {}} 

37 

38 # Loop through each section in the INI file 

39 for section_name in config_parser.sections(): 

40 if not section_name.startswith("bumpversion"): 

41 continue 

42 

43 section_parts = section_name.split(":") 

44 num_parts = len(section_parts) 

45 options = {key: autocast.autocast_value(val) for key, val in config_parser.items(section_name)} 

46 

47 if num_parts == 1: # bumpversion section 

48 bumpversion_options.update(options) 

49 serialize = bumpversion_options.get("serialize", []) 

50 if "message" in bumpversion_options and isinstance(bumpversion_options["message"], list): 

51 bumpversion_options["message"] = ",".join(bumpversion_options["message"]) 

52 if not isinstance(serialize, list): 

53 bumpversion_options["serialize"] = [serialize] 

54 elif num_parts > 1 and section_parts[1].startswith("file"): 

55 file_options = { 

56 "filename": section_parts[2], 

57 } 

58 file_options.update(options) 

59 if "replace" in file_options and isinstance(file_options["replace"], list): 

60 file_options["replace"] = "\n".join(file_options["replace"]) 

61 bumpversion_options["files"].append(file_options) 

62 elif num_parts > 1 and section_parts[1].startswith("glob"): 

63 file_options = { 

64 "glob": section_parts[2], 

65 } 

66 file_options.update(options) 

67 if "replace" in file_options and isinstance(file_options["replace"], list): 

68 file_options["replace"] = "\n".join(file_options["replace"]) 

69 bumpversion_options["files"].append(file_options) 

70 elif num_parts > 1 and section_parts[1].startswith("part"): 

71 bumpversion_options["parts"][section_parts[2]] = options 

72 

73 # Return the dictionary of sections and options 

74 return bumpversion_options 

75 

76 

77def update_ini_config_file( 

78 config_file: Union[str, Path], current_version: str, new_version: str, dry_run: bool = False 

79) -> None: 

80 """ 

81 Update the current_version key in the configuration file. 

82 

83 Instead of parsing and re-writing the config file with new information, it will use 

84 a regular expression to just replace the current_version value. The idea is it will 

85 avoid unintentional changes (like formatting) to the config file. 

86 

87 Args: 

88 config_file: The configuration file to explicitly use. 

89 current_version: The serialized current version. 

90 new_version: The serialized new version. 

91 dry_run: True if the update should be a dry run. 

92 """ 

93 cfg_current_version_regex = re.compile( 

94 f"(?P<section_prefix>\\[bumpversion]\n[^[]*current_version\\s*=\\s*)(?P<version>{current_version})", 

95 re.MULTILINE, 

96 ) 

97 

98 config_path = Path(config_file) 

99 existing_config = config_path.read_text() 

100 if config_path.suffix == ".cfg" and cfg_current_version_regex.search(existing_config): 

101 sub_str = f"\\g<section_prefix>{new_version}" 

102 new_config = cfg_current_version_regex.sub(sub_str, existing_config) 

103 else: 

104 logger.info("Could not find the current version in the config file: %s.", config_path) 

105 return 

106 

107 logger.info( 

108 "%s to config file %s:", 

109 "Would write" if dry_run else "Writing", 

110 config_path, 

111 ) 

112 

113 logger.info( 

114 "\n".join( 

115 list( 

116 context_diff( 

117 existing_config.splitlines(), 

118 new_config.splitlines(), 

119 fromfile=f"before {config_path}", 

120 tofile=f"after {config_path}", 

121 lineterm="", 

122 ) 

123 ) 

124 ) 

125 ) 

126 

127 if not dry_run: 

128 config_path.write_text(new_config)