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

1"""Contains methods for finding and reading configuration files."""

2

3 from __future__ import annotations

4

5 from pathlib import Path

6 from typing import TYPE_CHECKING, Any, Dict, MutableMapping, Union

7

8 from bumpversion.config.files_legacy import read_ini_file

9 from bumpversion.ui import get_indented_logger, print_warning

10

11 if TYPE_CHECKING: # pragma: no-coverage 11 ↛ 12line 11 didn't jump to line 12, because the condition on line 11 was never true

12 from bumpversion.config.models import Config

13 from bumpversion.versioning.models import Version

14

15 logger = get_indented_logger(__name__)

16

17 CONFIG_FILE_SEARCH_ORDER = (

18 ".bumpversion.cfg",

19 ".bumpversion.toml",

20 "setup.cfg",

21 "pyproject.toml",

22)

23

24

25 def find_config_file(explicit_file: Union[str, Path, None] = None) -> Union[Path, None]:

26 """

27 Find the configuration file, if it exists.

28

29 If no explicit configuration file is passed, it will search in several files to

30 find its configuration.

31

32 Args:

33 explicit_file: The configuration file to explicitly use.

34

35 Returns:

36 The configuration file path

37 """

38 search_paths = (

39 [Path(explicit_file)] if explicit_file else [Path.cwd().joinpath(path) for path in CONFIG_FILE_SEARCH_ORDER]

40 )

41 return next(

42 (

43 cfg_file

44 for cfg_file in search_paths

45 if cfg_file.exists() and "bumpversion]" in cfg_file.read_text(encoding="utf-8")

46 ),

47 None,

48 )

49

50

51 def read_config_file(config_file: Union[str, Path, None] = None) -> Dict[str, Any]:

52 """

53 Read the configuration file, if it exists.

54

55 If no explicit configuration file is passed, it will search in several files to

56 find its configuration.

57

58 Args:

59 config_file: The configuration file to explicitly use.

60

61 Returns:

62 A dictionary of read key-values

63 """

64 if not config_file: 64 ↛ 65line 64 didn't jump to line 65, because the condition on line 64 was never true

65 logger.info("No configuration file found.")

66 return {}

67

68 config_path = Path(config_file)

69 if not config_path.exists():

70 logger.info("Configuration file not found: %s.", config_path)

71 return {}

72

73 logger.info("Reading config file: %s", config_file)

74

75 if config_path.suffix == ".cfg": 75 ↛ 76line 75 didn't jump to line 76, because the condition on line 75 was never true

76 print_warning("The .cfg file format is deprecated. Please use .toml instead.")

77 return read_ini_file(config_path)

78 elif config_path.suffix == ".toml": 78 ↛ 81line 78 didn't jump to line 81, because the condition on line 78 was never false

79 return read_toml_file(config_path)

80 else:

81 logger.info("Unknown config file suffix: %s. Using defaults.", config_path.suffix)

82 return {}

83

84

85 def read_toml_file(file_path: Path) -> Dict[str, Any]:

86 """

87 Parse a TOML file and return the `bumpversion` section.

88

89 Args:

90 file_path: The path to the TOML file.

91

92 Returns:

93 dict: A dictionary of the `bumpversion` section.

94 """

95 import tomlkit

96

97 # Load the TOML file

98 toml_data = tomlkit.parse(file_path.read_text(encoding="utf-8")).unwrap()

99

100 return toml_data.get("tool", {}).get("bumpversion", {})

101

102

103 def update_config_file(

104 config_file: Union[str, Path],

105 config: Config,

106 current_version: Version,

107 new_version: Version,

108 context: MutableMapping,

109 dry_run: bool = False,

110) -> None:

111 """

112 Update the current_version key in the configuration file.

113

114 Args:

115 config_file: The configuration file to explicitly use.

116 config: The configuration to use.

117 current_version: The current version.

118 new_version: The new version.

119 context: The context to use for serialization.

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

121 """

122 from bumpversion.config.models import FileChange

123 from bumpversion.files import DataFileUpdater

124

125 if not config_file: 125 ↛ 126line 125 didn't jump to line 126, because the condition on line 125 was never true

126 logger.info("\n%sNo configuration file found to update.", logger.indent_str)

127 return

128 else:

129 logger.info("\n%sProcessing config file: %s", logger.indent_str, config_file)

130 logger.indent()

131 config_path = Path(config_file)

132 if config_path.suffix != ".toml": 132 ↛ 133line 132 didn't jump to line 133, because the condition on line 132 was never true

133 logger.info("You must have a `.toml` suffix to update the config file: %s.", config_path)

134 return

135

136 # TODO: Eventually this should be transformed into another default "files_to_modify" entry

137 datafile_config = FileChange(

138 filename=str(config_path),

139 key_path="tool.bumpversion.current_version",

140 search=config.search,

141 replace=config.replace,

142 regex=config.regex,

143 ignore_missing_version=True,

144 ignore_missing_file=True,

145 serialize=config.serialize,

146 parse=config.parse,

147 )

148

149 updater = DataFileUpdater(datafile_config, config.version_config.part_configs)

150 updater.update_file(current_version, new_version, context, dry_run)

151 logger.dedent()