|
5 | 5 |
|
6 | 6 | from itertools import groupby |
7 | 7 |
|
8 | | -from azure.mgmt.resource.resources.models import ChangeType, PropertyChangeType |
| 8 | +from azure.mgmt.resource.resources.models import ChangeType, PropertyChangeType, Level |
9 | 9 |
|
10 | 10 | from ._symbol import Symbol |
11 | 11 | from ._color import Color, ColoredStringBuilder |
|
30 | 30 | PropertyChangeType.no_effect: Color.GRAY, |
31 | 31 | } |
32 | 32 |
|
| 33 | +_diagnostic_level_to_color = { |
| 34 | + Level.ERROR: Color.RED, |
| 35 | + Level.WARNING: Color.DARK_YELLOW, |
| 36 | + Level.INFO: Color.RESET, |
| 37 | +} |
| 38 | + |
33 | 39 | _change_type_to_symbol = { |
34 | 40 | ChangeType.create: Symbol.PLUS, |
35 | 41 | ChangeType.delete: Symbol.MINUS, |
@@ -73,8 +79,22 @@ def format_what_if_operation_result(what_if_operation_result, enable_color=True) |
73 | 79 | builder = ColoredStringBuilder(enable_color) |
74 | 80 | _format_noise_notice(builder) |
75 | 81 | _format_change_type_legend(builder, what_if_operation_result.changes) |
76 | | - _format_resource_changes(builder, what_if_operation_result.changes) |
77 | | - _format_resource_changes_stats(builder, what_if_operation_result.changes) |
| 82 | + _format_resource_changes(builder, |
| 83 | + what_if_operation_result.changes, |
| 84 | + definite_changes=True) |
| 85 | + _format_resource_changes_stats(builder, |
| 86 | + what_if_operation_result.changes, |
| 87 | + definite_changes=True) |
| 88 | + _format_resource_changes(builder, |
| 89 | + what_if_operation_result.potential_changes, |
| 90 | + definite_changes=False) |
| 91 | + _format_resource_changes_stats(builder, |
| 92 | + what_if_operation_result.potential_changes, |
| 93 | + definite_changes=False) |
| 94 | + _format_diagnostics(builder, |
| 95 | + what_if_operation_result.changes, |
| 96 | + what_if_operation_result.potential_changes, |
| 97 | + what_if_operation_result.diagnostics) |
78 | 98 | return builder.build() |
79 | 99 |
|
80 | 100 |
|
@@ -120,12 +140,15 @@ def populate_change_type_set(property_changes): |
120 | 140 | builder.append_line(change_type.title()) |
121 | 141 |
|
122 | 142 |
|
123 | | -def _format_resource_changes_stats(builder, resource_changes): |
124 | | - builder.append_line().append("Resource changes: ") |
| 143 | +def _format_resource_changes_stats(builder, resource_changes, definite_changes = True): |
| 144 | + if definite_changes: |
| 145 | + builder.append_line().append("Resource changes: ") |
125 | 146 |
|
126 | | - if not resource_changes: |
127 | | - builder.append("no change.") |
128 | | - return |
| 147 | + if not resource_changes: |
| 148 | + builder.append("no change.") |
| 149 | + return |
| 150 | + elif resource_changes: |
| 151 | + builder.append_line().append("Potential changes: ") |
129 | 152 |
|
130 | 153 | sorted_resource_changes = sorted(resource_changes, key=lambda x: _change_type_to_weight[x.change_type]) |
131 | 154 | resource_changes_by_change_type = groupby(sorted_resource_changes, lambda x: x.change_type) |
@@ -155,15 +178,48 @@ def _format_change_type_count(change_type, count): # pylint: disable=too-many-r |
155 | 178 | raise ValueError(f"Invalid ChangeType: {change_type}") |
156 | 179 |
|
157 | 180 |
|
158 | | -def _format_resource_changes(builder, resource_changes): |
| 181 | +def _format_diagnostics(builder, resource_changes, potential_changes, diagnostics): |
| 182 | + short_circuited_resources = [r for r in (resource_changes or []) + (potential_changes or []) if r.change_type == ChangeType.UNSUPPORTED] |
| 183 | + |
| 184 | + diags = diagnostics or [] |
| 185 | + |
| 186 | + if len(short_circuited_resources) + len(diags) > 0: |
| 187 | + builder.append_line() |
| 188 | + builder.append_line() |
| 189 | + builder.append(f"Diagnostics ({len(short_circuited_resources) + len(diags)}): ") |
| 190 | + builder.append_line() |
| 191 | + |
| 192 | + for change in short_circuited_resources: |
| 193 | + with builder.new_color_scope(_diagnostic_level_to_color[Level.WARNING]): |
| 194 | + builder.append(_get_relative_resource_id(change)) |
| 195 | + builder.append(" (Unsupported) ") |
| 196 | + builder.append(change.unsupported_reason) |
| 197 | + builder.append_line() |
| 198 | + |
| 199 | + for diag in diags: |
| 200 | + with builder.new_color_scope(_diagnostic_level_to_color[diag.level]): |
| 201 | + builder.append(diag.target) |
| 202 | + builder.append(" (") |
| 203 | + builder.append(diag.Code) |
| 204 | + builder.append(") ") |
| 205 | + builder.append(diag.message) |
| 206 | + builder.append_line() |
| 207 | + |
| 208 | + |
| 209 | +def _format_resource_changes(builder, resource_changes, definite_changes = True): |
159 | 210 | if not resource_changes: |
160 | 211 | return |
161 | 212 |
|
162 | 213 | num_scopes = len(set(map(_get_scope_uppercase, resource_changes))) |
163 | 214 | resource_changes_by_scope = groupby(sorted(resource_changes, key=_get_scope_uppercase), _get_scope_uppercase) |
164 | 215 |
|
165 | 216 | builder.append_line() |
166 | | - builder.append_line(f"The deployment will update the following {'scope:' if num_scopes == 1 else 'scopes'}") |
| 217 | + if definite_changes: |
| 218 | + builder.append("The deployment will update the following ") |
| 219 | + else: |
| 220 | + builder.append("The following change MAY OR MAY NOT be deployed to the following ") |
| 221 | + |
| 222 | + builder.append_line('scope:' if num_scopes == 1 else 'scopes:') |
167 | 223 |
|
168 | 224 | for _, resource_changes_in_scope in resource_changes_by_scope: |
169 | 225 | resource_changes_in_scope_list = list(resource_changes_in_scope) |
|
0 commit comments