appmap 0.100.0 → 0.102.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/CHANGELOG.md +19 -0
- data/lib/appmap/agent.rb +1 -0
- data/lib/appmap/cucumber.rb +8 -5
- data/lib/appmap/detect_enabled.rb +50 -31
- data/lib/appmap/minitest.rb +12 -10
- data/lib/appmap/rspec.rb +25 -19
- data/lib/appmap/rswag.rb +70 -0
- data/lib/appmap/trace.rb +12 -12
- data/lib/appmap/util.rb +43 -31
- data/lib/appmap/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1df97ff2f7c62ce830193389327e102a89798678350dbc653aecc98157e502cb
|
4
|
+
data.tar.gz: ff14a72537014f549a5094b592a6dd28e9a6658679e0c411529d7c4c12491822
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21781f0d7b9d61d72cd6b442b1105a1eabd19ba07ccca62bb8fd5acaede9e6db2a3cf5594a80c1270ff574d977b709c22031a12a88361cd36fe3013e5238cb03
|
7
|
+
data.tar.gz: bcc9fd8526da90172d0f7f159a1c4a61a0245e70d1d800f38b98e1d13f0a35ee26898c064107a0de5eb3f7d11d1eecf98c12df1f14a4c37cb72582a1a6bdcf1d
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
# [0.102.0](https://github.com/getappmap/appmap-ruby/compare/v0.101.0...v0.102.0) (2023-07-18)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Discourage conflicting recording methods ([f86303b](https://github.com/getappmap/appmap-ruby/commit/f86303bf1b62d5131d9ed2c10e01225ec21c1405))
|
7
|
+
|
8
|
+
# [0.101.0](https://github.com/getappmap/appmap-ruby/compare/v0.100.0...v0.101.0) (2023-07-17)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Auto-enable tracing on block recording ([59886b6](https://github.com/getappmap/appmap-ruby/commit/59886b6b4720240e9f961a8b76f3035eaf3be44e))
|
14
|
+
|
15
|
+
|
16
|
+
### Features
|
17
|
+
|
18
|
+
* Record RSwag ([a60d480](https://github.com/getappmap/appmap-ruby/commit/a60d4803feeab519ef4eae1702da00e3dc2dd4ea))
|
19
|
+
|
1
20
|
# [0.100.0](https://github.com/getappmap/appmap-ruby/compare/v0.99.4...v0.100.0) (2023-07-11)
|
2
21
|
|
3
22
|
|
data/lib/appmap/agent.rb
CHANGED
data/lib/appmap/cucumber.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative '../appmap'
|
4
|
+
require_relative './util'
|
5
|
+
require_relative './detect_enabled'
|
5
6
|
require 'fileutils'
|
6
7
|
|
7
8
|
module AppMap
|
8
9
|
module Cucumber
|
9
10
|
APPMAP_OUTPUT_DIR = 'tmp/appmap/cucumber'
|
10
|
-
|
11
|
+
|
11
12
|
ScenarioAttributes = Struct.new(:name, :feature, :feature_group)
|
12
13
|
|
13
14
|
ProviderStruct = Struct.new(:scenario) do
|
@@ -43,11 +44,13 @@ module AppMap
|
|
43
44
|
|
44
45
|
class << self
|
45
46
|
def init
|
47
|
+
AppMap::DetectEnabled.discourage_conflicting_recording_methods :cucumber
|
48
|
+
|
46
49
|
warn 'Configuring AppMap recorder for Cucumber'
|
47
50
|
|
48
51
|
FileUtils.mkdir_p APPMAP_OUTPUT_DIR
|
49
52
|
end
|
50
|
-
|
53
|
+
|
51
54
|
def write_scenario(scenario, appmap)
|
52
55
|
appmap['metadata'] = update_metadata(scenario, appmap['metadata'])
|
53
56
|
scenario_filename = AppMap::Util.scenario_filename(appmap['metadata']['name'])
|
@@ -62,7 +65,7 @@ module AppMap
|
|
62
65
|
def run
|
63
66
|
init
|
64
67
|
end
|
65
|
-
|
68
|
+
|
66
69
|
protected
|
67
70
|
|
68
71
|
def cucumber_version
|
@@ -9,6 +9,32 @@ module AppMap
|
|
9
9
|
@@detected_for_method = {}
|
10
10
|
|
11
11
|
class << self
|
12
|
+
def discourage_conflicting_recording_methods(recording_method)
|
13
|
+
return if ENV['APPMAP_DISCOURAGE_CONFLICTING_RECORDING_METHODS'] == 'false'
|
14
|
+
|
15
|
+
return unless enabled?(recording_method.to_sym) && enabled?(:requests)
|
16
|
+
|
17
|
+
warn Util.color <<~MSG, :yellow
|
18
|
+
AppMap recording is enabled for both 'requests' and '#{recording_method}'. This is not recommended
|
19
|
+
because the recordings will contain duplicitive information, and in some case may conflict with each other.
|
20
|
+
MSG
|
21
|
+
|
22
|
+
return unless ENV['APPMAP'] == 'true'
|
23
|
+
|
24
|
+
warn Util.color <<~MSG, :yellow
|
25
|
+
The environment contains APPMAP=true, which is not recommended in this application environment because
|
26
|
+
it enables all recording methods. Consider letting AppMap detect the appropriate recording method,
|
27
|
+
or explicitly enabling only the recording methods you want to use using environment variables like
|
28
|
+
APPMAP_RECORD_REQUESTS, APPMAP_RECORD_RSPEC, etc.
|
29
|
+
|
30
|
+
See https://appmap.io/docs/reference/appmap-ruby.html#advanced-runtime-options for more information.
|
31
|
+
MSG
|
32
|
+
end
|
33
|
+
|
34
|
+
def enabled?(recording_method)
|
35
|
+
new(recording_method).enabled?
|
36
|
+
end
|
37
|
+
|
12
38
|
def clear_cache
|
13
39
|
@@detected_for_method = {}
|
14
40
|
end
|
@@ -19,20 +45,20 @@ module AppMap
|
|
19
45
|
end
|
20
46
|
|
21
47
|
def enabled?
|
22
|
-
unless @@detected_for_method[@recording_method].nil?
|
23
|
-
return @@detected_for_method[@recording_method]
|
24
|
-
end
|
48
|
+
return @@detected_for_method[@recording_method] unless @@detected_for_method[@recording_method].nil?
|
25
49
|
|
26
|
-
|
50
|
+
if @recording_method && !AppMap::RECORDING_METHODS.member?(@recording_method)
|
51
|
+
raise "Unrecognized recording method: #{@recording_method}"
|
52
|
+
end
|
27
53
|
|
28
54
|
message, enabled, enabled_by_env = detect_enabled
|
29
55
|
|
30
56
|
@@detected_for_method[@recording_method] = enabled
|
31
57
|
|
32
|
-
if @recording_method
|
33
|
-
|
34
|
-
|
35
|
-
|
58
|
+
if @recording_method && (enabled && enabled_by_app_env?)
|
59
|
+
warn AppMap::Util.color(
|
60
|
+
"AppMap #{@recording_method.nil? ? '' : "#{@recording_method} "}recording is enabled because #{message}", :magenta
|
61
|
+
)
|
36
62
|
end
|
37
63
|
|
38
64
|
enabled
|
@@ -49,48 +75,41 @@ module AppMap
|
|
49
75
|
]
|
50
76
|
|
51
77
|
message, enabled = []
|
52
|
-
while enabled.nil? && !detection_functions.empty?
|
53
|
-
message, enabled = method(detection_functions.shift).call
|
54
|
-
end
|
78
|
+
message, enabled = method(detection_functions.shift).call while enabled.nil? && !detection_functions.empty?
|
55
79
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
return [ 'it is not enabled by any configuration or framework', false, false ]
|
61
|
-
end
|
80
|
+
return [ 'it is not enabled by any configuration or framework', false, false ] if enabled.nil?
|
81
|
+
|
82
|
+
_, enabled_by_env = enabled_by_app_env?
|
83
|
+
[ message, enabled, enabled_by_env ]
|
62
84
|
end
|
63
85
|
|
64
86
|
def enabled_by_testing?
|
65
|
-
|
66
|
-
|
67
|
-
|
87
|
+
return unless %i[rspec minitest cucumber].member?(@recording_method)
|
88
|
+
|
89
|
+
[ "running tests with #{@recording_method}", true ]
|
68
90
|
end
|
69
91
|
|
70
92
|
def enabled_by_app_env?
|
71
93
|
env_name, app_env = detect_app_env
|
72
|
-
if @recording_method.nil?
|
73
|
-
return [ "#{env_name} is '#{app_env}'", true ] if %w[test development].member?(app_env)
|
74
|
-
end
|
94
|
+
return [ "#{env_name} is '#{app_env}'", true ] if @recording_method.nil? && %w[test development].member?(app_env)
|
75
95
|
|
76
|
-
|
77
|
-
|
78
|
-
end
|
96
|
+
return unless %i[remote requests].member?(@recording_method)
|
97
|
+
return [ "#{env_name} is '#{app_env}'", true ] if app_env == 'development'
|
79
98
|
end
|
80
99
|
|
81
100
|
def detect_app_env
|
82
101
|
if rails_env
|
83
|
-
|
102
|
+
[ 'RAILS_ENV', rails_env ]
|
84
103
|
elsif ENV['APP_ENV']
|
85
|
-
|
104
|
+
[ 'APP_ENV', ENV['APP_ENV']]
|
86
105
|
end
|
87
106
|
end
|
88
107
|
|
89
108
|
def globally_enabled?
|
90
109
|
# Don't auto-enable request recording in the 'test' environment, because users probably don't want
|
91
110
|
# AppMaps of both test cases and requests. Requests recording can always be enabled by APPMAP_RECORD_REQUESTS=true.
|
92
|
-
requests_recording_in_test = ->
|
93
|
-
[ 'APPMAP=true', true ] if ENV['APPMAP'] == 'true' && !requests_recording_in_test.
|
111
|
+
requests_recording_in_test = -> { [ :requests ].member?(@recording_method) && detect_app_env == 'test' }
|
112
|
+
[ 'APPMAP=true', true ] if ENV['APPMAP'] == 'true' && !requests_recording_in_test.call
|
94
113
|
end
|
95
114
|
|
96
115
|
def globally_disabled?
|
@@ -114,7 +133,7 @@ module AppMap
|
|
114
133
|
def rails_env
|
115
134
|
return Rails.env if defined?(::Rails::Railtie)
|
116
135
|
|
117
|
-
|
136
|
+
ENV.fetch('RAILS_ENV', nil)
|
118
137
|
end
|
119
138
|
end
|
120
139
|
end
|
data/lib/appmap/minitest.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative '../appmap'
|
4
|
+
require_relative './util'
|
5
|
+
require_relative './detect_enabled'
|
5
6
|
require 'fileutils'
|
6
7
|
require 'active_support'
|
7
8
|
require 'active_support/core_ext'
|
@@ -32,7 +33,9 @@ module AppMap
|
|
32
33
|
|
33
34
|
def finish(failures, exception)
|
34
35
|
failed = failures.any? || exception
|
35
|
-
|
36
|
+
if AppMap::Minitest::LOG
|
37
|
+
warn "Finishing recording of #{failed ? 'failed ' : ''} test #{test.class}.#{test.name}"
|
38
|
+
end
|
36
39
|
warn "Exception: #{exception}" if exception && AppMap::Minitest::LOG
|
37
40
|
|
38
41
|
if failed
|
@@ -78,7 +81,8 @@ module AppMap
|
|
78
81
|
end
|
79
82
|
|
80
83
|
def begin_test(test, name)
|
81
|
-
AppMap.
|
84
|
+
AppMap::DetectEnabled.discourage_conflicting_recording_methods :minitest if first_recording?
|
85
|
+
|
82
86
|
@recording_count += 1
|
83
87
|
|
84
88
|
@recordings_by_test[test.object_id] = Recording.new(test, name)
|
@@ -107,24 +111,22 @@ module AppMap
|
|
107
111
|
m[:frameworks] ||= []
|
108
112
|
m[:frameworks] << {
|
109
113
|
name: 'minitest',
|
110
|
-
version: Gem.loaded_specs['minitest']&.version&.to_s
|
114
|
+
version: Gem.loaded_specs['minitest']&.version&.to_s
|
111
115
|
}
|
112
116
|
m[:recorder] = {
|
113
117
|
name: 'minitest',
|
114
|
-
type: 'tests'
|
118
|
+
type: 'tests'
|
115
119
|
}
|
116
120
|
m[:test_status] = test_status
|
117
121
|
m[:test_failure] = test_failure if test_failure
|
118
|
-
if exception
|
119
|
-
m[:exception] = Util.format_exception(exception)
|
120
|
-
end
|
122
|
+
m[:exception] = Util.format_exception(exception) if exception
|
121
123
|
end
|
122
124
|
|
123
125
|
appmap = {
|
124
126
|
version: AppMap::APPMAP_FORMAT_VERSION,
|
125
127
|
metadata: metadata,
|
126
128
|
classMap: class_map,
|
127
|
-
events: events
|
129
|
+
events: events
|
128
130
|
}.compact
|
129
131
|
fname = AppMap::Util.scenario_filename(name)
|
130
132
|
|
data/lib/appmap/rspec.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require_relative '../appmap'
|
4
|
+
require_relative './util'
|
5
|
+
require_relative './detect_enabled'
|
5
6
|
require 'set'
|
6
7
|
require 'fileutils'
|
7
8
|
|
@@ -68,7 +69,7 @@ module AppMap
|
|
68
69
|
example_group.parent_groups.first
|
69
70
|
end
|
70
71
|
|
71
|
-
example_group_parent
|
72
|
+
example_group_parent == example_group ? nil : ScopeExampleGroup.new(example_group_parent)
|
72
73
|
end
|
73
74
|
end
|
74
75
|
|
@@ -87,7 +88,7 @@ module AppMap
|
|
87
88
|
|
88
89
|
warn "Starting recording of example #{example}@#{source_location}" if AppMap::RSpec::LOG
|
89
90
|
@trace = AppMap.tracing.trace
|
90
|
-
@webdriver_port = webdriver_port.
|
91
|
+
@webdriver_port = webdriver_port.call
|
91
92
|
end
|
92
93
|
|
93
94
|
def source_location
|
@@ -147,7 +148,7 @@ module AppMap
|
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
150
|
-
@recordings_by_example = {}
|
151
|
+
@recordings_by_example = {}.tap(&:compare_by_identity)
|
151
152
|
@event_methods = Set.new
|
152
153
|
@recording_count = 0
|
153
154
|
|
@@ -161,34 +162,38 @@ module AppMap
|
|
161
162
|
end
|
162
163
|
|
163
164
|
def begin_spec(example)
|
164
|
-
AppMap.
|
165
|
-
@recording_count += 1
|
166
|
-
|
167
|
-
recording = if example.metadata[:appmap] != false
|
168
|
-
Recording.new(example)
|
169
|
-
else
|
170
|
-
:false
|
171
|
-
end
|
165
|
+
AppMap::DetectEnabled.discourage_conflicting_recording_methods :rspec if first_recording?
|
172
166
|
|
173
|
-
@
|
167
|
+
@recording_count += 1
|
168
|
+
# Disable RSpec recording for RSwag, because all the action happens in the before block.
|
169
|
+
# The example is empty except for assertions. So RSwag has its own recorder, and RSpec
|
170
|
+
# recording is disabled so it won't clobber the AppMap with empty data.
|
171
|
+
recording = if example.metadata[:appmap] == false || example.metadata[:rswag]
|
172
|
+
:disabled
|
173
|
+
else
|
174
|
+
Recording.new(example)
|
175
|
+
end
|
176
|
+
|
177
|
+
@recordings_by_example[example] = recording
|
174
178
|
end
|
175
179
|
|
176
180
|
def end_spec(example, exception:)
|
177
|
-
recording = @recordings_by_example.delete(example
|
181
|
+
recording = @recordings_by_example.delete(example)
|
178
182
|
return warn "No recording found for #{example}" unless recording
|
179
183
|
|
180
|
-
recording.finish example.execution_result.exception || exception, exception unless recording == :
|
184
|
+
recording.finish example.execution_result.exception || exception, exception unless recording == :disabled
|
181
185
|
end
|
182
186
|
|
183
187
|
def config
|
184
|
-
@config or raise
|
188
|
+
@config or raise 'AppMap is not configured'
|
185
189
|
end
|
186
190
|
|
187
191
|
def add_event_methods(event_methods)
|
188
192
|
@event_methods += event_methods
|
189
193
|
end
|
190
194
|
|
191
|
-
def save(name:, class_map:, source_location:, test_status:, test_failure:, exception:, events:
|
195
|
+
def save(name:, class_map:, source_location:, test_status:, test_failure:, exception:, events:, frameworks: [],
|
196
|
+
recorder: nil)
|
192
197
|
metadata = AppMap::RSpec.metadata.tap do |m|
|
193
198
|
m[:name] = name
|
194
199
|
m[:source_location] = source_location
|
@@ -198,7 +203,8 @@ module AppMap
|
|
198
203
|
name: 'rspec',
|
199
204
|
version: Gem.loaded_specs['rspec-core']&.version&.to_s
|
200
205
|
}
|
201
|
-
m[:
|
206
|
+
m[:frameworks] += frameworks
|
207
|
+
m[:recorder] = recorder || {
|
202
208
|
name: 'rspec',
|
203
209
|
type: 'tests'
|
204
210
|
}
|
data/lib/appmap/rswag.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'appmap'
|
4
|
+
|
5
|
+
module AppMap
|
6
|
+
module Rswag
|
7
|
+
def self.record(metadata, &block)
|
8
|
+
description = metadata[:full_description]
|
9
|
+
warn "Recording of RSwag test #{description}" if AppMap::RSpec::LOG
|
10
|
+
source_location = (metadata[:example_group] || {})[:location]
|
11
|
+
|
12
|
+
appmap = AppMap.record(&block)
|
13
|
+
|
14
|
+
events = appmap['events']
|
15
|
+
class_map = appmap['classMap']
|
16
|
+
|
17
|
+
exception = (events.last || {})[:exception]
|
18
|
+
failed = true if exception
|
19
|
+
warn "Finishing recording of #{failed ? 'failed ' : ''} RSwag test #{description}" if AppMap::RSpec::LOG
|
20
|
+
warn "Exception: #{exception}" if exception && AppMap::RSpec::LOG
|
21
|
+
|
22
|
+
if failed
|
23
|
+
warn "Failure exception: #{exception}" if AppMap::RSpec::LOG
|
24
|
+
test_failure = Util.extract_test_failure(exception)
|
25
|
+
end
|
26
|
+
|
27
|
+
AppMap::RSpec.save name: description,
|
28
|
+
class_map: class_map,
|
29
|
+
source_location: source_location,
|
30
|
+
test_status: exception ? 'failed' : 'succeeded',
|
31
|
+
test_failure: test_failure,
|
32
|
+
exception: exception,
|
33
|
+
events: events,
|
34
|
+
frameworks: [
|
35
|
+
{ name: 'rswag',
|
36
|
+
version: Gem.loaded_specs['rswag-specs']&.version&.to_s }
|
37
|
+
],
|
38
|
+
recorder: {
|
39
|
+
name: 'rswag',
|
40
|
+
type: 'tests'
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
class << self
|
45
|
+
def enabled?
|
46
|
+
RSpec.enabled? && defined?(Rswag)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if Rswag.enabled?
|
52
|
+
require 'rswag'
|
53
|
+
require 'rswag/specs'
|
54
|
+
require 'appmap/rspec'
|
55
|
+
|
56
|
+
module ::Rswag
|
57
|
+
module Specs
|
58
|
+
module ExampleHelpers
|
59
|
+
alias submit_request_without_appmap submit_request
|
60
|
+
|
61
|
+
def submit_request(metadata)
|
62
|
+
AppMap::Rswag.record(metadata) do
|
63
|
+
submit_request_without_appmap(metadata)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/appmap/trace.rb
CHANGED
@@ -24,7 +24,7 @@ module AppMap
|
|
24
24
|
return nil if source_location.nil? || source_location.first.start_with?('<')
|
25
25
|
|
26
26
|
# Do not use method_source's comment method because it's slow
|
27
|
-
@comment ||= RubyMethod.last_comment
|
27
|
+
@comment ||= RubyMethod.last_comment(*source_location)
|
28
28
|
rescue Errno::EINVAL, Errno::ENOENT
|
29
29
|
nil
|
30
30
|
end
|
@@ -41,8 +41,6 @@ module AppMap
|
|
41
41
|
@package.labels
|
42
42
|
end
|
43
43
|
|
44
|
-
private
|
45
|
-
|
46
44
|
# Read file and get last comment before line.
|
47
45
|
def self.last_comment(file, line_number)
|
48
46
|
File.open(file) do |f|
|
@@ -114,19 +112,19 @@ module AppMap
|
|
114
112
|
end
|
115
113
|
|
116
114
|
def initialize
|
117
|
-
@@stacks ||=
|
115
|
+
@@stacks ||= {}
|
118
116
|
end
|
119
117
|
|
120
118
|
def record(event)
|
121
119
|
stack = caller.select { |line| !line.index('/lib/appmap/') }[0...StackPrinter.depth].join("\n ")
|
122
120
|
stack_hash = Digest::SHA256.hexdigest(stack)
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
121
|
+
return if @@stacks[stack_hash]
|
122
|
+
|
123
|
+
@@stacks[stack_hash] = stack
|
124
|
+
puts
|
125
|
+
puts 'Event: ' + event.to_h.map { |k, v| [ "#{k}: #{v}" ] }.join(', ')
|
126
|
+
puts ' ' + stack
|
127
|
+
puts
|
130
128
|
end
|
131
129
|
end
|
132
130
|
|
@@ -163,7 +161,9 @@ module AppMap
|
|
163
161
|
def record_event(event, package: nil, defined_class: nil, method: nil)
|
164
162
|
return unless @enabled
|
165
163
|
|
166
|
-
|
164
|
+
if @thread_id && @thread_id != event.thread_id
|
165
|
+
raise "Expected event in thread #{@thread_id}, got #{event.thread_id}"
|
166
|
+
end
|
167
167
|
|
168
168
|
@stack_printer.record(event) if @stack_printer
|
169
169
|
@last_package_for_thread[Thread.current.object_id] = package if package
|
data/lib/appmap/util.rb
CHANGED
@@ -25,9 +25,17 @@ module AppMap
|
|
25
25
|
package_tokens = name.split('/')
|
26
26
|
|
27
27
|
class_and_name = package_tokens.pop
|
28
|
-
class_name, function_name, static = class_and_name.include?('.')
|
28
|
+
class_name, function_name, static = if class_and_name.include?('.')
|
29
|
+
class_and_name.split('.',
|
30
|
+
2) + [ true ]
|
31
|
+
else
|
32
|
+
class_and_name.split(
|
33
|
+
'#', 2
|
34
|
+
) + [ false ]
|
35
|
+
end
|
29
36
|
|
30
37
|
raise "Malformed fully-qualified function name #{name}" unless function_name
|
38
|
+
|
31
39
|
[ package_tokens.empty? ? 'ruby' : package_tokens.join('/'), class_name, static, function_name ]
|
32
40
|
end
|
33
41
|
|
@@ -70,20 +78,20 @@ module AppMap
|
|
70
78
|
def sanitize_paths(h)
|
71
79
|
require 'hashie'
|
72
80
|
h.extend(Hashie::Extensions::DeepLocate)
|
73
|
-
keys = %i
|
74
|
-
h.deep_locate
|
81
|
+
keys = %i[path location]
|
82
|
+
h.deep_locate lambda { |k, _v, o|
|
75
83
|
next unless keys.include?(k)
|
76
|
-
|
77
|
-
fix = ->(v) {v.gsub(%r{#{Gem.dir}/gems/.*(?=lib)}, '')}
|
78
|
-
keys.each {|k| o[k] = fix.(o[k]) if o[k] }
|
84
|
+
|
85
|
+
fix = ->(v) { v.gsub(%r{#{Gem.dir}/gems/.*(?=lib)}, '') }
|
86
|
+
keys.each { |k| o[k] = fix.call(o[k]) if o[k] }
|
79
87
|
}
|
80
88
|
|
81
89
|
h
|
82
90
|
end
|
83
|
-
|
91
|
+
|
84
92
|
# sanitize_event removes ephemeral values from an event, making
|
85
93
|
# events easier to compare across runs.
|
86
|
-
def sanitize_event(event
|
94
|
+
def sanitize_event(event)
|
87
95
|
event.delete(:thread_id)
|
88
96
|
event.delete(:elapsed)
|
89
97
|
event.delete(:elapsed_instrumentation)
|
@@ -114,8 +122,8 @@ module AppMap
|
|
114
122
|
blank?(headers) ? nil : headers
|
115
123
|
end
|
116
124
|
|
117
|
-
|
118
|
-
warn
|
125
|
+
unless env['rack.version']
|
126
|
+
warn 'Request headers does not contain rack.version. HTTP_ prefix is not expected.'
|
119
127
|
return finalize_headers.call(env.dup)
|
120
128
|
end
|
121
129
|
|
@@ -123,18 +131,18 @@ module AppMap
|
|
123
131
|
# Apparently, it's following the CGI spec in doing so.
|
124
132
|
# https://datatracker.ietf.org/doc/html/rfc3875#section-4.1.18
|
125
133
|
matching_headers = env
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
134
|
+
.select { |k, _v| k.to_s.start_with? 'HTTP_' }
|
135
|
+
.merge(
|
136
|
+
'CONTENT_TYPE' => env['CONTENT_TYPE'],
|
137
|
+
'CONTENT_LENGTH' => env['CONTENT_LENGTH'],
|
138
|
+
'AUTHORIZATION' => env['AUTHORIZATION']
|
139
|
+
)
|
140
|
+
.reject { |_k, v| blank?(v) }
|
141
|
+
.each_with_object({}) do |kv, memo|
|
142
|
+
key = kv[0].sub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
|
143
|
+
value = kv[1]
|
144
|
+
memo[key] = value
|
145
|
+
end
|
138
146
|
finalize_headers.call(matching_headers)
|
139
147
|
end
|
140
148
|
|
@@ -143,7 +151,7 @@ module AppMap
|
|
143
151
|
is_bundled_path = -> { path.index(Bundler.bundle_path.to_s) == 0 }
|
144
152
|
is_vendored_path = -> { path.index(File.join(Dir.pwd, 'vendor/bundle')) == 0 }
|
145
153
|
|
146
|
-
if is_local_path.
|
154
|
+
if is_local_path.call && !is_bundled_path.call && !is_vendored_path.call
|
147
155
|
path[Dir.pwd.length + 1..-1]
|
148
156
|
else
|
149
157
|
path
|
@@ -153,7 +161,7 @@ module AppMap
|
|
153
161
|
def format_exception(exception)
|
154
162
|
{
|
155
163
|
class: exception.class.name,
|
156
|
-
message: AppMap::Event::MethodEvent.display_string(exception.to_s)
|
164
|
+
message: AppMap::Event::MethodEvent.display_string(exception.to_s)
|
157
165
|
}
|
158
166
|
end
|
159
167
|
|
@@ -164,7 +172,10 @@ module AppMap
|
|
164
172
|
first_location = exception.backtrace_locations&.find do |location|
|
165
173
|
!Pathname.new(normalize_path(location.absolute_path || location.path)).absolute?
|
166
174
|
end
|
167
|
-
|
175
|
+
if first_location
|
176
|
+
test_failure[:location] =
|
177
|
+
[ normalize_path(first_location.path), first_location.lineno ].join(':')
|
178
|
+
end
|
168
179
|
end
|
169
180
|
end
|
170
181
|
|
@@ -175,7 +186,7 @@ module AppMap
|
|
175
186
|
tokens = path.split('/')
|
176
187
|
tokens.map do |token|
|
177
188
|
# stop matching if an ending ) is found
|
178
|
-
token.gsub(/^:(.*[
|
189
|
+
token.gsub(/^:(.*[^)])/, '{\1}')
|
179
190
|
end.join('/')
|
180
191
|
end
|
181
192
|
|
@@ -196,22 +207,23 @@ module AppMap
|
|
196
207
|
|
197
208
|
def color(text, color, bold: false)
|
198
209
|
color = Util.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
199
|
-
bold = bold ? BOLD :
|
210
|
+
bold = bold ? BOLD : ''
|
200
211
|
"#{bold}#{color}#{text}#{CLEAR}"
|
201
212
|
end
|
202
213
|
|
203
214
|
def classify(word)
|
204
|
-
word.split(/[
|
215
|
+
word.split(/[-_]/).map(&:capitalize).join
|
205
216
|
end
|
206
217
|
|
207
218
|
# https://api.rubyonrails.org/v6.1.3.2/classes/ActiveSupport/Inflector.html#method-i-underscore
|
208
219
|
def underscore(camel_cased_word)
|
209
220
|
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
210
|
-
|
221
|
+
|
222
|
+
word = camel_cased_word.to_s.gsub('::', '/')
|
211
223
|
# word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
|
212
224
|
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
213
225
|
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
214
|
-
word.tr!(
|
226
|
+
word.tr!('-', '_')
|
215
227
|
word.downcase!
|
216
228
|
word
|
217
229
|
end
|
@@ -223,7 +235,7 @@ module AppMap
|
|
223
235
|
|
224
236
|
def blank?(obj)
|
225
237
|
return true if obj.nil?
|
226
|
-
|
238
|
+
|
227
239
|
return true if obj.is_a?(String) && obj == ''
|
228
240
|
|
229
241
|
return true if obj.respond_to?(:length) && obj.length == 0
|
data/lib/appmap/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appmap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.102.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Gilpin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07-
|
11
|
+
date: 2023-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: method_source
|
@@ -425,6 +425,7 @@ files:
|
|
425
425
|
- lib/appmap/record.rb
|
426
426
|
- lib/appmap/recording_methods.rb
|
427
427
|
- lib/appmap/rspec.rb
|
428
|
+
- lib/appmap/rswag.rb
|
428
429
|
- lib/appmap/service/config_analyzer.rb
|
429
430
|
- lib/appmap/service/guesser.rb
|
430
431
|
- lib/appmap/service/integration_test_path_finder.rb
|