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

1"""Version changing methods.""" 

2 

3import shlex 

4from pathlib import Path 

5from typing import TYPE_CHECKING, ChainMap, List, Optional 

6 

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 

10 

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 

18 

19logger = get_indented_logger(__name__) 

20 

21 

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. 

27 

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 

33 

34 Returns: 

35 The new version 

36 

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.") 

50 

51 logger.info("Values are now: %s", key_val_string(next_version.components)) 

52 logger.dedent() 

53 return next_version 

54 

55 

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. 

65 

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 

74 

75 logger.indent() 

76 

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) 

85 

86 if config.current_version == next_version_str: 

87 logger.info("Version is already '%s'", next_version_str) 

88 return 

89 

90 logger.dedent() 

91 

92 if dry_run: 

93 logger.info("Dry run active, won't touch any files.") 

94 

95 ctx = get_context(config, version, next_version) 

96 

97 configured_files = resolve_file_config(config.files_to_modify, config.version_config) 

98 

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] 

103 

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) 

109 

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.") 

114 

115 

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. 

125 

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 

135 

136 extra_args = shlex.split(config.commit_args) if config.commit_args else [] 

137 

138 commit_files = {f.file_change.filename for f in configured_files} 

139 if config_file: 

140 commit_files |= {str(config_file)} 

141 

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)