mux_tf 0.8.4 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21e0e5f58ecc6d306e555902ffe4db396a624dcd238cffd4ffa9f601baa44f8a
4
- data.tar.gz: 80cd848539404d195931669894311556df35b7a6949a3aaae61f5ee35c9c065b
3
+ metadata.gz: b79dc73fcdc056b82b415b35dbb624b69e70edf3bc6db7852d8e2ea06f95c1ce
4
+ data.tar.gz: 119261f6a5f86ff78319cf411d1f24ff35f2c13262a427d3dd3ec990bd4fbd09
5
5
  SHA512:
6
- metadata.gz: 9be81dd55dcc793400fddffc83af284893d71f02ce7462f7f7f10203114ba9260619887ecbdf92aeb35175f26334c40fef84e7d91e1bc380d0bf976ed7ecd561
7
- data.tar.gz: b16d3e6f1b3214912354ff6915e13c64542ed224b16e1ec7d40241218ab2effe292dda60bceb6b7ab8d71292e3cf99c057d14096b39628482e65430c704380f1
6
+ metadata.gz: dce2287920bef8ea5eafd6b8565b7c2a7b6799ceb4514739a3aa7d7dc5fe0bcb840275824faf824294309b929a40698dc6203ed2755071238ed9008409865277
7
+ data.tar.gz: 92da3b7540fee9234c8d2b9ecc2cb6b8a4027c8644549777417aff862a3babdb5f66deeb1bd815f7ef43abf256305f26602efe4c93308176a7023d92845125f2
data/exe/tf_current CHANGED
@@ -8,7 +8,7 @@ begin
8
8
  require "mux_tf"
9
9
 
10
10
  MuxTf::Cli.run(:current, ARGV)
11
- rescue Exception => e
11
+ rescue Exception => e # rubocop:disable Lint/RescueException
12
12
  warn e.full_message
13
13
  warn "<press enter>"
14
14
  $stdin.gets
data/exe/tf_mux CHANGED
@@ -8,7 +8,7 @@ begin
8
8
  require "mux_tf"
9
9
 
10
10
  MuxTf::Cli.run(:mux, ARGV)
11
- rescue Exception => e
11
+ rescue Exception => e # rubocop:disable Lint/RescueException
12
12
  warn e.full_message
13
13
  warn "<press enter>"
14
14
  $stdin.gets
data/exe/tf_plan_summary CHANGED
@@ -8,7 +8,7 @@ begin
8
8
  require "mux_tf"
9
9
 
10
10
  MuxTf::Cli.run(:plan_summary, ARGV)
11
- rescue Exception => e
11
+ rescue Exception => e # rubocop:disable Lint/RescueException
12
12
  warn e.full_message
13
13
  warn "<press enter>"
14
14
  $stdin.gets
data/lib/deps.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/inline"
2
4
 
3
5
  gemfile do
@@ -10,8 +10,6 @@ module MuxTf
10
10
  extend PiotrbCliUtils::CriCommandSupport
11
11
  extend PiotrbCliUtils::CmdLoop
12
12
 
13
- PLAN_FILENAME = "foo.tfplan"
14
-
15
13
  class << self
16
14
  def run(args)
17
15
  version_check
@@ -30,11 +28,11 @@ module MuxTf
30
28
  return launch_cmd_loop(:error) unless run_validate
31
29
 
32
30
  if ENV["TF_UPGRADE"]
33
- upgrade_status, upgrade_meta = run_upgrade
31
+ upgrade_status, _upgrade_meta = run_upgrade
34
32
  return launch_cmd_loop(:error) unless upgrade_status == :ok
35
33
  end
36
34
 
37
- plan_status, @plan_meta = create_plan(PLAN_FILENAME)
35
+ plan_status, @plan_meta = create_plan(plan_filename)
38
36
 
39
37
  case plan_status
40
38
  when :ok
@@ -44,7 +42,7 @@ module MuxTf
44
42
  launch_cmd_loop(plan_status)
45
43
  when :changes
46
44
  log "Printing Plan Summary ...", depth: 1
47
- pretty_plan_summary(PLAN_FILENAME)
45
+ pretty_plan_summary(plan_filename)
48
46
  launch_cmd_loop(plan_status)
49
47
  when :unknown
50
48
  launch_cmd_loop(plan_status)
@@ -59,17 +57,21 @@ module MuxTf
59
57
  exit 1
60
58
  end
61
59
 
60
+ def plan_filename
61
+ PlanFilenameGenerator.for_path
62
+ end
63
+
62
64
  private
63
65
 
64
66
  def version_check
65
- if VersionCheck.has_updates?
66
- log Paint["=" * 80, :yellow]
67
- log "New version of #{Paint["mux_tf", :cyan]} is available!"
68
- log "You are currently on version: #{Paint[VersionCheck.current_gem_version, :yellow]}"
69
- log "Latest version found is: #{Paint[VersionCheck.latest_gem_version, :green]}"
70
- log "Run `#{Paint["gem install mux_tf", :green]}` to update!"
71
- log Paint["=" * 80, :yellow]
72
- end
67
+ return unless VersionCheck.has_updates?
68
+
69
+ log Paint["=" * 80, :yellow]
70
+ log "New version of #{Paint['mux_tf', :cyan]} is available!"
71
+ log "You are currently on version: #{Paint[VersionCheck.current_gem_version, :yellow]}"
72
+ log "Latest version found is: #{Paint[VersionCheck.latest_gem_version, :green]}"
73
+ log "Run `#{Paint['gem install mux_tf', :green]}` to update!"
74
+ log Paint["=" * 80, :yellow]
73
75
  end
74
76
 
75
77
  def run_validate
@@ -176,7 +178,7 @@ module MuxTf
176
178
 
177
179
  def apply_cmd
178
180
  define_cmd("apply", summary: "Apply the current plan") do |_opts, _args, _cmd|
179
- status = tf_apply(filename: PLAN_FILENAME)
181
+ status = tf_apply(filename: plan_filename)
180
182
  if status.success?
181
183
  plan_status = run_plan
182
184
  throw :stop, :done if plan_status == :ok
@@ -190,7 +192,7 @@ module MuxTf
190
192
  define_cmd("shell", summary: "Open your default terminal in the current folder") do |_opts, _args, _cmd|
191
193
  log Paint["Launching shell ...", :yellow]
192
194
  log Paint["When it exits you will be back at this prompt.", :yellow]
193
- system ENV["SHELL"]
195
+ system ENV.fetch("SHELL")
194
196
  end
195
197
  end
196
198
 
@@ -208,11 +210,11 @@ module MuxTf
208
210
 
209
211
  if @plan_meta && @plan_meta["error"] == "lock"
210
212
  done = catch(:abort) {
211
- if @plan_meta["Operation"] != "OperationTypePlan"
212
- throw :abort unless prompt.yes?(
213
- "Are you sure you want to force unlock a lock for operation: #{@plan_meta["Operation"]}",
214
- default: false
215
- )
213
+ if @plan_meta["Operation"] != "OperationTypePlan" && !prompt.yes?(
214
+ "Are you sure you want to force unlock a lock for operation: #{@plan_meta['Operation']}",
215
+ default: false
216
+ )
217
+ throw :abort
216
218
  end
217
219
 
218
220
  throw :abort unless prompt.yes?(
@@ -259,17 +261,15 @@ module MuxTf
259
261
 
260
262
  def interactive_cmd
261
263
  define_cmd("interactive", summary: "Apply interactively") do |_opts, _args, _cmd|
262
- plan = PlanSummaryHandler.from_file(PLAN_FILENAME)
264
+ plan = PlanSummaryHandler.from_file(plan_filename)
263
265
  begin
264
- abort_message = catch :abort do
265
- plan.run_interactive
266
- end
266
+ abort_message = catch(:abort) { plan.run_interactive }
267
267
  if abort_message
268
268
  log Paint["Aborted: #{abort_message}", :red]
269
269
  else
270
270
  run_plan
271
271
  end
272
- rescue Exception => e
272
+ rescue Exception => e # rubocop:disable Lint/RescueException
273
273
  log e.full_message
274
274
  log "Interactive Apply Failed!"
275
275
  end
@@ -277,7 +277,7 @@ module MuxTf
277
277
  end
278
278
 
279
279
  def run_plan(targets: [])
280
- plan_status, @plan_meta = create_plan(PLAN_FILENAME, targets: targets)
280
+ plan_status, @plan_meta = create_plan(plan_filename, targets: targets)
281
281
 
282
282
  case plan_status
283
283
  when :ok
@@ -286,7 +286,7 @@ module MuxTf
286
286
  log "something went wrong", depth: 1
287
287
  when :changes
288
288
  log "Printing Plan Summary ...", depth: 1
289
- pretty_plan_summary(PLAN_FILENAME)
289
+ pretty_plan_summary(plan_filename)
290
290
  when :unknown
291
291
  # nothing
292
292
  end
@@ -13,7 +13,7 @@ module MuxTf
13
13
  backup = {}
14
14
  Bundler.with_original_env do
15
15
  ENV.keys.grep(/^(RBENV_|RUBYLIB)/).each do |key|
16
- backup[key] = ENV[key]
16
+ backup[key] = ENV.fetch(key)
17
17
  ENV.delete(key)
18
18
  end
19
19
  yield
@@ -104,7 +104,7 @@ module MuxTf
104
104
  ignored += ENV["MUX_IGNORE"].split(",") if ENV["MUX_IGNORE"]
105
105
 
106
106
  dirs = Dir["**/.terraform.lock.hcl"].map { |f| File.dirname(f) }
107
- dirs.reject! { |d| d.in?(ignored) }
107
+ dirs.reject! do |d| d.in?(ignored) end
108
108
 
109
109
  dirs
110
110
  end
@@ -23,23 +23,17 @@ module MuxTf
23
23
  end
24
24
  }.parse!(args)
25
25
 
26
- if options[:interactive]
27
- raise "must specify plan file in interactive mode" if args[0].blank?
28
- end
26
+ raise "must specify plan file in interactive mode" if options[:interactive] && args[0].blank?
29
27
 
30
28
  plan = if args[0]
31
- PlanSummaryHandler.from_file(args[0])
32
- else
33
- PlanSummaryHandler.from_data(JSON.parse(STDIN.read))
34
- end
29
+ PlanSummaryHandler.from_file(args[0])
30
+ else
31
+ PlanSummaryHandler.from_data(JSON.parse($stdin.read))
32
+ end
35
33
 
36
34
  if options[:interactive]
37
- abort_message = catch :abort do
38
- plan.run_interactive
39
- end
40
- if abort_message
41
- log Paint["Aborted: #{abort_message}", :red]
42
- end
35
+ abort_message = catch(:abort) { plan.run_interactive }
36
+ log Paint["Aborted: #{abort_message}", :red] if abort_message
43
37
  else
44
38
  if options[:hierarchy]
45
39
  plan.nested_summary.each do |line|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MuxTf
2
4
  class OnceHelper
3
5
  # once = OnceHelper.new
@@ -5,25 +7,21 @@ module MuxTf
5
7
 
6
8
  class StateEvaluator
7
9
  def initialize(once_helper, new_state)
8
- if once_helper.state != new_state
10
+ if once_helper.state == new_state
11
+ @path = :otherwise
12
+ else
9
13
  once_helper.state = new_state
10
14
  @path = :once
11
- else
12
- @path = :otherwise
13
15
  end
14
16
  end
15
17
 
16
- def once(&block)
17
- if @path == :then
18
- yield
19
- end
18
+ def once
19
+ yield if @path == :then
20
20
  self
21
21
  end
22
22
 
23
- def otherwise(&block)
24
- if @path == :otherwise
25
- yield
26
- end
23
+ def otherwise
24
+ yield if @path == :otherwise
27
25
  self
28
26
  end
29
27
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MuxTf
4
+ class PlanFilenameGenerator
5
+ def self.for_path(path = Dir.getwd)
6
+ folder_name = File.basename(path)
7
+ temp_dir = Dir.tmpdir
8
+ hash = Digest::MD5.hexdigest(path)
9
+ "#{temp_dir}/#{folder_name}-#{hash}.tfplan"
10
+ end
11
+ end
12
+ end
@@ -6,7 +6,7 @@ module MuxTf
6
6
  extend PiotrbCliUtils::Util
7
7
 
8
8
  class << self
9
- def pretty_plan(filename, targets: [])
9
+ def pretty_plan(filename, targets: []) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
10
10
  pastel = Pastel.new
11
11
 
12
12
  once = OnceHelper.new
@@ -15,11 +15,12 @@ module MuxTf
15
15
 
16
16
  parser = StatefulParser.new(normalizer: pastel.method(:strip))
17
17
  parser.state(:info, /^Acquiring state lock/)
18
- parser.state(:error, /(╷|Error locking state|Error:)/, %i[none blank info reading])
19
- parser.state(:reading, /: (Reading...|Read complete after)/, %i[none info reading])
18
+ parser.state(:error, /(╷|Error locking state|Error:)/, [:none, :blank, :info, :reading])
19
+ parser.state(:reading, /: (Reading...|Read complete after)/, [:none, :info, :reading])
20
20
  parser.state(:none, /^$/, [:reading])
21
- parser.state(:refreshing, /^.+: Refreshing state... \[id=/, %i[none info reading])
22
- parser.state(:refreshing, /Refreshing Terraform state in-memory prior to plan.../, %i[none blank info reading])
21
+ parser.state(:refreshing, /^.+: Refreshing state... \[id=/, [:none, :info, :reading])
22
+ parser.state(:refreshing, /Refreshing Terraform state in-memory prior to plan.../,
23
+ [:none, :blank, :info, :reading])
23
24
  parser.state(:refresh_done, /^----------+$/, [:refreshing])
24
25
  parser.state(:refresh_done, /^$/, [:refreshing])
25
26
  parser.state(:plan_info, /Terraform will perform the following actions:/, [:refresh_done, :none])
@@ -31,7 +32,7 @@ module MuxTf
31
32
  parser.state(:error_lock_info, /Lock Info/, [:error])
32
33
  parser.state(:error, /^$/, [:error_lock_info])
33
34
 
34
- parser.state(:plan_error, /^╷|Error: /, %i[refreshing refresh_done])
35
+ parser.state(:plan_error, /^╷|Error: /, [:refreshing, :refresh_done])
35
36
 
36
37
  status = tf_plan(out: filename, detailed_exitcode: true, compact_warnings: true, targets: targets) { |raw_line|
37
38
  parser.parse(raw_line.rstrip) do |state, line|
@@ -65,13 +66,11 @@ module MuxTf
65
66
  meta["error"] = "lock"
66
67
  log Paint[line, :red], depth: 2
67
68
  when :plan_error
68
- once.for(state).once { puts }
69
+ once.for(state).once do puts end
69
70
  meta["error"] = "refresh"
70
71
  log Paint[line, :red], depth: 2
71
72
  when :error_lock_info
72
- if line =~ /([A-Z]+[\S]+)+:\s+(.+)$/
73
- meta[$LAST_MATCH_INFO[1]] = $LAST_MATCH_INFO[2]
74
- end
73
+ meta[$LAST_MATCH_INFO[1]] = $LAST_MATCH_INFO[2] if line =~ /([A-Z]+\S+)+:\s+(.+)$/
75
74
  log Paint[line, :red], depth: 2
76
75
  when :refreshing
77
76
  once.for(state).once {
@@ -80,16 +79,16 @@ module MuxTf
80
79
  print "."
81
80
  }
82
81
  when :plan_legend
83
- once.for(state).once { puts }
82
+ once.for(state).once do puts end
84
83
  log line, depth: 2
85
84
  when :refresh_done
86
85
  once.for(state).once {
87
86
  puts
88
87
  }.otherwise {
89
- #nothing
88
+ # nothing
90
89
  }
91
- when :plan_info
92
- once.for(state).once { puts }
90
+ when :plan_info # rubocop:disable Lint/DuplicateBranch
91
+ once.for(state).once do puts end
93
92
  log line, depth: 2
94
93
  when :plan_summary
95
94
  log line, depth: 2
@@ -114,7 +113,7 @@ module MuxTf
114
113
  remedies
115
114
  end
116
115
 
117
- def run_tf_init(upgrade: nil, reconfigure: nil)
116
+ def run_tf_init(upgrade: nil, reconfigure: nil) # rubocop:disable Metrics/MethodLength
118
117
  pastel = Pastel.new
119
118
 
120
119
  phase = :init
@@ -145,7 +144,7 @@ module MuxTf
145
144
  case stripped_line
146
145
  when /^Downloading (?<repo>[^ ]+) (?<version>[^ ]+) for (?<module>[^ ]+)\.\.\./
147
146
  print "D"
148
- when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./
147
+ when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./ # rubocop:disable Lint/DuplicateBranch
149
148
  print "D"
150
149
  when /^- (?<module>[^ ]+) in (?<path>.+)$/
151
150
  print "."
@@ -166,7 +165,7 @@ module MuxTf
166
165
  print "."
167
166
  when /^Downloading (?<repo>[^ ]+) (?<version>[^ ]+) for (?<module>[^ ]+)\.\.\./
168
167
  print "D"
169
- when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./
168
+ when /^Downloading (?<repo>[^ ]+) for (?<module>[^ ]+)\.\.\./ # rubocop:disable Lint/DuplicateBranch
170
169
  print "D"
171
170
  when ""
172
171
  puts
@@ -183,7 +182,7 @@ module MuxTf
183
182
  case stripped_line
184
183
  when /^Successfully configured/
185
184
  log line, depth: 2
186
- when /unless the backend/
185
+ when /unless the backend/ # rubocop:disable Lint/DuplicateBranch
187
186
  log line, depth: 2
188
187
  when ""
189
188
  puts
@@ -205,28 +204,28 @@ module MuxTf
205
204
  case stripped_line
206
205
  when /^- Reusing previous version of (?<module>.+) from the dependency lock file$/
207
206
  info = $LAST_MATCH_INFO.named_captures
208
- log "- [FROM-LOCK] #{info["module"]}", depth: 2
207
+ log "- [FROM-LOCK] #{info['module']}", depth: 2
209
208
  when /^- (?<module>.+) is built in to Terraform$/
210
209
  info = $LAST_MATCH_INFO.named_captures
211
- log "- [BUILTIN] #{info["module"]}", depth: 2
210
+ log "- [BUILTIN] #{info['module']}", depth: 2
212
211
  when /^- Finding (?<module>[^ ]+) versions matching "(?<version>.+)"\.\.\./
213
212
  info = $LAST_MATCH_INFO.named_captures
214
- log "- [FIND] #{info["module"]} matching #{info["version"].inspect}", depth: 2
213
+ log "- [FIND] #{info['module']} matching #{info['version'].inspect}", depth: 2
215
214
  when /^- Finding latest version of (?<module>.+)\.\.\.$/
216
215
  info = $LAST_MATCH_INFO.named_captures
217
- log "- [FIND] #{info["module"]}", depth: 2
216
+ log "- [FIND] #{info['module']}", depth: 2
218
217
  when /^- Installing (?<module>[^ ]+) v(?<version>.+)\.\.\.$/
219
218
  info = $LAST_MATCH_INFO.named_captures
220
- log "- [INSTALLING] #{info["module"]} v#{info["version"]}", depth: 2
221
- when /^- Installed (?<module>[^ ]+) v(?<version>.+) \(signed by( a)? (?<signed>.+)\)$/
219
+ log "- [INSTALLING] #{info['module']} v#{info['version']}", depth: 2
220
+ when /^- Installed (?<module>[^ ]+) v(?<version>.+) \(signed by(?: a)? (?<signed>.+)\)$/
222
221
  info = $LAST_MATCH_INFO.named_captures
223
- log "- [INSTALLED] #{info["module"]} v#{info["version"]} (#{info["signed"]})", depth: 2
222
+ log "- [INSTALLED] #{info['module']} v#{info['version']} (#{info['signed']})", depth: 2
224
223
  when /^- Using previously-installed (?<module>[^ ]+) v(?<version>.+)$/
225
224
  info = $LAST_MATCH_INFO.named_captures
226
- log "- [USING] #{info["module"]} v#{info["version"]}", depth: 2
225
+ log "- [USING] #{info['module']} v#{info['version']}", depth: 2
227
226
  when /^- Downloading plugin for provider "(?<provider>[^"]+)" \((?<provider_path>[^)]+)\) (?<version>.+)\.\.\.$/
228
227
  info = $LAST_MATCH_INFO.named_captures
229
- log "- #{info["provider"]} #{info["version"]}", depth: 2
228
+ log "- #{info['provider']} #{info['version']}", depth: 2
230
229
  when "- Checking for available provider plugins..."
231
230
  # noop
232
231
  else
@@ -242,6 +241,7 @@ module MuxTf
242
241
  log Paint[line, :yellow], depth: 1
243
242
  when :none
244
243
  next if line == ""
244
+
245
245
  p [state, line]
246
246
  else
247
247
  p [state, line]
@@ -252,23 +252,21 @@ module MuxTf
252
252
  [status.status, meta]
253
253
  end
254
254
 
255
- def process_validation(info)
255
+ def process_validation(info) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
256
256
  remedies = Set.new
257
257
 
258
- if info["error_count"] > 0 || info["warning_count"] > 0
259
- log "Encountered #{Paint[info["error_count"], :red]} Errors and #{Paint[info["warning_count"], :yellow]} Warnings!", depth: 2
258
+ if (info["error_count"]).positive? || (info["warning_count"]).positive?
259
+ log "Encountered #{Paint[info['error_count'], :red]} Errors and #{Paint[info['warning_count'], :yellow]} Warnings!", depth: 2
260
260
  info["diagnostics"].each do |dinfo|
261
261
  color = dinfo["severity"] == "error" ? :red : :yellow
262
- log "#{Paint[dinfo["severity"].capitalize, color]}: #{dinfo["summary"]}", depth: 3
262
+ log "#{Paint[dinfo['severity'].capitalize, color]}: #{dinfo['summary']}", depth: 3
263
263
  if dinfo["detail"]&.include?("terraform init")
264
264
  remedies << :init
265
- elsif /there is no package for .+ cached in/.match?(dinfo["summary"])
265
+ elsif /there is no package for .+ cached in/.match?(dinfo["summary"]) # rubocop:disable Lint/DuplicateBranch
266
266
  remedies << :init
267
267
  else
268
268
  log dinfo["detail"], depth: 4 if dinfo["detail"]
269
- if dinfo["range"]
270
- log format_validation_range(dinfo["range"], color), depth: 4
271
- end
269
+ log format_validation_range(dinfo["range"], color), depth: 4 if dinfo["range"]
272
270
 
273
271
  remedies << :unknown if dinfo["severity"] == "error"
274
272
  end
@@ -280,7 +278,7 @@ module MuxTf
280
278
 
281
279
  private
282
280
 
283
- def format_validation_range(range, color)
281
+ def format_validation_range(range, color) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
284
282
  # filename: "../../../modules/pods/jane_pod/main.tf"
285
283
  # start:
286
284
  # line: 151
@@ -299,12 +297,17 @@ module MuxTf
299
297
  # on ../../../modules/pods/jane_pod/main.tf line 151, in module "jane":
300
298
  # 151: jane_resources_preset = var.jane_resources_presetx
301
299
  output = []
302
- lines_info = lines.size == 1 ? "#{lines.first}:#{columns.first}" : "#{lines.first}:#{columns.first} to #{lines.last}:#{columns.last}"
303
- output << "on: #{range["filename"]} line#{lines.size > 1 ? "s" : ""}: #{lines_info}"
300
+ lines_info = if lines.size == 1
301
+ "#{lines.first}:#{columns.first}"
302
+ else
303
+ "#{lines.first}:#{columns.first} to #{lines.last}:#{columns.last}"
304
+ end
305
+ output << "on: #{range['filename']} line#{lines.size > 1 ? 's' : ''}: #{lines_info}"
304
306
 
305
307
  if File.exist?(range["filename"])
306
308
  file_lines = File.read(range["filename"]).split("\n")
307
- extract_range = ([lines.first - context_lines, 0].max)..([lines.last + context_lines, file_lines.length - 1].min)
309
+ extract_range = (([lines.first - context_lines,
310
+ 0].max)..([lines.last + context_lines, file_lines.length - 1].min))
308
311
  file_lines.each_with_index do |line, index|
309
312
  if extract_range.cover?(index + 1)
310
313
  if lines.cover?(index + 1)
@@ -316,7 +319,7 @@ module MuxTf
316
319
  start_col = columns.last
317
320
  end
318
321
  painted_line = paint_line(line, color, start_col: start_col, end_col: end_col)
319
- output << "#{Paint[">", color]} #{index + 1}: #{painted_line}"
322
+ output << "#{Paint['>', color]} #{index + 1}: #{painted_line}"
320
323
  else
321
324
  output << " #{index + 1}: #{line}"
322
325
  end
@@ -330,7 +333,7 @@ module MuxTf
330
333
  def paint_line(line, *paint_options, start_col: 1, end_col: :max)
331
334
  end_col = line.length if end_col == :max
332
335
  prefix = line[0, start_col - 1]
333
- suffix = line[end_col..-1]
336
+ suffix = line[end_col..]
334
337
  middle = line[start_col - 1..end_col - 1]
335
338
  "#{prefix}#{Paint[middle, *paint_options]}#{suffix}"
336
339
  end