appmap 0.52.1 → 0.54.3
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/.travis.yml +16 -10
- data/CHANGELOG.md +41 -0
- data/Rakefile +13 -4
- data/appmap.gemspec +1 -1
- data/exe/appmap-agent-init +19 -0
- data/lib/appmap.rb +31 -112
- data/lib/appmap/agent.rb +115 -0
- data/lib/appmap/class_map.rb +2 -2
- data/lib/appmap/config.rb +11 -3
- data/lib/appmap/handler/net_http.rb +3 -2
- data/lib/appmap/handler/rails/request_handler.rb +2 -1
- data/lib/appmap/handler/rails/template.rb +2 -1
- data/lib/appmap/hook.rb +0 -1
- data/lib/appmap/hook/method.rb +36 -28
- data/lib/appmap/metadata.rb +4 -2
- data/lib/appmap/minitest.rb +2 -0
- data/lib/appmap/railtie.rb +2 -2
- data/lib/appmap/rspec.rb +5 -3
- data/lib/appmap/swagger.rb +2 -0
- data/lib/appmap/swagger/configuration.rb +70 -0
- data/lib/appmap/swagger/markdown_descriptions.rb +43 -0
- data/lib/appmap/swagger/rake_tasks.rb +43 -0
- data/lib/appmap/swagger/stable.rb +37 -0
- data/lib/appmap/trace.rb +2 -0
- data/lib/appmap/util.rb +17 -1
- data/lib/appmap/version.rb +1 -1
- data/package.json +0 -1
- data/release.sh +0 -1
- data/spec/config_spec.rb +0 -1
- data/spec/fixtures/hook/.gitignore +2 -0
- data/spec/fixtures/hook/app/controllers/api/api_keys_controller.rb +1 -0
- data/spec/fixtures/hook/app/controllers/organizations_controller.rb +1 -0
- data/spec/fixtures/hook/app/models/api_key.rb +1 -0
- data/spec/fixtures/hook/app/models/configuration.rb +1 -0
- data/spec/fixtures/hook/app/models/show.rb +1 -0
- data/spec/fixtures/hook/app/models/user.rb +1 -0
- data/spec/fixtures/hook/kwargs.rb +11 -0
- data/spec/fixtures/hook/revoke_api_key.appmap.json +847 -0
- data/spec/fixtures/hook/spec/api_spec.rb +1 -0
- data/spec/fixtures/hook/spec/user_spec.rb +1 -0
- data/spec/fixtures/hook/user_page_scenario.appmap.json +1722 -0
- data/spec/fixtures/rails5_users_app/config/environments/test.rb +3 -0
- data/spec/fixtures/rails6_users_app/Dockerfile +0 -1
- data/spec/fixtures/rails6_users_app/appmap.yml +3 -1
- data/spec/fixtures/rails6_users_app/config/environments/test.rb +3 -0
- data/spec/fixtures/rails6_users_app/lib/tasks/appmap.rake +13 -0
- data/spec/hook_spec.rb +9 -0
- data/spec/rails_recording_spec.rb +1 -1
- data/spec/record_net_http_spec.rb +1 -0
- data/spec/swagger/swagger_spec.rb +47 -0
- data/test/{agent_setup_cli_test.rb → agent_setup_init_test.rb} +4 -4
- data/test/gem_test.rb +1 -0
- metadata +39 -19
- data/exe/appmap-agent-setup +0 -47
data/lib/appmap/class_map.rb
CHANGED
@@ -111,7 +111,7 @@ module AppMap
|
|
111
111
|
end
|
112
112
|
|
113
113
|
comment = method.comment
|
114
|
-
function_info[:comment] = comment unless
|
114
|
+
function_info[:comment] = comment unless Util.blank?(comment)
|
115
115
|
|
116
116
|
function_info[:labels] = parse_labels(comment) + (method.labels || [])
|
117
117
|
object_infos << function_info
|
@@ -119,7 +119,7 @@ module AppMap
|
|
119
119
|
parent = root
|
120
120
|
object_infos.each do |info|
|
121
121
|
parent = find_or_create parent.children, info do
|
122
|
-
Types.const_get(info[:type]
|
122
|
+
Types.const_get(Util.classify(info[:type])).new(info[:name].to_s).tap do |type|
|
123
123
|
info.keys.tap do |keys|
|
124
124
|
keys.delete(:name)
|
125
125
|
keys.delete(:type)
|
data/lib/appmap/config.rb
CHANGED
@@ -5,6 +5,7 @@ require 'appmap/util'
|
|
5
5
|
require 'appmap/handler/net_http'
|
6
6
|
require 'appmap/handler/rails/template'
|
7
7
|
require 'appmap/service/guesser'
|
8
|
+
require 'appmap/swagger/configuration'
|
8
9
|
|
9
10
|
module AppMap
|
10
11
|
class Config
|
@@ -81,8 +82,8 @@ module AppMap
|
|
81
82
|
package_name: package_name,
|
82
83
|
gem: gem,
|
83
84
|
handler_class: handler_class.name,
|
84
|
-
exclude:
|
85
|
-
labels:
|
85
|
+
exclude: Util.blank?(exclude) ? nil : exclude,
|
86
|
+
labels: Util.blank?(labels) ? nil : labels,
|
86
87
|
shallow: shallow
|
87
88
|
}.compact
|
88
89
|
end
|
@@ -226,15 +227,17 @@ module AppMap
|
|
226
227
|
'JSON::Ext::Generator::State' => TargetMethods.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json.generate])),
|
227
228
|
}.freeze
|
228
229
|
|
229
|
-
attr_reader :name, :appmap_dir, :packages, :exclude, :hooked_methods, :builtin_hooks
|
230
|
+
attr_reader :name, :appmap_dir, :packages, :exclude, :swagger_config, :hooked_methods, :builtin_hooks
|
230
231
|
|
231
232
|
def initialize(name,
|
232
233
|
packages: [],
|
234
|
+
swagger_config: Swagger::Configuration.new,
|
233
235
|
exclude: [],
|
234
236
|
functions: [])
|
235
237
|
@name = name
|
236
238
|
@appmap_dir = AppMap::DEFAULT_APPMAP_DIR
|
237
239
|
@packages = packages
|
240
|
+
@swagger_config = swagger_config
|
238
241
|
@hook_paths = Set.new(packages.map(&:path))
|
239
242
|
@exclude = exclude
|
240
243
|
@builtin_hooks = BUILTIN_HOOKS
|
@@ -351,6 +354,11 @@ module AppMap
|
|
351
354
|
end
|
352
355
|
end
|
353
356
|
|
357
|
+
if config_data['swagger']
|
358
|
+
swagger_config = Swagger::Configuration.load(config_data['swagger'])
|
359
|
+
config_params[:swagger_config] = swagger_config
|
360
|
+
end
|
361
|
+
|
354
362
|
Config.new name, config_params
|
355
363
|
end
|
356
364
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'appmap/event'
|
4
|
+
require 'appmap/util'
|
4
5
|
|
5
6
|
module AppMap
|
6
7
|
module Handler
|
@@ -38,7 +39,7 @@ module AppMap
|
|
38
39
|
headers: headers
|
39
40
|
}.compact
|
40
41
|
|
41
|
-
unless
|
42
|
+
unless Util.blank?(params)
|
42
43
|
h[:message] = params.keys.map do |key|
|
43
44
|
val = params[key]
|
44
45
|
{
|
@@ -81,7 +82,7 @@ module AppMap
|
|
81
82
|
def request_headers(request)
|
82
83
|
{}.tap do |headers|
|
83
84
|
request.each_header do |k,v|
|
84
|
-
key = [ 'HTTP',
|
85
|
+
key = [ 'HTTP', Util.underscore(k).upcase ].join('_')
|
85
86
|
headers[key] = v
|
86
87
|
end
|
87
88
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'appmap/event'
|
4
4
|
require 'appmap/hook'
|
5
|
+
require 'appmap/util'
|
5
6
|
|
6
7
|
module AppMap
|
7
8
|
module Handler
|
@@ -40,7 +41,7 @@ module AppMap
|
|
40
41
|
headers: headers,
|
41
42
|
}.compact
|
42
43
|
|
43
|
-
unless
|
44
|
+
unless Util.blank?(params)
|
44
45
|
h[:message] = params.keys.map do |key|
|
45
46
|
val = params[key]
|
46
47
|
{
|
data/lib/appmap/hook.rb
CHANGED
data/lib/appmap/hook/method.rb
CHANGED
@@ -18,6 +18,8 @@ module AppMap
|
|
18
18
|
TIME_NOW = Time.method(:now)
|
19
19
|
private_constant :TIME_NOW
|
20
20
|
|
21
|
+
ARRAY_OF_EMPTY_HASH = [{}.freeze].freeze
|
22
|
+
|
21
23
|
def initialize(hook_package, hook_class, hook_method)
|
22
24
|
@hook_package = hook_package
|
23
25
|
@hook_class = hook_class
|
@@ -45,42 +47,48 @@ module AppMap
|
|
45
47
|
after_hook = self.method(:after_hook)
|
46
48
|
with_disabled_hook = self.method(:with_disabled_hook)
|
47
49
|
|
48
|
-
hook_method_def =
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
50
|
+
hook_method_def = Proc.new do |*args, &block|
|
51
|
+
instance_method = hook_method.bind(self).to_proc
|
52
|
+
call_instance_method = -> {
|
53
|
+
# https://github.com/applandinc/appmap-ruby/issues/153
|
54
|
+
if Util.ruby_minor_version >= 2.7 && args == ARRAY_OF_EMPTY_HASH && hook_method.arity == 1
|
55
|
+
instance_method.call({}, &block)
|
56
|
+
else
|
57
|
+
instance_method.call(*args, &block)
|
58
|
+
end
|
59
|
+
}
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
61
|
+
# We may not have gotten the class for the method during
|
62
|
+
# initialization (e.g. for a singleton method on an embedded
|
63
|
+
# struct), so make sure we have it now.
|
64
|
+
defined_class, = Hook.qualify_method_name(hook_method) unless defined_class
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
reentrant = Thread.current[HOOK_DISABLE_KEY]
|
67
|
+
disabled_by_shallow_flag = \
|
68
|
+
-> { hook_package&.shallow? && AppMap.tracing.last_package_for_current_thread == hook_package }
|
62
69
|
|
63
|
-
|
70
|
+
enabled = true if AppMap.tracing.enabled? && !reentrant && !disabled_by_shallow_flag.call
|
64
71
|
|
65
|
-
|
72
|
+
return call_instance_method.call unless enabled
|
66
73
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
74
|
+
call_event, start_time = with_disabled_hook.call do
|
75
|
+
before_hook.call(self, defined_class, args)
|
76
|
+
end
|
77
|
+
return_value = nil
|
78
|
+
exception = nil
|
79
|
+
begin
|
80
|
+
return_value = call_instance_method.call
|
81
|
+
rescue
|
82
|
+
exception = $ERROR_INFO
|
83
|
+
raise
|
84
|
+
ensure
|
85
|
+
with_disabled_hook.call do
|
86
|
+
after_hook.call(self, call_event, start_time, return_value, exception) if call_event
|
81
87
|
end
|
82
88
|
end
|
83
89
|
end
|
90
|
+
hook_method_def = hook_method_def.ruby2_keywords if hook_method_def.respond_to?(:ruby2_keywords)
|
91
|
+
|
84
92
|
hook_class.define_method_with_arity(hook_method.name, hook_method.arity, hook_method_def)
|
85
93
|
end
|
86
94
|
|
data/lib/appmap/metadata.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'appmap/util'
|
4
|
+
|
3
5
|
module AppMap
|
4
6
|
module Metadata
|
5
7
|
class << self
|
@@ -40,9 +42,9 @@ module AppMap
|
|
40
42
|
git_sha = `git rev-parse HEAD`.strip
|
41
43
|
git_status = `git status -s`.split("\n").map(&:strip)
|
42
44
|
git_last_annotated_tag = `git describe --abbrev=0 2>/dev/null`.strip
|
43
|
-
git_last_annotated_tag = nil if
|
45
|
+
git_last_annotated_tag = nil if Util.blank?(git_last_annotated_tag)
|
44
46
|
git_last_tag = `git describe --abbrev=0 --tags 2>/dev/null`.strip
|
45
|
-
git_last_tag = nil if
|
47
|
+
git_last_tag = nil if Util.blank?(git_last_tag)
|
46
48
|
git_commits_since_last_annotated_tag = `git describe`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_annotated_tag
|
47
49
|
git_commits_since_last_tag = `git describe --tags`.strip =~ /-(\d+)-(\w+)$/[1] rescue 0 if git_last_tag
|
48
50
|
|
data/lib/appmap/minitest.rb
CHANGED
data/lib/appmap/railtie.rb
CHANGED
@@ -5,8 +5,8 @@ module AppMap
|
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
6
|
initializer 'appmap.remote_recording' do
|
7
7
|
require 'appmap/middleware/remote_recording'
|
8
|
-
Rails.application.config.middleware.
|
9
|
-
|
8
|
+
Rails.application.config.middleware.insert_before \
|
9
|
+
ActionDispatch::Executor,
|
10
10
|
AppMap::Middleware::RemoteRecording
|
11
11
|
end
|
12
12
|
|
data/lib/appmap/rspec.rb
CHANGED
@@ -62,8 +62,10 @@ module AppMap
|
|
62
62
|
example_group_parent = \
|
63
63
|
if example_group.respond_to?(:module_parent)
|
64
64
|
example_group.module_parent
|
65
|
-
|
65
|
+
elsif example_group.respond_to?(:parent)
|
66
66
|
example_group.parent
|
67
|
+
elsif example_group.respond_to?(:parent_groups)
|
68
|
+
example_group.parent_groups.first
|
67
69
|
end
|
68
70
|
|
69
71
|
example_group_parent != example_group ? ScopeExampleGroup.new(example_group_parent) : nil
|
@@ -109,13 +111,13 @@ module AppMap
|
|
109
111
|
|
110
112
|
description = []
|
111
113
|
scope = ScopeExample.new(example)
|
112
|
-
|
113
114
|
while scope
|
114
115
|
description << scope.description
|
115
116
|
scope = scope.parent
|
116
117
|
end
|
117
118
|
|
118
|
-
description.reject!(&:nil?)
|
119
|
+
description.reject!(&:nil?)
|
120
|
+
description.reject!(&Util.method(:blank?))
|
119
121
|
default_description = description.last
|
120
122
|
description.reverse!
|
121
123
|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module AppMap
|
4
|
+
module Swagger
|
5
|
+
class Configuration
|
6
|
+
DEFAULT_VERSION = '1.0'
|
7
|
+
DEFAULT_OUTPUT_DIR = 'swagger'
|
8
|
+
DEFAULT_DESCRIPTION = 'Generate Swagger from AppMaps'
|
9
|
+
|
10
|
+
attr_accessor :project_version,
|
11
|
+
:output_dir,
|
12
|
+
:description
|
13
|
+
attr_writer :project_name, :template
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def load(config_data)
|
17
|
+
Configuration.new.tap do |config|
|
18
|
+
config_data.each do |k,v|
|
19
|
+
config.send "#{k}=", v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@project_name = nil
|
27
|
+
@project_version = DEFAULT_VERSION
|
28
|
+
@output_dir = DEFAULT_OUTPUT_DIR
|
29
|
+
@description = DEFAULT_DESCRIPTION
|
30
|
+
end
|
31
|
+
|
32
|
+
def project_name
|
33
|
+
@project_name || default_project_name
|
34
|
+
end
|
35
|
+
|
36
|
+
def template
|
37
|
+
@template || default_template
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_template
|
41
|
+
YAML.load <<~TEMPLATE
|
42
|
+
openapi: 3.0.1
|
43
|
+
info:
|
44
|
+
title: #{project_name}
|
45
|
+
version: #{project_version}
|
46
|
+
paths:
|
47
|
+
components:
|
48
|
+
servers:
|
49
|
+
- url: http://{defaultHost}
|
50
|
+
variables:
|
51
|
+
defaultHost:
|
52
|
+
default: localhost:3000
|
53
|
+
TEMPLATE
|
54
|
+
end
|
55
|
+
|
56
|
+
def default_project_name
|
57
|
+
# https://www.rubydoc.info/docs/rails/Module#module_parent_name-instance_method
|
58
|
+
module_parent_name = ->(cls) { cls.name =~ /::[^:]+\Z/ ? $`.freeze : nil }
|
59
|
+
|
60
|
+
# Lazy-evaluate this so that Rails.application will be defined.
|
61
|
+
# If this code runs too early in the lifecycle, Rails.application is nil.
|
62
|
+
if defined?(::Rails)
|
63
|
+
[module_parent_name.(::Rails.application.class).humanize.titleize, "API"].join(" ")
|
64
|
+
else
|
65
|
+
"MyProject API"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rdoc'
|
2
|
+
require 'reverse_markdown'
|
3
|
+
|
4
|
+
module AppMap
|
5
|
+
module Swagger
|
6
|
+
# Transform description fields into Markdown.
|
7
|
+
class MarkdownDescriptions
|
8
|
+
def initialize(swagger_yaml)
|
9
|
+
@swagger_yaml = swagger_yaml
|
10
|
+
end
|
11
|
+
|
12
|
+
def converter
|
13
|
+
method(:rdoc_to_markdown)
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform
|
17
|
+
to_markdown = lambda do |obj|
|
18
|
+
return obj.each(&to_markdown) if obj.is_a?(Array)
|
19
|
+
return unless obj.is_a?(Hash)
|
20
|
+
|
21
|
+
description = obj['description']
|
22
|
+
obj['description'] = converter.(description) if description
|
23
|
+
|
24
|
+
obj.reject { |k,v| k == 'properties' }.each_value(&to_markdown)
|
25
|
+
|
26
|
+
obj
|
27
|
+
end
|
28
|
+
|
29
|
+
to_markdown.(Util.deep_dup(@swagger_yaml))
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def rdoc_to_markdown(comment)
|
35
|
+
# Strip tags
|
36
|
+
comment = comment.split("\n").reject { |line| line =~ /^\s*@/ }.join("\n")
|
37
|
+
converter = ::RDoc::Markup::ToHtml.new(::RDoc::Options.new)
|
38
|
+
html = converter.convert(comment).strip
|
39
|
+
::ReverseMarkdown.convert(html).strip
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'yaml'
|
3
|
+
require 'appmap/node_cli'
|
4
|
+
require 'appmap/swagger/markdown_descriptions'
|
5
|
+
require 'appmap/swagger/stable'
|
6
|
+
|
7
|
+
module AppMap
|
8
|
+
module Swagger
|
9
|
+
module RakeTasks
|
10
|
+
extend self
|
11
|
+
extend Rake::DSL
|
12
|
+
|
13
|
+
def configuration
|
14
|
+
AppMap.configuration
|
15
|
+
end
|
16
|
+
|
17
|
+
def define_tasks
|
18
|
+
generate_swagger = lambda do |t, args|
|
19
|
+
appmap_js = AppMap::NodeCLI.new(verbose: Rake.verbose == true)
|
20
|
+
|
21
|
+
FileUtils.mkdir_p configuration.swagger_config.output_dir
|
22
|
+
|
23
|
+
cmd = %w[swagger]
|
24
|
+
|
25
|
+
swagger_raw, = appmap_js.command(cmd)
|
26
|
+
|
27
|
+
gen_swagger = YAML.load(swagger_raw)
|
28
|
+
gen_swagger_full = AppMap::Swagger::MarkdownDescriptions.new(gen_swagger).perform
|
29
|
+
gen_swagger_stable = AppMap::Swagger::Stable.new(gen_swagger).perform
|
30
|
+
|
31
|
+
swagger = configuration.swagger_config.template.merge(gen_swagger_full)
|
32
|
+
File.write File.join(configuration.swagger_config.output_dir, 'openapi.yaml'), YAML.dump(swagger)
|
33
|
+
|
34
|
+
swagger = configuration.swagger_config.template.merge(gen_swagger_stable)
|
35
|
+
File.write File.join(configuration.swagger_config.output_dir, 'openapi_stable.yaml'), YAML.dump(swagger)
|
36
|
+
end
|
37
|
+
|
38
|
+
desc configuration.swagger_config.description
|
39
|
+
task :swagger, &generate_swagger
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|