mux_tf 0.13.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab68c9969748e0246a48cb2bf53876b0b2f47993b021017e1e9bb31782a7e4b4
4
- data.tar.gz: 63fb2194ba923f3c30c9480f50946c550e85ea9e7e1988fdcc1764cbe7666f6a
3
+ metadata.gz: f9a03af7a131fd34e58d5fb27d3c578154f49246634a684980e6ebc16aa28d08
4
+ data.tar.gz: d093d1604dabbeb1aed8ef5b1ebc3e33a0b5e3575602f7b3802796b2b51f7a7a
5
5
  SHA512:
6
- metadata.gz: e8d1442c6cff1c7c0828347176b1cc0a49fa28fb5a27e0212e730e3bf176fc4a072ba247e9cbf6d248c488fb1c62ffc6a71181dbde47e0b35a759b798ded6886
7
- data.tar.gz: 3d85fc7be2b58bd815060145c33bccf7dc5814a5ee3a052f5adc6a4c7512792e290f0b1bb26faa07d4f950aab81036bcf9c09b91c2a3a20878fcd70601bd2044
6
+ metadata.gz: 7809b83e63a8aa17671ef6fbaac79a09cd7aa8216fdd1ccd390f2e32ee0b4ec0a85e4f6653d4c4bbbafcb99d47076413a9135f970f4d4c0f7f8608b2e8858f5f
7
+ data.tar.gz: c9dd73ed72236b568c7bbdc34ede9701e1d1db94403ccd2e84ee611cd58500e73810f50c9c0bdd6817c2ef7f8bd5d504fd945d86d340db95d9246e797376efb4
data/exe/tf_current CHANGED
@@ -11,6 +11,8 @@ begin
11
11
  rescue Interrupt
12
12
  warn "\nInterrupted"
13
13
  exit 1
14
+ rescue SystemExit => e
15
+ exit e.status
14
16
  rescue Exception => e # rubocop:disable Lint/RescueException
15
17
  warn e.full_message
16
18
  warn "<press enter>"
data/exe/tf_mux CHANGED
@@ -11,6 +11,8 @@ begin
11
11
  rescue Interrupt
12
12
  warn "\nInterrupted"
13
13
  exit 1
14
+ rescue SystemExit => e
15
+ exit e.status
14
16
  rescue Exception => e # rubocop:disable Lint/RescueException
15
17
  warn e.full_message
16
18
  warn "<press enter>"
data/exe/tf_plan_summary CHANGED
@@ -11,6 +11,8 @@ begin
11
11
  rescue Interrupt
12
12
  warn "\nInterrupted"
13
13
  exit 1
14
+ rescue SystemExit => e
15
+ exit e.status
14
16
  rescue Exception => e # rubocop:disable Lint/RescueException
15
17
  warn e.full_message
16
18
  warn "<press enter>"
data/lib/deps.rb CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  require "bundler/inline"
4
4
 
5
- gemfile do
5
+ dep_def = proc do
6
6
  gemspec(path: File.join(__dir__, ".."))
7
7
  end
8
+
9
+ begin
10
+ gemfile(&dep_def)
11
+ rescue Bundler::GemNotFound
12
+ gemfile(true) do
13
+ source "https://rubygems.org"
14
+ instance_exec(&dep_def)
15
+ end
16
+ end
@@ -9,8 +9,9 @@ module MuxTf
9
9
  extend PiotrbCliUtils::Util
10
10
  extend PiotrbCliUtils::CriCommandSupport
11
11
  extend PiotrbCliUtils::CmdLoop
12
+ include Coloring
12
13
 
13
- class << self
14
+ class << self # rubocop:disable Metrics/ClassLength
14
15
  def run(args)
15
16
  version_check
16
17
 
@@ -19,8 +20,21 @@ module MuxTf
19
20
  return
20
21
  end
21
22
 
23
+ unless args.empty?
24
+ root_cmd = build_root_cmd
25
+ valid_commands = root_cmd.subcommands.map(&:name)
26
+
27
+ if args[0] && valid_commands.include?(args[0])
28
+ stop_reason = catch(:stop) {
29
+ root_cmd.run(args, {}, hard_exit: true)
30
+ }
31
+ log pastel.red("Stopped: #{stop_reason}") if stop_reason
32
+ return
33
+ end
34
+ end
35
+
22
36
  folder_name = File.basename(Dir.getwd)
23
- log "Processing #{Paint[folder_name, :cyan]} ..."
37
+ log "Processing #{pastel.cyan(folder_name)} ..."
24
38
 
25
39
  ENV["TF_IN_AUTOMATION"] = "1"
26
40
  ENV["TF_INPUT"] = "0"
@@ -55,52 +69,102 @@ module MuxTf
55
69
  def version_check
56
70
  return unless VersionCheck.has_updates?
57
71
 
58
- log Paint["=" * 80, :yellow]
59
- log "New version of #{Paint['mux_tf', :cyan]} is available!"
60
- log "You are currently on version: #{Paint[VersionCheck.current_gem_version, :yellow]}"
61
- log "Latest version found is: #{Paint[VersionCheck.latest_gem_version, :green]}"
62
- log "Run `#{Paint['gem install mux_tf', :green]}` to update!"
63
- log Paint["=" * 80, :yellow]
72
+ log pastel.yellow("=" * 80)
73
+ log "New version of #{pastel.cyan('mux_tf')} is available!"
74
+ log "You are currently on version: #{pastel.yellow(VersionCheck.current_gem_version)}"
75
+ log "Latest version found is: #{pastel.green(VersionCheck.latest_gem_version)}"
76
+ log "Run `#{pastel.green('gem install mux_tf')}` to update!"
77
+ log pastel.yellow("=" * 80)
64
78
  end
65
79
 
66
- def run_validate
67
- remedies = PlanFormatter.process_validation(validate)
68
- status, _results = process_remedies(remedies)
69
- status
80
+ # block is expected to return a touple, the first element is a list of remedies
81
+ # the rest are any additional results
82
+ def remedy_retry_helper(from:, level: 1, attempt: 0, &block)
83
+ catch(:abort) do
84
+ until attempt > 1
85
+ attempt += 1
86
+ remedies, *results = block.call
87
+ return results if remedies.empty?
88
+
89
+ remedy_status, _remedy_results = process_remedies(remedies, from: from, level: level)
90
+ return unless remedy_status
91
+ end
92
+ log "!! giving up because attempt: #{attempt}"
93
+ end
94
+ end
95
+
96
+ # returns boolean true if succeeded
97
+ def run_validate(level: 1)
98
+ remedy_retry_helper(from: :validate, level: level) do
99
+ validation_info = validate
100
+ PlanFormatter.print_validation_errors(validation_info)
101
+ remedies = PlanFormatter.process_validation(validation_info)
102
+ [remedies, validation_info]
103
+ end
70
104
  end
71
105
 
72
- def process_remedies(remedies, retry_count: 0) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
106
+ def process_remedies(remedies, from: nil, level: 1, retry_count: 0) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
107
+ remedies = remedies.dup
108
+ remedy = nil
109
+ wrap_log = lambda do |msg, color: nil|
110
+ [
111
+ from ? pastel.cyan("#{from} -> ") : nil,
112
+ pastel.cyan(remedy ? "[remedy: #{remedy}]" : "[process remedies]"),
113
+ " ",
114
+ color ? pastel.decorate(msg, color) : msg,
115
+ " ",
116
+ level > 1 ? pastel.cyan("[lv #{level}]") : nil,
117
+ retry_count.positive? ? pastel.cyan("[try #{retry_count}]") : nil
118
+ ].compact.join
119
+ end
73
120
  results = {}
74
121
  if retry_count > 5
75
- log "giving up because retry_count: #{retry_count}", depth: 1
76
- log "unprocessed remedies: #{remedies.to_a}", depth: 1
122
+ log wrap_log["giving up because retry_count: #{retry_count}", color: :yellow], depth: 1
123
+ log wrap_log["unprocessed remedies: #{remedies.to_a}", color: :red], depth: 1
77
124
  return [false, results]
78
125
  end
79
126
  if remedies.delete? :init
80
- log "[remedy] Running terraform init ...", depth: 2
81
- remedies = PlanFormatter.init_status_to_remedies(*PlanFormatter.run_tf_init)
82
- status, r_results = process_remedies(remedies)
127
+ remedy = :init
128
+ log wrap_log["Running terraform init ..."], depth: 2
129
+ exit_code, meta = PlanFormatter.run_tf_init
130
+ print_errors_and_warnings(meta)
131
+ remedies = PlanFormatter.init_status_to_remedies(exit_code, meta)
132
+ status, r_results = process_remedies(remedies, from: from, level: level + 1)
83
133
  results.merge!(r_results)
84
- if status
85
- remedies = PlanFormatter.process_validation(validate)
86
- return [false, results] unless process_remedies(remedies)
87
- end
134
+ return [true, r_results] if status
88
135
  end
89
136
  if remedies.delete?(:plan)
90
- log "[remedy] Running terraform plan ...", depth: 2
137
+ remedy = :plan
138
+ log wrap_log["Running terraform plan ..."], depth: 2
91
139
  plan_status = run_plan(retry_count: retry_count)
92
140
  results[:plan_status] = plan_status
93
141
  return [false, results] unless [:ok, :changes].include?(plan_status)
94
142
  end
95
143
  if remedies.delete? :reconfigure
96
- log "[remedy] Running terraform init ...", depth: 2
97
- remedies = PlanFormatter.init_status_to_remedies(*PlanFormatter.run_tf_init(reconfigure: true))
98
- status, r_results = process_remedies(remedies)
99
- results.merge!(r_results)
100
- return [false, results] unless status
144
+ remedy = :reconfigure
145
+ log wrap_log["Running terraform init ..."], depth: 2
146
+ result = remedy_retry_helper(from: :reconfigure, level: level + 1, attempt: retry_count) {
147
+ exit_code, meta = PlanFormatter.run_tf_init(reconfigure: true)
148
+ print_errors_and_warnings(meta)
149
+ remedies = PlanFormatter.init_status_to_remedies(exit_code, meta)
150
+ [remedies, exit_code, meta]
151
+ }
152
+ unless result
153
+ log wrap_log["Failed", color: :red], depth: 2
154
+ return [false, result]
155
+ end
156
+ end
157
+ if remedies.delete? :user_error
158
+ remedy = :user_error
159
+ log wrap_log["user error encountered!", color: :red]
160
+ log wrap_log["-" * 40, color: :red]
161
+ log wrap_log["!! User Error, Please fix the issue and try again", color: :red]
162
+ log wrap_log["-" * 40, color: :red]
163
+ return [false, results]
101
164
  end
102
165
  unless remedies.empty?
103
- log "unprocessed remedies: #{remedies.to_a}", depth: 1
166
+ remedy = nil
167
+ log wrap_log["Unprocessed remedies: #{remedies.to_a}", color: :red], depth: 1 if level == 1
104
168
  return [false, results]
105
169
  end
106
170
  [true, results]
@@ -122,7 +186,7 @@ module MuxTf
122
186
  when 2
123
187
  [:changes, meta]
124
188
  else
125
- log Paint["terraform plan exited with an unknown exit code: #{exit_code}", :yellow]
189
+ log pastel.yellow("terraform plan exited with an unknown exit code: #{exit_code}")
126
190
  [:unknown, meta]
127
191
  end
128
192
  end
@@ -132,9 +196,9 @@ module MuxTf
132
196
 
133
197
  case status
134
198
  when :error, :unknown
135
- log Paint["Dropping to command line so you can fix the issue!", :red]
199
+ log pastel.red("Dropping to command line so you can fix the issue!")
136
200
  when :changes
137
- log Paint["Dropping to command line so you can review the changes.", :yellow]
201
+ log pastel.yellow("Dropping to command line so you can review the changes.")
138
202
  end
139
203
  cmd_loop(status)
140
204
  end
@@ -149,9 +213,9 @@ module MuxTf
149
213
  prompt = "#{folder_name} => "
150
214
  case status
151
215
  when :error, :unknown
152
- prompt = "[#{Paint[status.to_s, :red]}] #{prompt}"
216
+ prompt = "[#{pastel.red(status.to_s)}] #{prompt}"
153
217
  when :changes
154
- prompt = "[#{Paint[status.to_s, :yellow]}] #{prompt}"
218
+ prompt = "[#{pastel.yellow(status.to_s)}] #{prompt}"
155
219
  end
156
220
 
157
221
  run_cmd_loop(prompt) do |cmd|
@@ -171,11 +235,31 @@ module MuxTf
171
235
  root_cmd.add_command(upgrade_cmd)
172
236
  root_cmd.add_command(reconfigure_cmd)
173
237
  root_cmd.add_command(interactive_cmd)
238
+ root_cmd.add_command(plan_details_cmd)
174
239
 
175
240
  root_cmd.add_command(exit_cmd)
241
+ root_cmd.add_command(define_cmd("help", summary: "Show help for commands") { |_opts, _args, cmd| puts cmd.supercommand.help })
176
242
  root_cmd
177
243
  end
178
244
 
245
+ def plan_summary_text
246
+ plan_filename = PlanFilenameGenerator.for_path
247
+ if File.exist?("#{plan_filename}.txt") && File.mtime("#{plan_filename}.txt").to_f >= File.mtime(plan_filename).to_f
248
+ File.read("#{plan_filename}.txt")
249
+ else
250
+ puts "Inspecting Changes ... #{plan_filename}"
251
+ data = PlanUtils.text_version_of_plan_show(plan_filename)
252
+ File.write("#{plan_filename}.txt", data)
253
+ data
254
+ end
255
+ end
256
+
257
+ def plan_details_cmd
258
+ define_cmd("details", summary: "Show Plan Details") do |_opts, _args, _cmd|
259
+ puts plan_summary_text
260
+ end
261
+ end
262
+
179
263
  def plan_cmd
180
264
  define_cmd("plan", summary: "Re-run plan") do |_opts, _args, _cmd|
181
265
  run_validate && run_plan
@@ -196,28 +280,30 @@ module MuxTf
196
280
 
197
281
  def shell_cmd
198
282
  define_cmd("shell", summary: "Open your default terminal in the current folder") do |_opts, _args, _cmd|
199
- log Paint["Launching shell ...", :yellow]
200
- log Paint["When it exits you will be back at this prompt.", :yellow]
283
+ log pastel.yellow("Launching shell ...")
284
+ log pastel.yellow("When it exits you will be back at this prompt.")
201
285
  system ENV.fetch("SHELL")
202
286
  end
203
287
  end
204
288
 
205
289
  def force_unlock_cmd
206
- define_cmd("force-unlock", summary: "Force unlock state after encountering a lock error!") do
290
+ define_cmd("force-unlock", summary: "Force unlock state after encountering a lock error!") do # rubocop:disable Metrics/BlockLength
207
291
  prompt = TTY::Prompt.new(interrupt: :noop)
208
292
 
209
- table = TTY::Table.new(header: %w[Field Value])
210
- table << ["Lock ID", @plan_meta["ID"]]
211
- table << ["Operation", @plan_meta["Operation"]]
212
- table << ["Who", @plan_meta["Who"]]
213
- table << ["Created", @plan_meta["Created"]]
293
+ lock_info = @last_lock_info
294
+
295
+ if lock_info
296
+ table = TTY::Table.new(header: %w[Field Value])
297
+ table << ["Lock ID", lock_info[:lock_id]]
298
+ table << ["Operation", lock_info[:operation]]
299
+ table << ["Who", lock_info[:who]]
300
+ table << ["Created", lock_info[:created]]
214
301
 
215
- puts table.render(:unicode, padding: [0, 1])
302
+ puts table.render(:unicode, padding: [0, 1])
216
303
 
217
- if @plan_meta && @plan_meta["error"] == "lock"
218
304
  done = catch(:abort) {
219
- if @plan_meta["Operation"] != "OperationTypePlan" && !prompt.yes?(
220
- "Are you sure you want to force unlock a lock for operation: #{@plan_meta['Operation']}",
305
+ if lock_info[:operation] != "OperationTypePlan" && !prompt.yes?(
306
+ "Are you sure you want to force unlock a lock for operation: #{lock_info[:operation]}",
221
307
  default: false
222
308
  )
223
309
  throw :abort
@@ -228,19 +314,19 @@ module MuxTf
228
314
  default: false
229
315
  )
230
316
 
231
- status = tf_force_unlock(id: @plan_meta["ID"])
317
+ status = tf_force_unlock(id: lock_info[:lock_id])
232
318
  if status.success?
233
319
  log "Done!"
234
320
  else
235
- log Paint["Failed with status: #{status}", :red]
321
+ log pastel.red("Failed with status: #{status}")
236
322
  end
237
323
 
238
324
  true
239
325
  }
240
326
 
241
- log Paint["Aborted", :yellow] unless done
327
+ log pastel.yellow("Aborted") unless done
242
328
  else
243
- log Paint["No lock error or no plan ran!", :red]
329
+ log pastel.red("No lock error or no plan ran!")
244
330
  end
245
331
  end
246
332
  end
@@ -257,8 +343,9 @@ module MuxTf
257
343
 
258
344
  def reconfigure_cmd
259
345
  define_cmd("reconfigure", summary: "Reconfigure modules/plguins") do |_opts, _args, _cmd|
260
- status, meta = PlanFormatter.run_tf_init(reconfigure: true)
261
- if status != 0
346
+ exit_code, meta = PlanFormatter.run_tf_init(reconfigure: true)
347
+ print_errors_and_warnings(meta)
348
+ if exit_code != 0
262
349
  log meta.inspect unless meta.empty?
263
350
  log "Reconfigure Failed!"
264
351
  end
@@ -271,7 +358,7 @@ module MuxTf
271
358
  begin
272
359
  abort_message = catch(:abort) { plan.run_interactive }
273
360
  if abort_message
274
- log Paint["Aborted: #{abort_message}", :red]
361
+ log pastel.red("Aborted: #{abort_message}")
275
362
  else
276
363
  run_plan
277
364
  end
@@ -282,30 +369,30 @@ module MuxTf
282
369
  end
283
370
  end
284
371
 
285
- def print_errors_and_warnings # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
372
+ def print_errors_and_warnings(meta) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
286
373
  message = []
287
- message << Paint["#{@plan_meta[:warnings].length} Warnings", :yellow] if @plan_meta[:warnings]
288
- message << Paint["#{@plan_meta[:errors].length} Errors", :red] if @plan_meta[:errors]
374
+ message << pastel.yellow("#{meta[:warnings].length} Warnings") if meta[:warnings]
375
+ message << pastel.red("#{meta[:errors].length} Errors") if meta[:errors]
289
376
  if message.length.positive?
290
377
  log ""
291
378
  log "Encountered: #{message.join(' and ')}"
292
379
  log ""
293
380
  end
294
381
 
295
- @plan_meta[:warnings]&.each do |warning|
382
+ meta[:warnings]&.each do |warning|
296
383
  log "-" * 20
297
- log Paint["Warning: #{warning[:message]}", :yellow]
384
+ log pastel.yellow("Warning: #{warning[:message]}")
298
385
  warning[:body]&.each do |line|
299
- log Paint[line, :yellow], depth: 1
386
+ log pastel.yellow(line), depth: 1
300
387
  end
301
388
  log ""
302
389
  end
303
390
 
304
- @plan_meta[:errors]&.each do |error|
391
+ meta[:errors]&.each do |error|
305
392
  log "-" * 20
306
- log Paint["Error: #{error[:message]}", :red]
393
+ log pastel.red("Error: #{error[:message]}")
307
394
  error[:body]&.each do |line|
308
- log Paint[line, :red], depth: 1
395
+ log pastel.red(line), depth: 1
309
396
  end
310
397
  log ""
311
398
  end
@@ -315,47 +402,76 @@ module MuxTf
315
402
  log ""
316
403
  end
317
404
 
318
- def detect_remedies_from_plan
405
+ def detect_remedies_from_plan(meta)
319
406
  remedies = Set.new
320
- @plan_meta[:errors]&.each do |error|
407
+ meta[:errors]&.each do |error|
321
408
  remedies << :plan if error[:message].include?("timeout while waiting for plugin to start")
322
409
  end
410
+ remedies << :unlock if lock_error?(meta)
323
411
  remedies
324
412
  end
325
413
 
326
- def run_plan(targets: [], retry_count: 0)
327
- plan_status, @plan_meta = create_plan(plan_filename, targets: targets)
414
+ def lock_error?(meta)
415
+ meta && meta["error"] == "lock"
416
+ end
417
+
418
+ def extract_lock_info(meta)
419
+ {
420
+ lock_id: meta["ID"],
421
+ operation: meta["Operation"],
422
+ who: meta["Who"],
423
+ created: meta["Created"]
424
+ }
425
+ end
426
+
427
+ def run_plan(targets: [], level: 1, retry_count: 0)
428
+ plan_status, = remedy_retry_helper(from: :plan, level: level, attempt: retry_count) {
429
+ @last_lock_info = nil
430
+
431
+ plan_status, meta = create_plan(plan_filename, targets: targets)
432
+
433
+ print_errors_and_warnings(meta)
434
+
435
+ remedies = detect_remedies_from_plan(meta)
436
+
437
+ if remedies.include?(:unlock)
438
+ @last_lock_info = extract_lock_info(meta)
439
+ throw :abort, [plan_status, meta]
440
+ end
441
+
442
+ [remedies, plan_status, meta]
443
+ }
328
444
 
329
445
  case plan_status
330
446
  when :ok
331
447
  log "no changes", depth: 1
332
448
  when :error
333
- # log "something went wrong", depth: 1
334
- print_errors_and_warnings
335
- remedies = detect_remedies_from_plan
336
- status, results = process_remedies(remedies, retry_count: retry_count)
337
- plan_status = results[:plan_status] if status
449
+ log "something went wrong", depth: 1
338
450
  when :changes
339
- log "Printing Plan Summary ...", depth: 1
340
- pretty_plan_summary(plan_filename)
451
+ unless ENV["JSON_PLAN"]
452
+ log "Printing Plan Summary ...", depth: 1
453
+ pretty_plan_summary(plan_filename)
454
+ end
455
+ puts plan_summary_text if ENV["JSON_PLAN"]
341
456
  when :unknown
342
457
  # nothing
343
458
  end
344
459
 
345
- print_errors_and_warnings
346
-
347
460
  plan_status
348
461
  end
349
462
 
463
+ public :run_plan
464
+
350
465
  def run_upgrade
351
466
  exit_code, meta = PlanFormatter.run_tf_init(upgrade: true)
467
+ print_errors_and_warnings(meta)
352
468
  case exit_code
353
469
  when 0
354
470
  [:ok, meta]
355
471
  when 1
356
472
  [:error, meta]
357
473
  else
358
- log Paint["terraform init upgrade exited with an unknown exit code: #{exit_code}", :yellow]
474
+ log pastel.yellow("terraform init upgrade exited with an unknown exit code: #{exit_code}")
359
475
  [:unknown, meta]
360
476
  end
361
477
  end
@@ -6,6 +6,7 @@ module MuxTf
6
6
  extend PiotrbCliUtils::Util
7
7
  extend PiotrbCliUtils::ShellHelpers
8
8
  extend TerraformHelpers
9
+ import Coloring
9
10
 
10
11
  class << self
11
12
  def run(args)
@@ -33,7 +34,7 @@ module MuxTf
33
34
 
34
35
  if options[:interactive]
35
36
  abort_message = catch(:abort) { plan.run_interactive }
36
- log Paint["Aborted: #{abort_message}", :red] if abort_message
37
+ log pastel.red("Aborted: #{abort_message}") if abort_message
37
38
  else
38
39
  if options[:hierarchy]
39
40
  plan.nested_summary.each do |line|
data/lib/mux_tf/cli.rb CHANGED
@@ -7,13 +7,13 @@ module MuxTf
7
7
  def self.run(mode, args)
8
8
  case mode
9
9
  when :mux
10
- require_relative "./cli/mux"
10
+ require_relative "cli/mux"
11
11
  MuxTf::Cli::Mux.run(args)
12
12
  when :current
13
- require_relative "./cli/current"
13
+ require_relative "cli/current"
14
14
  MuxTf::Cli::Current.run(args)
15
15
  when :plan_summary
16
- require_relative "./cli/plan_summary"
16
+ require_relative "cli/plan_summary"
17
17
  MuxTf::Cli::PlanSummary.run(args)
18
18
  else
19
19
  fail_with "unhandled mode: #{mode.inspect}"
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MuxTf
4
+ module Coloring
5
+ def pastel
6
+ self.class.pastel
7
+ end
8
+
9
+ def self.included(other)
10
+ other.extend(ClassMethods)
11
+ end
12
+
13
+ module ClassMethods
14
+ def pastel
15
+ instance = Pastel.new
16
+ instance.alias_color(:orange, :yellow)
17
+ instance.alias_color(:gray, :bright_black)
18
+ instance.alias_color(:grey, :bright_black)
19
+ instance
20
+ end
21
+ end
22
+ end
23
+ end