pdk-akerl 1.8.0.1
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 +7 -0
- data/CHANGELOG.md +826 -0
- data/LICENSE +201 -0
- data/README.md +133 -0
- data/exe/pdk +10 -0
- data/lib/pdk.rb +10 -0
- data/lib/pdk/answer_file.rb +121 -0
- data/lib/pdk/cli.rb +113 -0
- data/lib/pdk/cli/build.rb +76 -0
- data/lib/pdk/cli/bundle.rb +42 -0
- data/lib/pdk/cli/convert.rb +41 -0
- data/lib/pdk/cli/errors.rb +23 -0
- data/lib/pdk/cli/exec.rb +246 -0
- data/lib/pdk/cli/exec_group.rb +67 -0
- data/lib/pdk/cli/module.rb +14 -0
- data/lib/pdk/cli/module/build.rb +14 -0
- data/lib/pdk/cli/module/generate.rb +45 -0
- data/lib/pdk/cli/new.rb +17 -0
- data/lib/pdk/cli/new/class.rb +32 -0
- data/lib/pdk/cli/new/defined_type.rb +30 -0
- data/lib/pdk/cli/new/module.rb +41 -0
- data/lib/pdk/cli/new/provider.rb +27 -0
- data/lib/pdk/cli/new/task.rb +31 -0
- data/lib/pdk/cli/test.rb +12 -0
- data/lib/pdk/cli/test/unit.rb +88 -0
- data/lib/pdk/cli/update.rb +32 -0
- data/lib/pdk/cli/util.rb +193 -0
- data/lib/pdk/cli/util/command_redirector.rb +26 -0
- data/lib/pdk/cli/util/interview.rb +63 -0
- data/lib/pdk/cli/util/option_normalizer.rb +53 -0
- data/lib/pdk/cli/util/option_validator.rb +56 -0
- data/lib/pdk/cli/validate.rb +124 -0
- data/lib/pdk/generate.rb +11 -0
- data/lib/pdk/generate/defined_type.rb +49 -0
- data/lib/pdk/generate/module.rb +318 -0
- data/lib/pdk/generate/provider.rb +82 -0
- data/lib/pdk/generate/puppet_class.rb +48 -0
- data/lib/pdk/generate/puppet_object.rb +288 -0
- data/lib/pdk/generate/task.rb +86 -0
- data/lib/pdk/i18n.rb +4 -0
- data/lib/pdk/logger.rb +28 -0
- data/lib/pdk/module.rb +21 -0
- data/lib/pdk/module/build.rb +214 -0
- data/lib/pdk/module/convert.rb +209 -0
- data/lib/pdk/module/metadata.rb +193 -0
- data/lib/pdk/module/templatedir.rb +313 -0
- data/lib/pdk/module/update.rb +111 -0
- data/lib/pdk/module/update_manager.rb +210 -0
- data/lib/pdk/report.rb +112 -0
- data/lib/pdk/report/event.rb +357 -0
- data/lib/pdk/template_file.rb +89 -0
- data/lib/pdk/tests/unit.rb +213 -0
- data/lib/pdk/util.rb +271 -0
- data/lib/pdk/util/bundler.rb +253 -0
- data/lib/pdk/util/filesystem.rb +12 -0
- data/lib/pdk/util/git.rb +74 -0
- data/lib/pdk/util/puppet_version.rb +242 -0
- data/lib/pdk/util/ruby_version.rb +147 -0
- data/lib/pdk/util/vendored_file.rb +88 -0
- data/lib/pdk/util/version.rb +42 -0
- data/lib/pdk/util/windows.rb +13 -0
- data/lib/pdk/util/windows/api_types.rb +57 -0
- data/lib/pdk/util/windows/file.rb +36 -0
- data/lib/pdk/util/windows/string.rb +16 -0
- data/lib/pdk/validate.rb +14 -0
- data/lib/pdk/validate/base_validator.rb +209 -0
- data/lib/pdk/validate/metadata/metadata_json_lint.rb +86 -0
- data/lib/pdk/validate/metadata/metadata_syntax.rb +109 -0
- data/lib/pdk/validate/metadata_validator.rb +30 -0
- data/lib/pdk/validate/puppet/puppet_lint.rb +67 -0
- data/lib/pdk/validate/puppet/puppet_syntax.rb +112 -0
- data/lib/pdk/validate/puppet_validator.rb +30 -0
- data/lib/pdk/validate/ruby/rubocop.rb +77 -0
- data/lib/pdk/validate/ruby_validator.rb +29 -0
- data/lib/pdk/validate/tasks/metadata_lint.rb +126 -0
- data/lib/pdk/validate/tasks/name.rb +88 -0
- data/lib/pdk/validate/tasks_validator.rb +33 -0
- data/lib/pdk/version.rb +4 -0
- data/locales/config.yaml +21 -0
- data/locales/pdk.pot +1283 -0
- metadata +304 -0
data/lib/pdk/report.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'time'
|
3
|
+
require 'pdk/report/event'
|
4
|
+
require 'socket'
|
5
|
+
|
6
|
+
module PDK
|
7
|
+
class Report
|
8
|
+
# @return [Array<String>] the list of supported report formats.
|
9
|
+
def self.formats
|
10
|
+
@report_formats ||= %w[junit text].freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Symbol] the method name of the default report format.
|
14
|
+
def self.default_format
|
15
|
+
:write_text
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [#write] the default target to write the report to.
|
19
|
+
def self.default_target
|
20
|
+
$stdout
|
21
|
+
end
|
22
|
+
|
23
|
+
# Memoised access to the report event storage hash.
|
24
|
+
#
|
25
|
+
# The keys of the Hash are the source names of the Events (see
|
26
|
+
# PDK::Report::Event#source).
|
27
|
+
#
|
28
|
+
# @example accessing events from the puppet-lint validator
|
29
|
+
# report = PDK::Report.new
|
30
|
+
# report.events['puppet-lint']
|
31
|
+
#
|
32
|
+
# @return [Hash{String=>Array<PDK::Report::Event>}] the events stored in
|
33
|
+
# the repuort.
|
34
|
+
def events
|
35
|
+
@events ||= {}
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create a new PDK::Report::Event from a hash of values and add it to the
|
39
|
+
# report.
|
40
|
+
#
|
41
|
+
# @param data [Hash] (see PDK::Report::Event#initialize)
|
42
|
+
def add_event(data)
|
43
|
+
(events[data[:source]] ||= []) << PDK::Report::Event.new(data)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Renders the report as a JUnit XML document.
|
47
|
+
#
|
48
|
+
# @param target [#write] an IO object that the report will be written to.
|
49
|
+
# Defaults to PDK::Report.default_target.
|
50
|
+
def write_junit(target = self.class.default_target)
|
51
|
+
# Open a File Object for IO if target is a string containing a filename or path
|
52
|
+
target = File.open(target, 'w') if target.is_a? String
|
53
|
+
|
54
|
+
document = REXML::Document.new
|
55
|
+
document << REXML::XMLDecl.new
|
56
|
+
testsuites = REXML::Element.new('testsuites')
|
57
|
+
|
58
|
+
id = 0
|
59
|
+
events.each do |testsuite_name, testcases|
|
60
|
+
testsuite = REXML::Element.new('testsuite')
|
61
|
+
testsuite.attributes['name'] = testsuite_name
|
62
|
+
testsuite.attributes['tests'] = testcases.length
|
63
|
+
testsuite.attributes['errors'] = testcases.select(&:error?).length
|
64
|
+
testsuite.attributes['failures'] = testcases.select(&:failure?).length
|
65
|
+
testsuite.attributes['skipped'] = testcases.select(&:skipped?).length
|
66
|
+
testsuite.attributes['time'] = 0
|
67
|
+
testsuite.attributes['timestamp'] = Time.now.strftime('%Y-%m-%dT%H:%M:%S')
|
68
|
+
testsuite.attributes['hostname'] = Socket.gethostname
|
69
|
+
testsuite.attributes['id'] = id
|
70
|
+
testsuite.attributes['package'] = testsuite_name
|
71
|
+
testsuite.add_element('properties')
|
72
|
+
testcases.each { |r| testsuite.elements << r.to_junit }
|
73
|
+
testsuite.add_element('system-out')
|
74
|
+
testsuite.add_element('system-err')
|
75
|
+
|
76
|
+
testsuites.elements << testsuite
|
77
|
+
id += 1
|
78
|
+
end
|
79
|
+
|
80
|
+
document.elements << testsuites
|
81
|
+
document.write(target, 2)
|
82
|
+
ensure
|
83
|
+
target.close if target.is_a? File
|
84
|
+
end
|
85
|
+
|
86
|
+
# Renders the report as plain text.
|
87
|
+
#
|
88
|
+
# This report is designed for interactive use by a human and so excludes
|
89
|
+
# all passing events in order to be consise.
|
90
|
+
#
|
91
|
+
# @param target [#write] an IO object that the report will be written to.
|
92
|
+
# Defaults to PDK::Report.default_target.
|
93
|
+
def write_text(target = self.class.default_target)
|
94
|
+
# Open a File Object for IO if target is a string containing a filename or path
|
95
|
+
target = File.open(target, 'w') if target.is_a? String
|
96
|
+
coverage_report = nil
|
97
|
+
|
98
|
+
events.each do |_tool, tool_events|
|
99
|
+
tool_events.each do |event|
|
100
|
+
if event.rspec_puppet_coverage?
|
101
|
+
coverage_report = event.to_text
|
102
|
+
else
|
103
|
+
target.puts(event.to_text) unless event.pass?
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
ensure
|
108
|
+
target.puts "\n#{coverage_report}" if coverage_report
|
109
|
+
target.close if target.is_a? File
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,357 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module PDK
|
5
|
+
class Report
|
6
|
+
class Event
|
7
|
+
# @return [String] The path to the file that the event is in reference
|
8
|
+
# to.
|
9
|
+
attr_reader :file
|
10
|
+
|
11
|
+
# @return [Integer] The line number in the file that the event is in
|
12
|
+
# reference to.
|
13
|
+
attr_reader :line
|
14
|
+
|
15
|
+
# @return [Integer] The column number in the line of the file that the
|
16
|
+
# event is in reference to.
|
17
|
+
attr_reader :column
|
18
|
+
|
19
|
+
# @return [String] The name of the source of the event (usually the name
|
20
|
+
# of the validation or testing tool that generated the event).
|
21
|
+
attr_reader :source
|
22
|
+
|
23
|
+
# @return [String] A freeform String containing a human readable message
|
24
|
+
# describing the event.
|
25
|
+
attr_reader :message
|
26
|
+
|
27
|
+
# @return [String] The severity of the event as reported by the
|
28
|
+
# underlying tool.
|
29
|
+
attr_reader :severity
|
30
|
+
|
31
|
+
# @return [String] The name of the test that generated the event.
|
32
|
+
attr_reader :test
|
33
|
+
|
34
|
+
# @return [Symbol] The state of the event. :passed, :failure, :error, or
|
35
|
+
# :skipped.
|
36
|
+
attr_reader :state
|
37
|
+
|
38
|
+
# @return [Array] Array of full stack trace lines associated with event
|
39
|
+
attr_reader :trace
|
40
|
+
|
41
|
+
# Initailises a new PDK::Report::Event object.
|
42
|
+
#
|
43
|
+
# @param data [Hash{Symbol=>Object}
|
44
|
+
# @option data [String] :file (see #file)
|
45
|
+
# @option data [Integer] :line (see #line)
|
46
|
+
# @option data [Integer] :column (see #column)
|
47
|
+
# @option data [String] :source (see #source)
|
48
|
+
# @option data [String] :message (see #message)
|
49
|
+
# @option data [String] :severity (see #severity)
|
50
|
+
# @option data [String] :test (see #test)
|
51
|
+
# @option data [Symbol] :state (see #state)
|
52
|
+
# @option data [Array] :trace (see #trace)
|
53
|
+
#
|
54
|
+
# @raise [ArgumentError] (see #sanitise_data)
|
55
|
+
def initialize(data)
|
56
|
+
sanitise_data(data).each do |key, value|
|
57
|
+
instance_variable_set("@#{key}", value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Checks if the event is the result of a passing test.
|
62
|
+
#
|
63
|
+
# @return [Boolean] true if the test passed, otherwise false.
|
64
|
+
def pass?
|
65
|
+
state == :passed
|
66
|
+
end
|
67
|
+
|
68
|
+
# Checks if the event is the result of a test that could not complete due
|
69
|
+
# to an error.
|
70
|
+
#
|
71
|
+
# @return [Boolean] true if the test did not complete, otherwise false.
|
72
|
+
def error?
|
73
|
+
state == :error
|
74
|
+
end
|
75
|
+
|
76
|
+
# Checks if the event is the result of a failing test.
|
77
|
+
#
|
78
|
+
# @return [Boolean] true if the test failed, otherwise false.
|
79
|
+
def failure?
|
80
|
+
state == :failure
|
81
|
+
end
|
82
|
+
|
83
|
+
# Checks if the event is the result of test that was not run.
|
84
|
+
# This includes pending tests (that are run but have an expected failure result).
|
85
|
+
#
|
86
|
+
# @return [Boolean] true if the test was skipped, otherwise false.
|
87
|
+
def skipped?
|
88
|
+
state == :skipped
|
89
|
+
end
|
90
|
+
|
91
|
+
# Checks if the event stores the result of an rspec-puppet coverage
|
92
|
+
# check.
|
93
|
+
#
|
94
|
+
# Due to the implementation details of this check, the `file` value for
|
95
|
+
# this event will always point to the coverage.rb file in rspec-puppet,
|
96
|
+
# making it easy to filter out.
|
97
|
+
#
|
98
|
+
# @return [Boolean] true if the event contains rspec-puppet coverage
|
99
|
+
# results.
|
100
|
+
def rspec_puppet_coverage?
|
101
|
+
@rspec_puppet_coverage_pattern ||= File.join('**', 'lib', 'rspec-puppet', 'coverage.rb')
|
102
|
+
source == 'rspec' && File.fnmatch?(@rspec_puppet_coverage_pattern, File.expand_path(file))
|
103
|
+
end
|
104
|
+
|
105
|
+
# Renders the event in a clang style text format.
|
106
|
+
#
|
107
|
+
# @return [String] The rendered event.
|
108
|
+
def to_text
|
109
|
+
return message if rspec_puppet_coverage?
|
110
|
+
|
111
|
+
location = [file, line, column].compact.join(':')
|
112
|
+
location = nil if location.empty?
|
113
|
+
|
114
|
+
# TODO: maybe add trace
|
115
|
+
header = [severity, source, location, message].compact.join(': ')
|
116
|
+
if source == 'rspec'
|
117
|
+
result = [header, " #{test}"]
|
118
|
+
context = context_lines
|
119
|
+
unless context.nil?
|
120
|
+
result << ' Failure/Error:'
|
121
|
+
result.concat(context)
|
122
|
+
result << "\n"
|
123
|
+
end
|
124
|
+
|
125
|
+
result.compact.join("\n")
|
126
|
+
else
|
127
|
+
header
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Renders the event as a JUnit XML testcase.
|
132
|
+
#
|
133
|
+
# @return [REXML::Element] The rendered event.
|
134
|
+
def to_junit
|
135
|
+
testcase = REXML::Element.new('testcase')
|
136
|
+
testcase.attributes['classname'] = [source, test].compact.join('.')
|
137
|
+
testcase.attributes['name'] = [file, line, column].compact.join(':')
|
138
|
+
testcase.attributes['time'] = 0
|
139
|
+
|
140
|
+
if failure?
|
141
|
+
failure = REXML::Element.new('failure')
|
142
|
+
failure.attributes['type'] = severity
|
143
|
+
failure.attributes['message'] = message
|
144
|
+
failure.text = to_text
|
145
|
+
testcase.elements << failure
|
146
|
+
elsif skipped?
|
147
|
+
testcase.add_element('skipped')
|
148
|
+
end
|
149
|
+
|
150
|
+
testcase
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
# Processes the data hash used to initialise the event, validating and
|
156
|
+
# munging the values as necessary.
|
157
|
+
#
|
158
|
+
# @param data [Hash{Symbol => Object}] (see #initialize)
|
159
|
+
#
|
160
|
+
# @return [Hash{Symbol => String}] A copy of the data hash passed to the
|
161
|
+
# method with sanitised values.
|
162
|
+
#
|
163
|
+
# @raise [ArgumentError] (see #sanitise_file)
|
164
|
+
# @raise [ArgumentError] (see #sanitise_state)
|
165
|
+
# @raise [ArgumentError] (see #sanitise_source)
|
166
|
+
def sanitise_data(data)
|
167
|
+
result = data.dup
|
168
|
+
data.each do |key, value|
|
169
|
+
key = key.to_sym unless key.is_a?(Symbol)
|
170
|
+
method = "sanitise_#{key}"
|
171
|
+
result[key] = send(method, value) if respond_to?(method, true)
|
172
|
+
end
|
173
|
+
|
174
|
+
result
|
175
|
+
end
|
176
|
+
|
177
|
+
# Munges and validates the file path used to instantiate the event.
|
178
|
+
#
|
179
|
+
# If the path is an absolute path, it will be rewritten so that it is
|
180
|
+
# relative to the module root instead.
|
181
|
+
#
|
182
|
+
# @param value [String] The path to the file that the event is
|
183
|
+
# describing.
|
184
|
+
#
|
185
|
+
# @return [String] The path to the file, relative to the module root.
|
186
|
+
#
|
187
|
+
# @raise [ArgumentError] if the value is nil, an empty String, or not
|
188
|
+
# a String.
|
189
|
+
def sanitise_file(value)
|
190
|
+
if value.nil? || (value.is_a?(String) && value.empty?)
|
191
|
+
raise ArgumentError, _('File not specified.')
|
192
|
+
end
|
193
|
+
|
194
|
+
unless value.is_a?(String)
|
195
|
+
raise ArgumentError, _('File must be a String.')
|
196
|
+
end
|
197
|
+
|
198
|
+
path = Pathname.new(value)
|
199
|
+
|
200
|
+
if path.absolute?
|
201
|
+
module_root = Pathname.new(PDK::Util.module_root)
|
202
|
+
path = path.relative_path_from(module_root).to_path
|
203
|
+
path << '/' if path == '.'
|
204
|
+
path
|
205
|
+
else
|
206
|
+
path.to_path
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Munges and validates the state of the event.
|
211
|
+
#
|
212
|
+
# The valid event states are:
|
213
|
+
# :passed - The event represents a passing test.
|
214
|
+
# :error - The event represents a test that could not be completed due
|
215
|
+
# to an unexpected error.
|
216
|
+
# :failure - The event represents a failing test.
|
217
|
+
# :skipped - The event represents a test that was skipped.
|
218
|
+
#
|
219
|
+
# @param value [Symbol, String] The state of the event. If passed as
|
220
|
+
# a String, it will be turned into a Symbol before validation.
|
221
|
+
#
|
222
|
+
# @return [Symbol] The sanitised state type.
|
223
|
+
#
|
224
|
+
# @raise [ArgumentError] if the value is nil, an empty String, or not
|
225
|
+
# a String or Symbol representation of a valid state.
|
226
|
+
def sanitise_state(value)
|
227
|
+
if value.nil? || (value.is_a?(String) && value.empty?)
|
228
|
+
raise ArgumentError, _('State not specified.')
|
229
|
+
end
|
230
|
+
|
231
|
+
value = value.to_sym if value.is_a?(String)
|
232
|
+
unless value.is_a?(Symbol)
|
233
|
+
raise ArgumentError, _('State must be a Symbol, not %{type}') % { type: value.class }
|
234
|
+
end
|
235
|
+
|
236
|
+
valid_states = [:passed, :error, :failure, :skipped]
|
237
|
+
unless valid_states.include?(value)
|
238
|
+
raise ArgumentError, _('Invalid state %{state}. Valid states are: %{valid}.') % {
|
239
|
+
state: value.inspect,
|
240
|
+
valid: valid_states.map(&:inspect).join(', '),
|
241
|
+
}
|
242
|
+
end
|
243
|
+
|
244
|
+
value
|
245
|
+
end
|
246
|
+
|
247
|
+
# Validates the source of the event.
|
248
|
+
#
|
249
|
+
# @param value [String, Symbol] The name of the source of the event.
|
250
|
+
#
|
251
|
+
# @return [String] the value passed to the event, converted to a String
|
252
|
+
# if necessary.
|
253
|
+
#
|
254
|
+
# @raise [ArgumentError] if the value is nil or an empty String.
|
255
|
+
def sanitise_source(value)
|
256
|
+
if value.nil? || (value.is_a?(String) && value.empty?)
|
257
|
+
raise ArgumentError, _('Source not specified.')
|
258
|
+
end
|
259
|
+
|
260
|
+
value.to_s
|
261
|
+
end
|
262
|
+
|
263
|
+
# Munges the line number of the event into an Integer.
|
264
|
+
#
|
265
|
+
# @param value [Integer, String, Fixnum] The line number.
|
266
|
+
#
|
267
|
+
# @return [Integer] the provided value, converted into an Integer if
|
268
|
+
# necessary.
|
269
|
+
def sanitise_line(value)
|
270
|
+
return nil if value.nil?
|
271
|
+
|
272
|
+
valid_types = [String, Integer]
|
273
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f < 2.4
|
274
|
+
valid_types << Fixnum # rubocop:disable Lint/UnifiedInteger
|
275
|
+
end
|
276
|
+
|
277
|
+
unless valid_types.include?(value.class)
|
278
|
+
raise ArgumentError, _('Line must be an Integer or a String representation of an Integer.')
|
279
|
+
end
|
280
|
+
|
281
|
+
if value.is_a?(String) && value !~ %r{\A[0-9]+\Z}
|
282
|
+
raise ArgumentError, _('The line number can contain only the digits 0-9.')
|
283
|
+
end
|
284
|
+
|
285
|
+
value.to_i
|
286
|
+
end
|
287
|
+
|
288
|
+
# Munges the column number of the event into an Integer.
|
289
|
+
#
|
290
|
+
# @param value [Integer, String, Fixnum] The column number.
|
291
|
+
#
|
292
|
+
# @return [Integer] the provided value, converted into an Integer if
|
293
|
+
# necessary.
|
294
|
+
def sanitise_column(value)
|
295
|
+
return nil if value.nil?
|
296
|
+
|
297
|
+
valid_types = [String, Integer]
|
298
|
+
if RUBY_VERSION.split('.')[0..1].join('.').to_f < 2.4
|
299
|
+
valid_types << Fixnum # rubocop:disable Lint/UnifiedInteger
|
300
|
+
end
|
301
|
+
|
302
|
+
unless valid_types.include?(value.class)
|
303
|
+
raise ArgumentError, _('Column must be an Integer or a String representation of an Integer.')
|
304
|
+
end
|
305
|
+
|
306
|
+
if value.is_a?(String) && value !~ %r{\A[0-9]+\Z}
|
307
|
+
raise ArgumentError, _('The column number can contain only the digits 0-9.')
|
308
|
+
end
|
309
|
+
|
310
|
+
value.to_i
|
311
|
+
end
|
312
|
+
|
313
|
+
# Cleans up provided stack trace by removing entries that are inside gems
|
314
|
+
# or the rspec binstub.
|
315
|
+
#
|
316
|
+
# @param value [Array] Array of stack trace lines
|
317
|
+
#
|
318
|
+
# @return [Array] Array of stack trace lines with less relevant lines excluded
|
319
|
+
def sanitise_trace(value)
|
320
|
+
return nil if value.nil?
|
321
|
+
|
322
|
+
valid_types = [Array]
|
323
|
+
|
324
|
+
unless valid_types.include?(value.class)
|
325
|
+
raise ArgumentError, _('Trace must be an Array of stack trace lines.')
|
326
|
+
end
|
327
|
+
|
328
|
+
# Drop any stacktrace lines that include '/gems/' in the path or
|
329
|
+
# are the original rspec binstub lines
|
330
|
+
value.reject do |line|
|
331
|
+
(line =~ %r{/gems/}) || (line =~ %r{bin/rspec:})
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
# Extract contextual information for the event from the file that it
|
336
|
+
# references.
|
337
|
+
#
|
338
|
+
# @param max_num_lines [Integer] The maximum number of lines to return.
|
339
|
+
#
|
340
|
+
# @return [Array] Array of lines from the file, centred on the line
|
341
|
+
# number of the event.
|
342
|
+
def context_lines(max_num_lines = 5)
|
343
|
+
return if file.nil? || line.nil?
|
344
|
+
|
345
|
+
file_path = [file, File.join(PDK::Util.module_root, file)].find { |r| File.file?(r) }
|
346
|
+
return if file_path.nil?
|
347
|
+
|
348
|
+
file_content = File.read(file_path).split("\n")
|
349
|
+
delta = (max_num_lines - 1) / 2
|
350
|
+
min = [0, (line - 1) - delta].max
|
351
|
+
max = [(line - 1) + delta, file_content.length].min
|
352
|
+
|
353
|
+
file_content[min..max].map { |r| " #{r}" }
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|