Coverage for /Users/OORDCOR/Documents/code/bump-my-version/bumpversion/config/__init__.py: 23%
40 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-15 09:15 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-15 09:15 -0600
1"""Configuration management."""
2from __future__ import annotations
4from typing import TYPE_CHECKING, Union
6from bumpversion.config.files import read_config_file
7from bumpversion.config.models import Config
8from bumpversion.exceptions import ConfigurationError
9from bumpversion.ui import get_indented_logger
11if 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 pathlib import Path
14logger = get_indented_logger(__name__)
16DEFAULTS = {
17 "current_version": None,
18 "parse": r"(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)",
19 "serialize": ["{major}.{minor}.{patch}"],
20 "search": "{current_version}",
21 "replace": "{new_version}",
22 "regex": False,
23 "ignore_missing_version": False,
24 "tag": False,
25 "sign_tags": False,
26 "tag_name": "v{new_version}",
27 "tag_message": "Bump version: {current_version} → {new_version}",
28 "allow_dirty": False,
29 "commit": False,
30 "message": "Bump version: {current_version} → {new_version}",
31 "commit_args": None,
32 "scm_info": None,
33 "parts": {},
34 "files": [],
35}
38def get_configuration(config_file: Union[str, Path, None] = None, **overrides) -> Config:
39 """
40 Return the configuration based on any configuration files and overrides.
42 Args:
43 config_file: An explicit configuration file to use, otherwise search for one
44 **overrides: Specific configuration key-values to override in the configuration
46 Returns:
47 The configuration
48 """
49 from bumpversion.config.utils import get_all_file_configs, get_all_part_configs
50 from bumpversion.scm import SCMInfo, SourceCodeManager, get_scm_info # noqa: F401
52 logger.info("Reading configuration")
53 logger.indent()
55 config_dict = DEFAULTS.copy()
56 parsed_config = read_config_file(config_file) if config_file else {}
58 # We want to strip out unrecognized key-values to avoid inadvertent issues
59 config_dict.update({key: val for key, val in parsed_config.items() if key in DEFAULTS.keys()})
61 allowed_overrides = set(DEFAULTS.keys())
62 config_dict.update({key: val for key, val in overrides.items() if key in allowed_overrides})
64 # Set any missing version parts
65 config_dict["parts"] = get_all_part_configs(config_dict)
67 # Set any missing file configuration
68 config_dict["files"] = get_all_file_configs(config_dict)
70 # Resolve the SCMInfo class for Pydantic's BaseSettings
71 Config.model_rebuild()
72 config = Config(**config_dict) # type: ignore[arg-type]
74 # Get the information about the SCM
75 scm_info = get_scm_info(config.tag_name, config.parse)
76 config.scm_info = scm_info
78 # Update and verify the current_version
79 config.current_version = check_current_version(config)
81 logger.dedent()
83 return config
86def check_current_version(config: Config) -> str:
87 """
88 Returns the current version.
90 If the current version is not specified in the config file, command line or env variable,
91 it attempts to retrieve it via a tag.
93 Args:
94 config: The current configuration dictionary.
96 Returns:
97 The version number
99 Raises:
100 ConfigurationError: If it can't find the current version
101 """
102 current_version = config.current_version
103 scm_info = config.scm_info
105 if current_version is None and scm_info.current_version:
106 return scm_info.current_version
107 elif current_version and scm_info.current_version and current_version != scm_info.current_version:
108 logger.warning(
109 "Specified version (%s) does not match last tagged version (%s)",
110 current_version,
111 scm_info.current_version,
112 )
113 return current_version
114 elif current_version:
115 return current_version
117 raise ConfigurationError("Unable to determine the current version.")