inspec-core 4.20.2 → 4.20.6

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: 2395ce22d38edca9eaac2fad00c1fc61f3fb95a154618540d23bc2a1e6ce0fcd
4
- data.tar.gz: 4ebdbe5526025408e729b52e0614b43fe89f70b0faae5eeecc8c23db8f0f1ff9
3
+ metadata.gz: bad597d54eeb47c2f634b9c2bba2fcec8afa0d507e0b321244caee264c3b59cf
4
+ data.tar.gz: 966803761b3601c83b1d2474b3405b863b245396f8e4962fc950484ed87ee9ea
5
5
  SHA512:
6
- metadata.gz: f2b21bfbc96b4830edf20f1d48493257845bfbeb52137141269371066c47359092d3ed280cc64e9358b3587d0ddb0c54a643cafd730d57ad2d7ba2331d35b33a
7
- data.tar.gz: 84bc11b59621836d20c045efcdee955cc97c605e5902fafaa79c8756dd44f66334731256c6ba4273484d645484f374b1ec2daf471a6dc56805ea819ab2685f38
6
+ metadata.gz: 2ea62a2de16846b6d3bd1075868e070e41a14d9a8dce9a711155e7d75519eb56fa23238fa4cc3b53a97480396c4bd7a1b20a98251918268a66278c970ab0cda1
7
+ data.tar.gz: a420f3368a7ae4b6f264f15901848e7615bd6e7fefac559dda3c955d83b7059dd59464e685cef5e4310da2d503e61f72c254739c4a054e7b6f76c7bd5f61ef37
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ gem "inspec", path: "."
9
9
  # in it in order to package the executable. Hence the odd backwards dependency.
10
10
  gem "inspec-bin", path: "./inspec-bin"
11
11
 
12
- gem "ffi", [">= 1.9.14", "< 1.13"] # 1.13 does not work on Windows: https://github.com/ffi/ffi/issues/784
12
+ gem "ffi", ">= 1.9.14", "!= 1.13.0"
13
13
 
14
14
  group :omnibus do
15
15
  gem "rb-readline"
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
  spec.add_dependency "faraday", ">= 0.9.0"
40
40
  spec.add_dependency "tty-table", "~> 0.10"
41
41
  spec.add_dependency "tty-prompt", "~> 0.17"
42
- spec.add_dependency "tomlrb", "~> 1.2"
42
+ spec.add_dependency "tomlrb", "~> 1.2.0"
43
43
  spec.add_dependency "addressable", "~> 2.4"
44
44
  spec.add_dependency "parslet", "~> 1.5"
45
45
  spec.add_dependency "semverse", "~> 3.0"
@@ -341,10 +341,8 @@ module Inspec
341
341
  # Tracked on https://github.com/inspec/inspec/issues/3667
342
342
  inspec_reporters_that_are_not_yet_plugins = %w{
343
343
  automate
344
- cli
345
344
  json
346
345
  json-automate
347
- json-min
348
346
  junit
349
347
  yaml
350
348
  }
@@ -356,7 +354,12 @@ module Inspec
356
354
  .find_activators(plugin_type: :reporter)\
357
355
  .map(&:activator_name).map(&:to_s)
358
356
 
359
- valid_types = rspec_built_in_formatters + inspec_reporters_that_are_not_yet_plugins + plugin_reporters
357
+ # Include CLI explicitly, because it is the default reporter and will usually not be
358
+ # present on the command line, and thus its plugin will not appear on the list.
359
+ valid_types = rspec_built_in_formatters + \
360
+ inspec_reporters_that_are_not_yet_plugins + \
361
+ plugin_reporters + \
362
+ [ "cli" ]
360
363
 
361
364
  reporters.each do |reporter_name, reporter_config|
362
365
  raise NotImplementedError, "'#{reporter_name}' is not a valid reporter type." unless valid_types.include?(reporter_name)
@@ -1,8 +1,6 @@
1
1
  require "inspec/reporters/base"
2
- require "inspec/reporters/cli"
3
2
  require "inspec/reporters/json"
4
3
  require "inspec/reporters/json_automate"
5
- require "inspec/reporters/json_min"
6
4
  require "inspec/reporters/junit"
7
5
  require "inspec/reporters/automate"
8
6
  require "inspec/reporters/yaml"
@@ -13,16 +11,12 @@ module Inspec::Reporters
13
11
  name, config = reporter.dup
14
12
  config[:run_data] = run_data
15
13
  case name
16
- when "cli"
17
- reporter = Inspec::Reporters::CLI.new(config)
18
14
  when "json"
19
15
  reporter = Inspec::Reporters::Json.new(config)
20
16
  # This reporter is only used for Chef internal. We reserve the
21
17
  # right to introduce breaking changes to this reporter at any time.
22
18
  when "json-automate"
23
19
  reporter = Inspec::Reporters::JsonAutomate.new(config)
24
- when "json-min"
25
- reporter = Inspec::Reporters::JsonMin.new(config)
26
20
  when "junit"
27
21
  reporter = Inspec::Reporters::Junit.new(config)
28
22
  when "automate"
@@ -60,15 +54,23 @@ module Inspec::Reporters
60
54
  case name
61
55
  when "json"
62
56
  reporter = Inspec::Reporters::Json.new(config)
63
- when "json-min"
64
- reporter = Inspec::Reporters::JsonMin.new(config)
65
57
  when "json-automate"
66
58
  reporter = Inspec::Reporters::JsonAutomate.new(config)
67
59
  when "yaml"
68
60
  reporter = Inspec::Reporters::Yaml.new(config)
69
61
  else
70
- # use base run_data hash for any other report
71
- return run_data
62
+ # If we made it here, it might be a plugin
63
+ begin
64
+ activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
65
+ activator.activate!
66
+ reporter = activator.implementation_class.new(config)
67
+ unless reporter.respond_to(:report?)
68
+ return run_data
69
+ end
70
+ rescue Inspec::Plugin::V2::LoadError
71
+ # Must not have been a plugin - just return the run_data
72
+ return run_data
73
+ end
72
74
  end
73
75
 
74
76
  reporter.report
@@ -1,12 +1,19 @@
1
1
 
2
2
  module Inspec
3
3
  module HashLikeStruct
4
+ # Only list keys whose value are non-nil
4
5
  def keys
5
- members
6
+ members.reject { |k| self[k].nil? }
6
7
  end
7
8
 
9
+ # Only list non-nil members for backwards compatibility
8
10
  def key?(item)
9
- members.include?(item)
11
+ members.include?(item) && non_nil?(item)
12
+ end
13
+
14
+ # This is provided for clarity - many locations make this test
15
+ def non_nil?(item)
16
+ !self[item].nil?
10
17
  end
11
18
  end
12
19
 
@@ -1,3 +1,3 @@
1
1
  module Inspec
2
- VERSION = "4.20.2".freeze
2
+ VERSION = "4.20.6".freeze
3
3
  end
@@ -0,0 +1,12 @@
1
+ # cli reporter
2
+
3
+ This is the implementation of the "cli" reporter. It is the default reporter used if you do not specify a reporter.
4
+
5
+ ## To Install This Plugin
6
+
7
+ This plugin is included with inspec. There is no need to install it separately.
8
+
9
+ ## What This Plugin Does
10
+
11
+ This reporter generates a summary of output at the end of the run to STDOUT by default. By default it uses color and terminal graphics if possible, depending on the capabilities of the host platform.
12
+
@@ -0,0 +1,13 @@
1
+ require_relative "inspec-reporter-cli/version"
2
+
3
+ module InspecPlugins
4
+ module CliReporter
5
+ class Plugin < ::Inspec.plugin(2)
6
+ plugin_name :'inspec-reporter-cli'
7
+ reporter :cli do
8
+ require_relative "inspec-reporter-cli/reporter"
9
+ InspecPlugins::CliReporter::Reporter
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,8 @@
1
- module Inspec::Reporters
2
- class CLI < Base
1
+ require "forwardable"
2
+
3
+ module InspecPlugins::CliReporter
4
+ class Reporter < Inspec.plugin(2, :reporter)
5
+
3
6
  case RUBY_PLATFORM
4
7
  when /windows|mswin|msys|mingw|cygwin/
5
8
  # Most currently available Windows terminals have poor support
@@ -40,11 +43,15 @@ module Inspec::Reporters
40
43
 
41
44
  MULTI_TEST_CONTROL_SUMMARY_MAX_LEN = 60
42
45
 
46
+ def self.run_data_schema_constraints
47
+ "~> 0.0"
48
+ end
49
+
43
50
  def render
44
- run_data[:profiles].each do |profile|
45
- if profile[:status] == "skipped"
46
- platform = run_data[:platform]
47
- output("Skipping profile: '#{profile[:name]}' on unsupported platform: '#{platform[:name]}/#{platform[:release]}'.")
51
+ run_data.profiles.each do |profile|
52
+ if profile.status == "skipped"
53
+ platform = run_data.platform
54
+ output("Skipping profile: '#{profile.name}' on unsupported platform: '#{platform.name}/#{platform.release}'.")
48
55
  next
49
56
  end
50
57
  @control_count = 0
@@ -70,9 +77,9 @@ module Inspec::Reporters
70
77
  def print_profile_header(profile)
71
78
  header = {
72
79
  "Profile" => format_profile_name(profile),
73
- "Version" => profile[:version] || "(not specified)",
80
+ "Version" => profile.version || "(not specified)",
74
81
  }
75
- header["Target"] = run_data[:platform][:target] unless run_data[:platform][:target].nil?
82
+ header["Target"] = run_data.platform.target unless run_data.platform.target.nil?
76
83
  header["Target ID"] = @config["target_id"] unless @config["target_id"].nil?
77
84
 
78
85
  pad = header.keys.max_by(&:length).length + 1
@@ -84,8 +91,8 @@ module Inspec::Reporters
84
91
 
85
92
  def print_standard_control_results(profile)
86
93
  standard_controls_from_profile(profile).each do |control_from_profile|
87
- control = Control.new(control_from_profile)
88
- next if control.results.nil?
94
+ control = ControlForCliDisplay.new(control_from_profile)
95
+ next if control.results.empty?
89
96
 
90
97
  output(format_control_header(control))
91
98
  control.results.each do |result|
@@ -98,8 +105,8 @@ module Inspec::Reporters
98
105
 
99
106
  def print_anonymous_control_results(profile)
100
107
  anonymous_controls_from_profile(profile).each do |control_from_profile|
101
- control = Control.new(control_from_profile)
102
- next if control.results.nil?
108
+ control = ControlForCliDisplay.new(control_from_profile)
109
+ next if control.results.empty?
103
110
 
104
111
  output(format_control_header(control))
105
112
  control.results.each do |result|
@@ -110,10 +117,10 @@ module Inspec::Reporters
110
117
  end
111
118
 
112
119
  def format_profile_name(profile)
113
- if profile[:title].nil?
114
- (profile[:name] || "unknown").to_s
120
+ if profile.title.nil?
121
+ (profile.name || "unknown").to_s
115
122
  else
116
- "#{profile[:title]} (#{profile[:name] || "unknown"})"
123
+ "#{profile.title} (#{profile.name || "unknown"})"
117
124
  end
118
125
  end
119
126
 
@@ -129,16 +136,16 @@ module Inspec::Reporters
129
136
  def format_result(control, result, type)
130
137
  impact = control.impact_string_for_result(result)
131
138
 
132
- message = if result[:status] == "skipped"
133
- result[:skip_message]
139
+ message = if result.status == "skipped"
140
+ result.skip_message
134
141
  elsif type == :anonymous
135
- result[:expectation_message]
142
+ result.expectation_message
136
143
  else
137
- result[:code_desc]
144
+ result.code_desc
138
145
  end
139
146
 
140
147
  # append any failure details to the message if they exist
141
- message += "\n#{result[:message]}" if result[:message]
148
+ message += "\n#{result.message}" if result.message
142
149
 
143
150
  format_message(
144
151
  color: impact,
@@ -170,9 +177,7 @@ module Inspec::Reporters
170
177
 
171
178
  def all_unique_controls
172
179
  @unique_controls ||= begin
173
- run_data[:profiles].flat_map do |profile|
174
- profile[:controls]
175
- end.uniq
180
+ run_data.profiles.flat_map(&:controls).uniq
176
181
  end
177
182
  end
178
183
 
@@ -182,12 +187,12 @@ module Inspec::Reporters
182
187
  passed = 0
183
188
 
184
189
  all_unique_controls.each do |control|
185
- next if control[:id].start_with? "(generated from "
186
- next unless control[:results]
190
+ next if control.id.start_with? "(generated from "
191
+ next if control.results.empty?
187
192
 
188
- if control[:results].any? { |r| r[:status] == "failed" }
193
+ if control.results.any? { |r| r.status == "failed" }
189
194
  failed += 1
190
- elsif control[:results].any? { |r| r[:status] == "skipped" }
195
+ elsif control.results.any? { |r| r.status == "skipped" }
191
196
  skipped += 1
192
197
  else
193
198
  passed += 1
@@ -211,12 +216,12 @@ module Inspec::Reporters
211
216
  passed = 0
212
217
 
213
218
  all_unique_controls.each do |control|
214
- next unless control[:results]
219
+ next if control.results.empty?
215
220
 
216
- control[:results].each do |result|
217
- if result[:status] == "failed"
221
+ control.results.each do |result|
222
+ if result.status == "failed"
218
223
  failed += 1
219
- elsif result[:status] == "skipped"
224
+ elsif result.status == "skipped"
220
225
  skipped += 1
221
226
  else
222
227
  passed += 1
@@ -273,42 +278,30 @@ module Inspec::Reporters
273
278
  end
274
279
 
275
280
  def standard_controls_from_profile(profile)
276
- profile[:controls].reject { |c| is_anonymous_control?(c) }
281
+ profile.controls.reject { |c| is_anonymous_control?(c) }
277
282
  end
278
283
 
279
284
  def anonymous_controls_from_profile(profile)
280
- profile[:controls].select { |c| is_anonymous_control?(c) && !c[:results].nil? }
285
+ profile.controls.select { |c| is_anonymous_control?(c) && !c[:results].nil? }
281
286
  end
282
287
 
283
288
  def is_anonymous_control?(control)
284
- control[:id].start_with?("(generated from ")
289
+ control.id.start_with?("(generated from ")
285
290
  end
286
291
 
287
292
  def indent_lines(message, indentation)
288
293
  message.lines.map { |line| " " * indentation + line }.join
289
294
  end
290
295
 
291
- class Control
292
- attr_reader :data
296
+ class ControlForCliDisplay
293
297
 
294
- def initialize(control_hash)
295
- @data = control_hash
296
- end
298
+ extend Forwardable
297
299
 
298
- def id
299
- data[:id]
300
- end
301
-
302
- def title
303
- data[:title]
304
- end
305
-
306
- def results
307
- data[:results]
308
- end
300
+ attr_reader :control_obj
301
+ def_delegators :@control_obj, :id, :impact, :results, :title
309
302
 
310
- def impact
311
- data[:impact]
303
+ def initialize(control_obj)
304
+ @control_obj = control_obj
312
305
  end
313
306
 
314
307
  def anonymous?
@@ -317,9 +310,9 @@ module Inspec::Reporters
317
310
 
318
311
  def title_for_report
319
312
  # if this is an anonymous control, just grab the resource title from any result entry
320
- return results.first[:resource_title] if anonymous?
313
+ return results.first.resource_title if anonymous?
321
314
 
322
- title_for_report = "#{id}: #{title || results.first[:resource_title]}"
315
+ title_for_report = "#{id}: #{title || results.first.resource_title}"
323
316
 
324
317
  # we will not add any additional data to the title if there's only
325
318
  # zero or one test for this control.
@@ -337,9 +330,9 @@ module Inspec::Reporters
337
330
  nil
338
331
  elsif impact.nil?
339
332
  "unknown"
340
- elsif results&.find { |r| r[:status] == "skipped" }
333
+ elsif results&.find { |r| r.status == "skipped" }
341
334
  "skipped"
342
- elsif results.nil? || results.empty? || results.all? { |r| r[:status] == "passed" }
335
+ elsif results.empty? || results.all? { |r| r.status == "passed" }
343
336
  "passed"
344
337
  else
345
338
  "failed"
@@ -347,9 +340,9 @@ module Inspec::Reporters
347
340
  end
348
341
 
349
342
  def impact_string_for_result(result)
350
- if result[:status] == "skipped"
343
+ if result.status == "skipped"
351
344
  "skipped"
352
- elsif result[:status] == "passed"
345
+ elsif result.status == "passed"
353
346
  "passed"
354
347
  elsif impact.nil?
355
348
  "unknown"
@@ -359,11 +352,11 @@ module Inspec::Reporters
359
352
  end
360
353
 
361
354
  def failure_count
362
- results.select { |r| r[:status] == "failed" }.size
355
+ results.select { |r| r.status == "failed" }.size
363
356
  end
364
357
 
365
358
  def skipped_count
366
- results.select { |r| r[:status] == "skipped" }.size
359
+ results.select { |r| r.status == "skipped" }.size
367
360
  end
368
361
  end
369
362
  end
@@ -0,0 +1,5 @@
1
+ module InspecPlugins
2
+ module CliReporter
3
+ VERSION = "0.1.0".freeze
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ # JSON Minimal Reporter Plugin
2
+
3
+ ## To Install This Plugin
4
+
5
+ This plugin is included with InSpec. There is no need to install it.
6
+
7
+ ## What This Plugin Does
8
+
9
+ This plugin provides the `json-min` reporter, which produces test output in JSON format with less detail than the `json` reporter.
10
+
@@ -0,0 +1,13 @@
1
+ require_relative "inspec-reporter-json-min/version"
2
+
3
+ module InspecPlugins
4
+ module JsonMinReporter
5
+ class Plugin < ::Inspec.plugin(2)
6
+ plugin_name :"inspec-reporter-json-min"
7
+ reporter :"json-min" do
8
+ require_relative "inspec-reporter-json-min/reporter"
9
+ InspecPlugins::JsonMinReporter::Reporter
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,50 @@
1
+ require "json"
2
+
3
+ module InspecPlugins::JsonMinReporter
4
+ class Reporter < Inspec.plugin(2, :reporter)
5
+ def self.run_data_schema_constraints
6
+ "~> 0.0"
7
+ end
8
+
9
+ def render
10
+ output(report.to_json, false)
11
+ end
12
+
13
+ def report # rubocop:disable Metrics/AbcSize
14
+ report = {
15
+ controls: [],
16
+ statistics: { duration: run_data.statistics.duration },
17
+ version: run_data.version,
18
+ }
19
+
20
+ # collect all test results and add them to the report
21
+ run_data.profiles.each do |profile|
22
+ profile_id = profile.name
23
+
24
+ profile.controls.each do |control|
25
+ control_id = control.id
26
+
27
+ control.results.each do |result|
28
+ result_for_report = {
29
+ id: control_id,
30
+ profile_id: profile_id,
31
+ profile_sha256: profile.sha256,
32
+ status: result.status,
33
+ code_desc: result.code_desc,
34
+ }
35
+
36
+ result_for_report[:skip_message] = result.skip_message if result.non_nil?(:skip_message)
37
+ result_for_report[:resource] = result.resource if result.non_nil?(:resource)
38
+ result_for_report[:message] = result.message if result.non_nil?(:message)
39
+ result_for_report[:exception] = result.exception if result.non_nil?(:exception)
40
+ result_for_report[:backtrace] = result.backtrace if result.non_nil?(:backtrace)
41
+
42
+ report[:controls] << result_for_report
43
+ end
44
+ end
45
+ end
46
+
47
+ report
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,5 @@
1
+ module InspecPlugins
2
+ module JsonMinReporter
3
+ VERSION = "0.1.0".freeze
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inspec-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.20.2
4
+ version: 4.20.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef InSpec Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-09 00:00:00.000000000 Z
11
+ date: 2020-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef-telemetry
@@ -264,14 +264,14 @@ dependencies:
264
264
  requirements:
265
265
  - - "~>"
266
266
  - !ruby/object:Gem::Version
267
- version: '1.2'
267
+ version: 1.2.0
268
268
  type: :runtime
269
269
  prerelease: false
270
270
  version_requirements: !ruby/object:Gem::Requirement
271
271
  requirements:
272
272
  - - "~>"
273
273
  - !ruby/object:Gem::Version
274
- version: '1.2'
274
+ version: 1.2.0
275
275
  - !ruby/object:Gem::Dependency
276
276
  name: addressable
277
277
  requirement: !ruby/object:Gem::Requirement
@@ -480,10 +480,8 @@ files:
480
480
  - lib/inspec/reporters.rb
481
481
  - lib/inspec/reporters/automate.rb
482
482
  - lib/inspec/reporters/base.rb
483
- - lib/inspec/reporters/cli.rb
484
483
  - lib/inspec/reporters/json.rb
485
484
  - lib/inspec/reporters/json_automate.rb
486
- - lib/inspec/reporters/json_min.rb
487
485
  - lib/inspec/reporters/junit.rb
488
486
  - lib/inspec/reporters/yaml.rb
489
487
  - lib/inspec/require_loader.rb
@@ -724,6 +722,14 @@ files:
724
722
  - lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli.rb
725
723
  - lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/cli_command.rb
726
724
  - lib/plugins/inspec-plugin-manager-cli/lib/inspec-plugin-manager-cli/plugin.rb
725
+ - lib/plugins/inspec-reporter-cli/README.md
726
+ - lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli.rb
727
+ - lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/reporter.rb
728
+ - lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/version.rb
729
+ - lib/plugins/inspec-reporter-json-min/README.md
730
+ - lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min.rb
731
+ - lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/reporter.rb
732
+ - lib/plugins/inspec-reporter-json-min/lib/inspec-reporter-json-min/version.rb
727
733
  - lib/plugins/shared/core_plugin_test_helper.rb
728
734
  - lib/plugins/things-for-train-integration.rb
729
735
  - lib/source_readers/flat.rb
@@ -1,48 +0,0 @@
1
- require "json"
2
-
3
- module Inspec::Reporters
4
- class JsonMin < Base
5
- def render
6
- output(report.to_json, false)
7
- end
8
-
9
- def report # rubocop:disable Metrics/AbcSize
10
- report = {
11
- controls: [],
12
- statistics: { duration: run_data[:statistics][:duration] },
13
- version: run_data[:version],
14
- }
15
-
16
- # collect all test results and add them to the report
17
- run_data[:profiles].each do |profile|
18
- profile_id = profile[:name]
19
- next unless profile[:controls]
20
-
21
- profile[:controls].each do |control|
22
- control_id = control[:id]
23
- next unless control[:results]
24
-
25
- control[:results].each do |result|
26
- result_for_report = {
27
- id: control_id,
28
- profile_id: profile_id,
29
- profile_sha256: profile[:sha256],
30
- status: result[:status],
31
- code_desc: result[:code_desc],
32
- }
33
-
34
- result_for_report[:skip_message] = result[:skip_message] if result.key?(:skip_message)
35
- result_for_report[:resource] = result[:resource] if result.key?(:resource)
36
- result_for_report[:message] = result[:message] if result.key?(:message)
37
- result_for_report[:exception] = result[:exception] if result.key?(:exception)
38
- result_for_report[:backtrace] = result[:backtrace] if result.key?(:backtrace)
39
-
40
- report[:controls] << result_for_report
41
- end
42
- end
43
- end
44
-
45
- report
46
- end
47
- end
48
- end