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

40 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2024-02-24 07:50 -0600

1"""Configuration management.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, 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 get_configuration(config_file: Union[str, Path, None] = None, **overrides) -> Config: 

41 """ 

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

43 

44 Args: 

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

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

47 

48 Returns: 

49 The configuration 

50 """ 

51 from bumpversion.config.utils import get_all_file_configs, get_all_part_configs 

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

53 

54 logger.info("Reading configuration") 

55 logger.indent() 

56 

57 config_dict = DEFAULTS.copy() 

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

59 

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

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

62 

63 allowed_overrides = set(DEFAULTS.keys()) 

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

65 

66 # Set any missing version parts 

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

68 

69 # Set any missing file configuration 

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

71 

72 # Resolve the SCMInfo class for Pydantic's BaseSettings 

73 Config.model_rebuild() 

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

75 

76 # Get the information about the SCM 

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

78 config.scm_info = scm_info 

79 

80 # Update and verify the current_version 

81 config.current_version = check_current_version(config) 

82 

83 logger.dedent() 

84 

85 return config 

86 

87 

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

89 """ 

90 Returns the current version. 

91 

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

93 it attempts to retrieve it via a tag. 

94 

95 Args: 

96 config: The current configuration dictionary. 

97 

98 Returns: 

99 The version number 

100 

101 Raises: 

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

103 """ 

104 current_version = config.current_version 

105 scm_info = config.scm_info 

106 

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

108 return scm_info.current_version 

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

110 logger.warning( 

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

112 current_version, 

113 scm_info.current_version, 

114 ) 

115 return current_version 

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

117 return current_version 

118 

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