Coverage for /Users/coordt/Documents/code/bump-my-version/bumpversion/bump.py: 94%
66 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-06-12 09:26 -0500
« prev ^ index » next coverage.py v7.4.4, created at 2024-06-12 09:26 -0500
1"""Version changing methods."""
3import shlex
4from pathlib import Path
5from typing import TYPE_CHECKING, ChainMap, List, Optional
7if TYPE_CHECKING: # pragma: no-coverage 7 ↛ 8line 7 didn't jump to line 8, because the condition on line 7 was never true
8 from bumpversion.files import ConfiguredFile
9 from bumpversion.versioning.models import Version
11from bumpversion.config import Config
12from bumpversion.config.files import update_config_file
13from bumpversion.config.files_legacy import update_ini_config_file
14from bumpversion.context import get_context
15from bumpversion.exceptions import ConfigurationError
16from bumpversion.ui import get_indented_logger
17from bumpversion.utils import key_val_string
19logger = get_indented_logger(__name__)
22def get_next_version(
23 current_version: "Version", config: Config, version_part: Optional[str], new_version: Optional[str]
24) -> "Version":
25 """
26 Bump the version_part to the next value.
28 Args:
29 current_version: The current version
30 config: The current configuration
31 version_part: Optional part of the version to bump
32 new_version: Optional specific version to bump to
34 Returns:
35 The new version
37 Raises:
38 ConfigurationError: If it can't generate the next version.
39 """
40 if new_version:
41 logger.info("Attempting to set new version '%s'", new_version)
42 logger.indent()
43 next_version = config.version_config.parse(new_version)
44 elif version_part:
45 logger.info("Attempting to increment part '%s'", version_part)
46 logger.indent()
47 next_version = current_version.bump(version_part)
48 else:
49 raise ConfigurationError("Unable to get the next version.")
51 logger.info("Values are now: %s", key_val_string(next_version.components))
52 logger.dedent()
53 return next_version
56def do_bump(
57 version_part: Optional[str],
58 new_version: Optional[str],
59 config: Config,
60 config_file: Optional[Path] = None,
61 dry_run: bool = False,
62) -> None:
63 """
64 Bump the version_part to the next value or set the version to new_version.
66 Args:
67 version_part: The version part to bump
68 new_version: The explicit version to set
69 config: The configuration to use
70 config_file: The configuration file to update
71 dry_run: True if the operation should be a dry run
72 """
73 from bumpversion.files import modify_files, resolve_file_config
75 logger.indent()
77 ctx = get_context(config)
78 logger.info("Parsing current version '%s'", config.current_version)
79 logger.indent()
80 version = config.version_config.parse(config.current_version)
81 logger.dedent()
82 next_version = get_next_version(version, config, version_part, new_version)
83 next_version_str = config.version_config.serialize(next_version, ctx)
84 logger.info("New version will be '%s'", next_version_str)
86 if config.current_version == next_version_str:
87 logger.info("Version is already '%s'", next_version_str)
88 return
90 logger.dedent()
92 if dry_run:
93 logger.info("Dry run active, won't touch any files.")
95 ctx = get_context(config, version, next_version)
97 configured_files = resolve_file_config(config.files_to_modify, config.version_config)
99 if version_part:
100 # filter the files that are not valid for this bump
101 configured_files = [file for file in configured_files if version_part in file.file_change.include_bumps]
102 configured_files = [file for file in configured_files if version_part not in file.file_change.exclude_bumps]
104 modify_files(configured_files, version, next_version, ctx, dry_run)
105 if config_file and config_file.suffix in {".cfg", ".ini"}: 105 ↛ 106line 105 didn't jump to line 106, because the condition on line 105 was never true
106 update_ini_config_file(config_file, config.current_version, next_version_str, dry_run) # pragma: no-coverage
107 else:
108 update_config_file(config_file, config, version, next_version, ctx, dry_run)
110 ctx = get_context(config, version, next_version)
111 ctx["new_version"] = next_version_str
112 commit_and_tag(config, config_file, configured_files, ctx, dry_run)
113 logger.info("Done.")
116def commit_and_tag(
117 config: Config,
118 config_file: Optional[Path],
119 configured_files: List["ConfiguredFile"],
120 ctx: ChainMap,
121 dry_run: bool = False,
122) -> None:
123 """
124 Commit and tag the changes if a tool is configured.
126 Args:
127 config: The configuration
128 config_file: The configuration file to include in the commit, if it exists
129 configured_files: A list of files to commit
130 ctx: The context used to render the tag and tag message
131 dry_run: True if the operation should be a dry run
132 """
133 if not config.scm_info.tool:
134 return
136 extra_args = shlex.split(config.commit_args) if config.commit_args else []
138 commit_files = {f.file_change.filename for f in configured_files}
139 if config_file:
140 commit_files |= {str(config_file)}
142 config.scm_info.tool.commit_to_scm(list(commit_files), config, ctx, extra_args, dry_run)
143 config.scm_info.tool.tag_in_scm(config, ctx, dry_run)