Coverage for /Users/OORDCOR/Documents/code/bump-my-version/bumpversion/visualize.py: 0%

62 statements  

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

1"""Visualize the bumpversion process.""" 

2 

3from dataclasses import dataclass 

4from typing import List, Optional 

5 

6from bumpversion.bump import get_next_version 

7from bumpversion.config import Config 

8from bumpversion.exceptions import BumpVersionError 

9from bumpversion.ui import print_info 

10from bumpversion.utils import base_context, get_context 

11 

12BOX_CHARS = { 

13 "ascii": ["+", "+", "+", "+", "+", "+", "+", "+", "-", "|", "+"], 

14 "light": ["╯", "╮", "╭", "╰", "┤", "┴", "┬", "├", "─", "│", "┼"], 

15} 

16 

17 

18@dataclass 

19class Border: 

20 """A border definition.""" 

21 

22 corner_bottom_right: str 

23 corner_top_right: str 

24 corner_top_left: str 

25 corner_bottom_left: str 

26 divider_left: str 

27 divider_up: str 

28 divider_down: str 

29 divider_right: str 

30 line: str 

31 pipe: str 

32 cross: str 

33 

34 

35def lead_string(version_str: str, border: Border, blank: bool = False) -> str: 

36 """ 

37 Return the first part of a string with the bump character or spaces of the correct amount. 

38 

39 Examples: 

40 >>> lead_string("1.0.0", Border(*BOX_CHARS["light"])) 

41 '1.0.0 ── bump ─' 

42 >>> lead_string("1.0.0", Border(*BOX_CHARS["light"]), blank=True) 

43 ' ' 

44 

45 Args: 

46 version_str: The string to render as the starting point 

47 border: The border definition to draw the lines 

48 blank: If `True`, return a blank string the same length as the version bump string 

49 

50 Returns: 

51 The version bump string or a blank string 

52 """ 

53 version_bump = f"{version_str} {border.line * 2} bump {border.line}" 

54 return " " * len(version_bump) if blank else version_bump 

55 

56 

57def connection_str(border: Border, has_next: bool = False, has_previous: bool = False) -> str: 

58 """ 

59 Return the correct connection string based on the next and previous. 

60 

61 Args: 

62 border: The border definition to draw the lines 

63 has_next: If `True`, there is a next line 

64 has_previous: If `True`, there is a previous line 

65 

66 Returns: 

67 A string that connects left-to-right and top-to-bottom based on the next and previous 

68 """ 

69 if has_next and has_previous: 

70 return border.divider_right + border.line 

71 elif has_next: 

72 return border.divider_down + border.line 

73 elif has_previous: 

74 return border.corner_bottom_left + border.line 

75 else: 

76 return border.line * 2 

77 

78 

79def labeled_line(label: str, border: Border, fit_length: Optional[int] = None) -> str: 

80 """ 

81 Return the version part string with the correct padding. 

82 

83 Args: 

84 label: The label to render 

85 border: The border definition to draw the lines 

86 fit_length: The length to fit the label to 

87 

88 Returns: 

89 A labeled line with leading and trailing spaces 

90 """ 

91 if fit_length is None: 

92 fit_length = len(label) 

93 return f" {label} {border.line * (fit_length - len(label))}{border.line} " 

94 

95 

96def filter_version_parts(config: Config) -> List[str]: 

97 """ 

98 Return the version parts that are in the configuration. 

99 

100 Args: 

101 config: The configuration to check against 

102 

103 Returns: 

104 The version parts that are in the configuration 

105 """ 

106 version_parts = [part for part in config.version_config.order if not part.startswith("$")] 

107 default_context = base_context(config.scm_info) 

108 return [part for part in version_parts if part not in default_context] 

109 

110 

111def visualize(config: Config, version_str: str, box_style: str = "light") -> None: 

112 """Output a visualization of the bump-my-version bump process.""" 

113 version = config.version_config.parse(version_str) 

114 version_parts = filter_version_parts(config) 

115 num_parts = len(version_parts) 

116 

117 box_style = box_style if box_style in BOX_CHARS else "light" 

118 border = Border(*BOX_CHARS[box_style]) 

119 

120 version_lead = lead_string(version_str, border) 

121 blank_lead = lead_string(version_str, border, blank=True) 

122 version_part_length = max(len(part) for part in version_parts) 

123 

124 for i, part in enumerate(version_parts): 

125 line = [version_lead] if i == 0 else [blank_lead] 

126 

127 try: 

128 next_version = get_next_version(version, config, part, None) 

129 next_version_str = config.version_config.serialize(next_version, get_context(config)) 

130 except (BumpVersionError, ValueError) as e: 

131 next_version_str = f"invalid: {e}" 

132 

133 has_next = i < num_parts - 1 

134 has_previous = i > 0 

135 line.append(connection_str(border, has_next=has_next, has_previous=has_previous)) 

136 line.append(labeled_line(part, border, version_part_length)) 

137 line.append(next_version_str) 

138 print_info("".join(line))