mux_tf 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mux_tf/cli/current.rb +3 -0
- data/lib/mux_tf/cli/plan_summary.rb +3 -0
- data/lib/mux_tf/plan_formatter.rb +2 -2
- data/lib/mux_tf/plan_summary_handler.rb +151 -51
- data/lib/mux_tf/resource_tokenizer.rb +7 -0
- data/lib/mux_tf/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86f905c9dcd8264222677f830925cff18e3258d10319be26c339705866ef8118
|
4
|
+
data.tar.gz: e61638e5a1d0a104debdd034cd7aecb9da34bcdd64fee57444967ba516d21f1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 120652ac965f70a186dd189a0cd0fd6fba14c2dc2c9421fe654d209e98432a70298079e86ea33107e61d0b163078db72a9d963971af43d4cddb3df499d2a76b9
|
7
|
+
data.tar.gz: dd063677d9d1f65b8c7e3a4a4d48c7c4bbefec455eda0ce021ddf020c17cb4d4230e0eae17914edec02d3c27a014a97456f4612a46bc11dbbff56fe023d100d5
|
data/lib/mux_tf/cli/current.rb
CHANGED
@@ -20,13 +20,13 @@ module MuxTf
|
|
20
20
|
parser.state(:refreshing, /Refreshing Terraform state in-memory prior to plan.../, %i[none blank info])
|
21
21
|
parser.state(:refresh_done, /^----------+$/, [:refreshing])
|
22
22
|
parser.state(:refresh_done, /^$/, [:refreshing])
|
23
|
-
parser.state(:plan_info, /Terraform will perform the following actions:/, [:refresh_done])
|
23
|
+
parser.state(:plan_info, /Terraform will perform the following actions:/, [:refresh_done, :none])
|
24
24
|
parser.state(:plan_summary, /^Plan:/, [:plan_info])
|
25
25
|
|
26
26
|
parser.state(:error_lock_info, /Lock Info/, [:error])
|
27
27
|
parser.state(:error, /^$/, [:error_lock_info])
|
28
28
|
|
29
|
-
parser.state(:plan_error,
|
29
|
+
parser.state(:plan_error, /^╷|Error: /, %i[refreshing refresh_done])
|
30
30
|
|
31
31
|
status = tf_plan(out: filename, detailed_exitcode: true, compact_warnings: true, targets: targets) { |raw_line|
|
32
32
|
parser.parse(raw_line.rstrip) do |state, line|
|
@@ -32,77 +32,174 @@ module MuxTf
|
|
32
32
|
def initialize(data)
|
33
33
|
@parts = []
|
34
34
|
|
35
|
-
data["
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
35
|
+
if data["output_changes"]
|
36
|
+
data["output_changes"].each do |output_name, v|
|
37
|
+
case v["actions"]
|
38
|
+
when ["no-op"]
|
39
|
+
# do nothing
|
40
|
+
when ["create"]
|
41
|
+
parts << {
|
42
|
+
type: "output",
|
43
|
+
action: "create",
|
44
|
+
after_unknown: v["after_unknown"],
|
45
|
+
sensitive: [v["before_sensitive"], v["after_sensitive"]],
|
46
|
+
address: output_name
|
47
|
+
}
|
48
|
+
when ["update"]
|
49
|
+
parts << {
|
50
|
+
type: "output",
|
51
|
+
action: "update",
|
52
|
+
after_unknown: v["after_unknown"],
|
53
|
+
sensitive: [v["before_sensitive"], v["after_sensitive"]],
|
54
|
+
address: output_name
|
55
|
+
}
|
56
|
+
when ["delete"]
|
57
|
+
parts << {
|
58
|
+
type: "output",
|
59
|
+
action: "delete",
|
60
|
+
after_unknown: v["after_unknown"],
|
61
|
+
sensitive: [v["before_sensitive"], v["after_sensitive"]],
|
62
|
+
address: output_name
|
63
|
+
}
|
64
|
+
else
|
65
|
+
puts "[??] #{output_name}"
|
66
|
+
puts "UNKNOWN ACTIONS: #{v["actions"].inspect}"
|
67
|
+
puts "TODO: update plan_summary to support this!"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if data["resource_changes"]
|
73
|
+
data["resource_changes"].each do |v|
|
74
|
+
next unless v["change"]
|
75
|
+
|
76
|
+
case v["change"]["actions"]
|
77
|
+
when ["no-op"]
|
78
|
+
# do nothing
|
79
|
+
when ["create"]
|
80
|
+
parts << {
|
81
|
+
type: "resource",
|
82
|
+
action: "create",
|
83
|
+
address: v["address"],
|
84
|
+
deps: find_deps(data, v["address"])
|
85
|
+
}
|
86
|
+
when ["update"]
|
87
|
+
parts << {
|
88
|
+
type: "resource",
|
89
|
+
action: "update",
|
90
|
+
address: v["address"],
|
91
|
+
deps: find_deps(data, v["address"])
|
92
|
+
}
|
93
|
+
when ["delete"]
|
94
|
+
parts << {
|
95
|
+
type: "resource",
|
96
|
+
action: "delete",
|
97
|
+
address: v["address"],
|
98
|
+
deps: find_deps(data, v["address"])
|
99
|
+
}
|
100
|
+
when %w[delete create]
|
101
|
+
parts << {
|
102
|
+
type: "resource",
|
103
|
+
action: "replace",
|
104
|
+
address: v["address"],
|
105
|
+
deps: find_deps(data, v["address"])
|
106
|
+
}
|
107
|
+
when ["read"]
|
108
|
+
parts << {
|
109
|
+
type: "resource",
|
110
|
+
action: "read",
|
111
|
+
address: v["address"],
|
112
|
+
deps: find_deps(data, v["address"])
|
113
|
+
}
|
114
|
+
else
|
115
|
+
puts "[??] #{v["address"]}"
|
116
|
+
puts "UNKNOWN ACTIONS: #{v["change"]["actions"].inspect}"
|
117
|
+
puts "TODO: update plan_summary to support this!"
|
118
|
+
end
|
75
119
|
end
|
76
120
|
end
|
77
121
|
|
78
122
|
prune_unchanged_deps(parts)
|
79
123
|
end
|
80
124
|
|
125
|
+
def resource_parts
|
126
|
+
parts.select { |part| part[:type] == "resource" }
|
127
|
+
end
|
128
|
+
|
129
|
+
def output_parts
|
130
|
+
parts.select { |part| part[:type] == "output" }
|
131
|
+
end
|
132
|
+
|
81
133
|
def summary
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
134
|
+
# resources
|
135
|
+
resource_summary = {}
|
136
|
+
resource_parts.each do |part|
|
137
|
+
resource_summary[part[:action]] ||= 0
|
138
|
+
resource_summary[part[:action]] += 1
|
86
139
|
end
|
87
|
-
|
140
|
+
resource_pieces = resource_summary.map { |k, v|
|
88
141
|
color = color_for_action(k)
|
89
142
|
"#{Paint[v, :yellow]} to #{Paint[k, color]}"
|
90
143
|
}
|
91
144
|
|
92
|
-
|
145
|
+
# outputs
|
146
|
+
output_summary = {}
|
147
|
+
output_parts.each do |part|
|
148
|
+
output_summary[part[:action]] ||= 0
|
149
|
+
output_summary[part[:action]] += 1
|
150
|
+
end
|
151
|
+
output_pieces = output_summary.map { |k, v|
|
152
|
+
color = color_for_action(k)
|
153
|
+
"#{Paint[v, :yellow]} to #{Paint[k, color]}"
|
154
|
+
}
|
155
|
+
|
156
|
+
if resource_pieces.any? || output_pieces.any?
|
157
|
+
[
|
158
|
+
"Plan Summary:",
|
159
|
+
resource_pieces.any? ? resource_pieces.join(Paint[", ", :gray]) : nil,
|
160
|
+
output_pieces.any? ? "Outputs: #{output_pieces.join(Paint[", ", :gray])}" : nil
|
161
|
+
].compact.join(" ")
|
162
|
+
else
|
163
|
+
"Plan Summary: no changes"
|
164
|
+
end
|
93
165
|
end
|
94
166
|
|
95
167
|
def flat_summary
|
96
168
|
result = []
|
97
|
-
|
169
|
+
resource_parts.each do |part|
|
98
170
|
result << "[#{format_action(part[:action])}] #{format_address(part[:address])}"
|
99
171
|
end
|
100
172
|
result
|
101
173
|
end
|
102
174
|
|
175
|
+
def sensitive_summary(bv, av)
|
176
|
+
# before vs after
|
177
|
+
if bv && av
|
178
|
+
"(#{Paint["sensitive", :yellow]})"
|
179
|
+
elsif bv
|
180
|
+
"(#{Paint["-sensitive", :red]})"
|
181
|
+
elsif av
|
182
|
+
"(#{Paint["+sensitive", :cyan]})"
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def output_summary
|
187
|
+
result = []
|
188
|
+
output_parts.each do |part|
|
189
|
+
pieces = [
|
190
|
+
"[#{format_action(part[:action])}]",
|
191
|
+
format_address("output.#{part[:address]}"),
|
192
|
+
part[:after_unknown] ? "(unknown)" : nil,
|
193
|
+
sensitive_summary(*part[:sensitive])
|
194
|
+
].compact
|
195
|
+
result << pieces.join(" ")
|
196
|
+
end
|
197
|
+
result
|
198
|
+
end
|
199
|
+
|
103
200
|
def nested_summary
|
104
201
|
result = []
|
105
|
-
parts =
|
202
|
+
parts = resource_parts.deep_dup
|
106
203
|
until parts.empty?
|
107
204
|
part = parts.shift
|
108
205
|
if part[:deps] == []
|
@@ -131,7 +228,7 @@ module MuxTf
|
|
131
228
|
def run_interactive
|
132
229
|
prompt = TTY::Prompt.new
|
133
230
|
result = prompt.multi_select("Update resources:", per_page: 99, echo: false) { |menu|
|
134
|
-
|
231
|
+
resource_parts.each do |part|
|
135
232
|
label = "[#{format_action(part[:action])}] #{format_address(part[:address])}"
|
136
233
|
menu.choice label, part[:address]
|
137
234
|
end
|
@@ -187,14 +284,17 @@ module MuxTf
|
|
187
284
|
plan.flat_summary.each do |line|
|
188
285
|
log line, depth: 2
|
189
286
|
end
|
287
|
+
plan.output_summary.each do |line|
|
288
|
+
log line, depth: 2
|
289
|
+
end
|
190
290
|
log "", depth: 2
|
191
291
|
log plan.summary, depth: 2
|
192
292
|
end
|
193
293
|
|
194
294
|
def prune_unchanged_deps(parts)
|
195
|
-
valid_addresses =
|
295
|
+
valid_addresses = resource_parts.map { |part| part[:address] }
|
196
296
|
|
197
|
-
|
297
|
+
resource_parts.each do |part|
|
198
298
|
part[:deps].select! { |dep| valid_addresses.include?(dep) }
|
199
299
|
end
|
200
300
|
end
|
@@ -32,6 +32,13 @@ class ResourceTokenizer
|
|
32
32
|
pn = n
|
33
33
|
state = :ri
|
34
34
|
end
|
35
|
+
if n == resource.length - 1
|
36
|
+
# last character .. close the current group
|
37
|
+
# the last thing should only ever be an index or a name
|
38
|
+
result << [:rn, resource[pn..n]]
|
39
|
+
pn = n
|
40
|
+
state = :done
|
41
|
+
end
|
35
42
|
when :ri
|
36
43
|
# looking for ]
|
37
44
|
if resource[n] == "]"
|
data/lib/mux_tf/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mux_tf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Banasik
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|