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
« prev ^ index » next coverage.py v7.3.2, created at 2024-02-24 07:45 -0600
1"""Visualize the bumpversion process."""
3from dataclasses import dataclass
4from typing import List, Optional
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
12BOX_CHARS = {
13 "ascii": ["+", "+", "+", "+", "+", "+", "+", "+", "-", "|", "+"],
14 "light": ["╯", "╮", "╭", "╰", "┤", "┴", "┬", "├", "─", "│", "┼"],
15}
18@dataclass
19class Border:
20 """A border definition."""
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
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.
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 ' '
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
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
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.
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
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
79def labeled_line(label: str, border: Border, fit_length: Optional[int] = None) -> str:
80 """
81 Return the version part string with the correct padding.
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
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} "
96def filter_version_parts(config: Config) -> List[str]:
97 """
98 Return the version parts that are in the configuration.
100 Args:
101 config: The configuration to check against
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]
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)
117 box_style = box_style if box_style in BOX_CHARS else "light"
118 border = Border(*BOX_CHARS[box_style])
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)
124 for i, part in enumerate(version_parts):
125 line = [version_lead] if i == 0 else [blank_lead]
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}"
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))