Coverage for /Users/coordt/Documents/code/bump-my-version/bumpversion/config/__init__.py: 82%

43 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-06-12 09:26 -0500

1"""Configuration management.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Any, Union 

6 

7from bumpversion.config.files import read_config_file 

8from bumpversion.config.models import Config 

9from bumpversion.exceptions import ConfigurationError 

10from bumpversion.ui import get_indented_logger 

11 

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

13 from pathlib import Path 

14 

15logger = get_indented_logger(__name__) 

16 

17DEFAULTS = { 

18 "current_version": None, 

19 "parse": r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)", 

20 "serialize": ("{major}.{minor}.{patch}",), 

21 "search": "{current_version}", 

22 "replace": "{new_version}", 

23 "regex": False, 

24 "ignore_missing_version": False, 

25 "ignore_missing_files": False, 

26 "tag": False, 

27 "sign_tags": False, 

28 "tag_name": "v{new_version}", 

29 "tag_message": "Bump version: {current_version} → {new_version}", 

30 "allow_dirty": False, 

31 "commit": False, 

32 "message": "Bump version: {current_version} → {new_version}", 

33 "commit_args": None, 

34 "scm_info": None, 

35 "parts": {}, 

36 "files": [], 

37} 

38 

39 

40def set_config_defaults(parsed_config: dict[str, Any], **overrides: Any) -> dict[str, Any]: 

41 """Apply the defaults to the parsed config.""" 

42 config_dict = DEFAULTS.copy() 

43 

44 # We want to strip out unrecognized key-values to avoid inadvertent issues 

45 config_dict.update({key: val for key, val in parsed_config.items() if key in DEFAULTS.keys()}) 

46 

47 allowed_overrides = set(DEFAULTS.keys()) 

48 config_dict.update({key: val for key, val in overrides.items() if key in allowed_overrides}) 

49 

50 return config_dict 

51 

52 

53def get_configuration(config_file: Union[str, Path, None] = None, **overrides: Any) -> Config: 

54 """ 

55 Return the configuration based on any configuration files and overrides. 

56 

57 Args: 

58 config_file: An explicit configuration file to use, otherwise search for one 

59 **overrides: Specific configuration key-values to override in the configuration 

60 

61 Returns: 

62 The configuration 

63 """ 

64 from bumpversion.config.utils import get_all_file_configs, get_all_part_configs 

65 from bumpversion.scm import SCMInfo, SourceCodeManager, get_scm_info # noqa: F401 

66 

67 logger.info("Reading configuration") 

68 logger.indent() 

69 

70 parsed_config = read_config_file(config_file) if config_file else {} 

71 config_dict = set_config_defaults(parsed_config, **overrides) 

72 

73 # Set any missing version parts 

74 config_dict["parts"] = get_all_part_configs(config_dict) 

75 

76 # Set any missing file configuration 

77 config_dict["files"] = get_all_file_configs(config_dict) 

78 

79 # Resolve the SCMInfo class for Pydantic's BaseSettings 

80 Config.model_rebuild() 

81 config = Config(**config_dict) # type: ignore[arg-type] 

82 

83 # Get the information about the SCM 

84 scm_info = get_scm_info(config.tag_name, config.parse) 

85 config.scm_info = scm_info 

86 

87 # Update and verify the current_version 

88 config.current_version = check_current_version(config) 

89 

90 logger.dedent() 

91 

92 return config 

93 

94 

95def check_current_version(config: Config) -> str: 

96 """ 

97 Returns the current version. 

98 

99 If the current version is not specified in the config file, command line or env variable, 

100 it attempts to retrieve it via a tag. 

101 

102 Args: 

103 config: The current configuration dictionary. 

104 

105 Returns: 

106 The version number 

107 

108 Raises: 

109 ConfigurationError: If it can't find the current version 

110 """ 

111 current_version = config.current_version 

112 scm_info = config.scm_info 

113 

114 if current_version is None and scm_info.current_version: 114 ↛ 115line 114 didn't jump to line 115, because the condition on line 114 was never true

115 return scm_info.current_version 

116 elif current_version and scm_info.current_version and current_version != scm_info.current_version: 116 ↛ 117line 116 didn't jump to line 117, because the condition on line 116 was never true

117 logger.warning( 

118 "Specified version (%s) does not match last tagged version (%s)", 

119 current_version, 

120 scm_info.current_version, 

121 ) 

122 return current_version 

123 elif current_version: 123 ↛ 126line 123 didn't jump to line 126, because the condition on line 123 was never false

124 return current_version 

125 

126 raise ConfigurationError("Unable to determine the current version.")