appmap 0.50.0 → 0.51.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/appmap.rb +12 -5
- data/lib/appmap/config.rb +113 -28
- data/lib/appmap/util.rb +21 -0
- data/lib/appmap/version.rb +3 -1
- data/spec/abstract_controller_base_spec.rb +57 -18
- data/spec/config_spec.rb +21 -0
- data/spec/hook_spec.rb +2 -2
- data/spec/record_net_http_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbe39a5de48eb36889755224aa85f8d1bee3af0c75a9eb00a28dd8bdc92cc5c0
|
4
|
+
data.tar.gz: 284eae1f685e7fe5f8d897f96027683119fc26d64de03e7be108341fff8783f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a50f7cf525571c964bff72d7da580f9a38cc6eba0f31e03a592cd5cd4b1321cba70a0d3e0e8b4fb22da6bf9e4d50cbc3f5b3d346b52cc8e6749626b71197b8fa
|
7
|
+
data.tar.gz: 7850f7fabe85ea64d1e97f841a1cbd3b944005b7959cd4e75ddca0cc7788bcad7640420ee3b12003387399c332a95d0c90550caa2a0ce065d463f33f0fd416e3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# [0.51.0](https://github.com/applandinc/appmap-ruby/compare/v0.50.0...v0.51.0) (2021-06-21)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* Provide default appmap.yml settings ([7fa8159](https://github.com/applandinc/appmap-ruby/commit/7fa8159b5020e35f13379017b44906d671e62e64))
|
7
|
+
|
1
8
|
# [0.50.0](https://github.com/applandinc/appmap-ruby/compare/v0.49.0...v0.50.0) (2021-06-17)
|
2
9
|
|
3
10
|
|
data/lib/appmap.rb
CHANGED
@@ -27,7 +27,7 @@ module AppMap
|
|
27
27
|
# Gets the configuration. If there is no configuration, the default
|
28
28
|
# configuration is initialized.
|
29
29
|
def configuration
|
30
|
-
@configuration ||=
|
30
|
+
@configuration ||= initialize_configuration
|
31
31
|
end
|
32
32
|
|
33
33
|
# Sets the configuration. This is only expected to happen once per
|
@@ -38,12 +38,19 @@ module AppMap
|
|
38
38
|
@configuration = config
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
def default_config_file_path
|
42
|
+
ENV['APPMAP_CONFIG_FILE'] || 'appmap.yml'
|
43
|
+
end
|
44
|
+
|
45
|
+
# Configures AppMap for recording. Default behavior is to configure from
|
46
|
+
# APPMAP_CONFIG_FILE, or 'appmap.yml'. If no config file is available, a
|
47
|
+
# configuration will be automatically generated and used - and the user is prompted
|
48
|
+
# to create the config file.
|
49
|
+
#
|
42
50
|
# This method also activates the code hooks which record function calls as trace events.
|
43
51
|
# Call this function before the program code is loaded by the Ruby VM, otherwise
|
44
52
|
# the load events won't be seen and the hooks won't activate.
|
45
|
-
def
|
46
|
-
raise "AppMap configuration file #{config_file_path} does not exist" unless ::File.exists?(config_file_path)
|
53
|
+
def initialize_configuration(config_file_path = default_config_file_path)
|
47
54
|
warn "Configuring AppMap from path #{config_file_path}"
|
48
55
|
Config.load_from_file(config_file_path).tap do |configuration|
|
49
56
|
self.configuration = configuration
|
@@ -118,4 +125,4 @@ if Gem.loaded_specs['minitest']
|
|
118
125
|
require 'appmap/minitest'
|
119
126
|
end
|
120
127
|
|
121
|
-
AppMap.
|
128
|
+
AppMap.initialize_configuration if ENV['APPMAP'] == 'true'
|
data/lib/appmap/config.rb
CHANGED
@@ -223,10 +223,14 @@ module AppMap
|
|
223
223
|
'JSON::Ext::Generator::State' => TargetMethods.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json.generate])),
|
224
224
|
}.freeze
|
225
225
|
|
226
|
-
attr_reader :name, :packages, :exclude, :hooked_methods, :builtin_hooks
|
226
|
+
attr_reader :name, :appmap_dir, :packages, :exclude, :hooked_methods, :builtin_hooks
|
227
227
|
|
228
|
-
def initialize(name,
|
228
|
+
def initialize(name,
|
229
|
+
packages: [],
|
230
|
+
exclude: [],
|
231
|
+
functions: [])
|
229
232
|
@name = name
|
233
|
+
@appmap_dir = AppMap::DEFAULT_APPMAP_DIR
|
230
234
|
@packages = packages
|
231
235
|
@hook_paths = Set.new(packages.map(&:path))
|
232
236
|
@exclude = exclude
|
@@ -253,38 +257,119 @@ module AppMap
|
|
253
257
|
class << self
|
254
258
|
# Loads configuration data from a file, specified by the file name.
|
255
259
|
def load_from_file(config_file_name)
|
256
|
-
|
257
|
-
|
260
|
+
logo = lambda do
|
261
|
+
Util.color(<<~LOGO, :magenta)
|
262
|
+
___ __ ___
|
263
|
+
/ _ | ___ ___ / |/ /__ ____
|
264
|
+
/ __ |/ _ \\/ _ \\/ /|_/ / _ `/ _ \\
|
265
|
+
/_/ |_/ .__/ .__/_/ /_/\\_,_/ .__/
|
266
|
+
/_/ /_/ /_/
|
267
|
+
LOGO
|
268
|
+
end
|
269
|
+
|
270
|
+
config_present = true if File.exists?(config_file_name)
|
271
|
+
|
272
|
+
config_data = if config_present
|
273
|
+
require 'yaml'
|
274
|
+
YAML.safe_load(::File.read(config_file_name))
|
275
|
+
else
|
276
|
+
warn logo.()
|
277
|
+
warn ''
|
278
|
+
warn Util.color(%Q|NOTICE: The AppMap config file #{config_file_name} was not found!|, :magenta, bold: true)
|
279
|
+
warn ''
|
280
|
+
warn Util.color(<<~MISSING_FILE_MSG, :magenta)
|
281
|
+
AppMap uses this file to customize its behavior. For example, you can use
|
282
|
+
the 'packages' setting to indicate which local file paths and dependency
|
283
|
+
gems you want to include in the AppMap. Since you haven't provided specific
|
284
|
+
settings, the appmap gem will try and guess some reasonable defaults.
|
285
|
+
To suppress this message, create the file:
|
286
|
+
|
287
|
+
#{Pathname.new(config_file_name).expand_path}.
|
288
|
+
|
289
|
+
Here are the default settings that will be used in the meantime. You can
|
290
|
+
copy and paste this example to start your appmap.yml.
|
291
|
+
MISSING_FILE_MSG
|
292
|
+
{}
|
293
|
+
end
|
294
|
+
load(config_data).tap do |config|
|
295
|
+
config_yaml = {
|
296
|
+
'name' => config.name,
|
297
|
+
'packages' => config.packages.select{|p| p.path}.map do |pkg|
|
298
|
+
{ 'path' => pkg.path }
|
299
|
+
end,
|
300
|
+
'exclude' => []
|
301
|
+
}.compact
|
302
|
+
unless config_present
|
303
|
+
warn Util.color(YAML.dump(config_yaml), :magenta)
|
304
|
+
warn logo.()
|
305
|
+
end
|
306
|
+
end
|
258
307
|
end
|
259
308
|
|
260
309
|
# Loads configuration from a Hash.
|
261
310
|
def load(config_data)
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
311
|
+
name = config_data['name'] || guess_name
|
312
|
+
config_params = {
|
313
|
+
exclude: config_data['exclude']
|
314
|
+
}.compact
|
315
|
+
|
316
|
+
if config_data['functions']
|
317
|
+
config_params[:functions] = config_data['functions'].map do |function_data|
|
318
|
+
package = function_data['package']
|
319
|
+
cls = function_data['class']
|
320
|
+
functions = function_data['function'] || function_data['functions']
|
321
|
+
raise %q(AppMap config 'function' element should specify 'package', 'class' and 'function' or 'functions') unless package && cls && functions
|
322
|
+
|
323
|
+
functions = Array(functions).map(&:to_sym)
|
324
|
+
labels = function_data['label'] || function_data['labels']
|
325
|
+
labels = Array(labels).map(&:to_s) if labels
|
326
|
+
Function.new(package, cls, labels, functions)
|
327
|
+
end
|
271
328
|
end
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
329
|
+
|
330
|
+
config_params[:packages] = \
|
331
|
+
if config_data['packages']
|
332
|
+
config_data['packages'].map do |package|
|
333
|
+
gem = package['gem']
|
334
|
+
path = package['path']
|
335
|
+
raise %q(AppMap config 'package' element should specify 'gem' or 'path', not both) if gem && path
|
336
|
+
|
337
|
+
if gem
|
338
|
+
shallow = package['shallow']
|
339
|
+
# shallow is true by default for gems
|
340
|
+
shallow = true if shallow.nil?
|
341
|
+
Package.build_from_gem(gem, exclude: package['exclude'] || [], shallow: shallow)
|
342
|
+
else
|
343
|
+
Package.build_from_path(path, exclude: package['exclude'] || [], shallow: package['shallow'])
|
344
|
+
end
|
345
|
+
end.compact
|
282
346
|
else
|
283
|
-
|
347
|
+
Array(guess_paths).map do |path|
|
348
|
+
Package.build_from_path(path)
|
349
|
+
end
|
284
350
|
end
|
285
|
-
|
286
|
-
|
287
|
-
|
351
|
+
|
352
|
+
Config.new name, config_params
|
353
|
+
end
|
354
|
+
|
355
|
+
def guess_name
|
356
|
+
reponame = lambda do
|
357
|
+
next unless File.directory?('.git')
|
358
|
+
|
359
|
+
repo_name = `git config --get remote.origin.url`.strip
|
360
|
+
repo_name.split('/').last.split('.').first unless repo_name == ''
|
361
|
+
end
|
362
|
+
dirname = -> { Dir.pwd.split('/').last }
|
363
|
+
|
364
|
+
reponame.() || dirname.()
|
365
|
+
end
|
366
|
+
|
367
|
+
def guess_paths
|
368
|
+
if defined?(::Rails)
|
369
|
+
%w[app/controllers app/models]
|
370
|
+
elsif File.directory?('lib')
|
371
|
+
%w[lib]
|
372
|
+
end
|
288
373
|
end
|
289
374
|
end
|
290
375
|
|
@@ -294,7 +379,7 @@ module AppMap
|
|
294
379
|
packages: packages.map(&:to_h),
|
295
380
|
functions: @functions.map(&:to_h),
|
296
381
|
exclude: exclude
|
297
|
-
}
|
382
|
+
}.compact
|
298
383
|
end
|
299
384
|
|
300
385
|
# Determines if methods defined in a file path should possibly be hooked.
|
data/lib/appmap/util.rb
CHANGED
@@ -4,6 +4,21 @@ require 'bundler'
|
|
4
4
|
|
5
5
|
module AppMap
|
6
6
|
module Util
|
7
|
+
# https://wynnnetherland.com/journal/a-stylesheet-author-s-guide-to-terminal-colors/
|
8
|
+
# Embed in a String to clear all previous ANSI sequences.
|
9
|
+
CLEAR = "\e[0m"
|
10
|
+
BOLD = "\e[1m"
|
11
|
+
|
12
|
+
# Colors
|
13
|
+
BLACK = "\e[30m"
|
14
|
+
RED = "\e[31m"
|
15
|
+
GREEN = "\e[32m"
|
16
|
+
YELLOW = "\e[33m"
|
17
|
+
BLUE = "\e[34m"
|
18
|
+
MAGENTA = "\e[35m"
|
19
|
+
CYAN = "\e[36m"
|
20
|
+
WHITE = "\e[37m"
|
21
|
+
|
7
22
|
class << self
|
8
23
|
# scenario_filename builds a suitable file name from a scenario name.
|
9
24
|
# Special characters are removed, and the file name is truncated to fit within
|
@@ -128,6 +143,12 @@ module AppMap
|
|
128
143
|
FileUtils.mv tempfile.path, filename
|
129
144
|
end
|
130
145
|
end
|
146
|
+
|
147
|
+
def color(text, color, bold: false)
|
148
|
+
color = Util.const_get(color.to_s.upcase) if color.is_a?(Symbol)
|
149
|
+
bold = bold ? BOLD : ""
|
150
|
+
"#{bold}#{color}#{text}#{CLEAR}"
|
151
|
+
end
|
131
152
|
end
|
132
153
|
end
|
133
154
|
end
|
data/lib/appmap/version.rb
CHANGED
@@ -1,9 +1,30 @@
|
|
1
1
|
require 'rails_spec_helper'
|
2
2
|
|
3
3
|
describe 'Rails' do
|
4
|
+
shared_context 'rails integration test setup' do
|
5
|
+
def tmpdir
|
6
|
+
'tmp/spec/AbstractControllerBase'
|
7
|
+
end
|
8
|
+
|
9
|
+
unless use_existing_data?
|
10
|
+
before(:all) do
|
11
|
+
FileUtils.rm_rf tmpdir
|
12
|
+
FileUtils.mkdir_p tmpdir
|
13
|
+
run_spec 'spec/controllers/users_controller_spec.rb'
|
14
|
+
run_spec 'spec/controllers/users_controller_api_spec.rb'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:appmap) { JSON.parse File.read File.join tmpdir, 'appmap/rspec', appmap_json_file }
|
19
|
+
let(:appmap_json_path) { File.join(tmpdir, 'appmap/rspec', appmap_json_file) }
|
20
|
+
let(:appmap) { JSON.parse File.read(appmap_json_path) }
|
21
|
+
let(:events) { appmap['events'] }
|
22
|
+
end
|
23
|
+
|
4
24
|
%w[5 6].each do |rails_major_version| # rubocop:disable Metrics/BlockLength
|
5
25
|
context "#{rails_major_version}" do
|
6
26
|
include_context 'Rails app pg database', "spec/fixtures/rails#{rails_major_version}_users_app" unless use_existing_data?
|
27
|
+
include_context 'rails integration test setup'
|
7
28
|
|
8
29
|
def run_spec(spec_name)
|
9
30
|
cmd = <<~CMD.gsub "\n", ' '
|
@@ -13,24 +34,6 @@ describe 'Rails' do
|
|
13
34
|
run_cmd cmd, chdir: fixture_dir
|
14
35
|
end
|
15
36
|
|
16
|
-
def tmpdir
|
17
|
-
'tmp/spec/AbstractControllerBase'
|
18
|
-
end
|
19
|
-
|
20
|
-
unless use_existing_data?
|
21
|
-
before(:all) do
|
22
|
-
FileUtils.rm_rf tmpdir
|
23
|
-
FileUtils.mkdir_p tmpdir
|
24
|
-
run_spec 'spec/controllers/users_controller_spec.rb'
|
25
|
-
run_spec 'spec/controllers/users_controller_api_spec.rb'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
let(:appmap) { JSON.parse File.read File.join tmpdir, 'appmap/rspec', appmap_json_file }
|
30
|
-
let(:appmap_json_path) { File.join(tmpdir, 'appmap/rspec', appmap_json_file) }
|
31
|
-
let(:appmap) { JSON.parse File.read(appmap_json_path) }
|
32
|
-
let(:events) { appmap['events'] }
|
33
|
-
|
34
37
|
describe 'an API route' do
|
35
38
|
describe 'creating an object' do
|
36
39
|
let(:appmap_json_file) do
|
@@ -253,4 +256,40 @@ describe 'Rails' do
|
|
253
256
|
end
|
254
257
|
end
|
255
258
|
end
|
259
|
+
|
260
|
+
describe 'with default appmap.yml' do
|
261
|
+
include_context 'Rails app pg database', "spec/fixtures/rails5_users_app" unless use_existing_data?
|
262
|
+
include_context 'rails integration test setup'
|
263
|
+
|
264
|
+
def run_spec(spec_name)
|
265
|
+
cmd = <<~CMD.gsub "\n", ' '
|
266
|
+
docker-compose run --rm -e RAILS_ENV=test -e APPMAP=true -e APPMAP_CONFIG_FILE=no/such/file
|
267
|
+
-v #{File.absolute_path tmpdir}:/app/tmp app ./bin/rspec #{spec_name}
|
268
|
+
CMD
|
269
|
+
run_cmd cmd, chdir: fixture_dir
|
270
|
+
end
|
271
|
+
|
272
|
+
let(:appmap_json_file) do
|
273
|
+
'Api_UsersController_POST_api_users_with_required_parameters_creates_a_user.appmap.json'
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'http_server_request is recorded' do
|
277
|
+
expect(events).to include(
|
278
|
+
hash_including(
|
279
|
+
'http_server_request' => hash_including(
|
280
|
+
'request_method' => 'POST',
|
281
|
+
'path_info' => '/api/users'
|
282
|
+
)
|
283
|
+
)
|
284
|
+
)
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'controller method is recorded' do
|
288
|
+
expect(events).to include hash_including(
|
289
|
+
'defined_class' => 'Api::UsersController',
|
290
|
+
'method_id' => 'build_user',
|
291
|
+
'path' => 'app/controllers/api/users_controller.rb',
|
292
|
+
)
|
293
|
+
end
|
294
|
+
end
|
256
295
|
end
|
data/spec/config_spec.rb
CHANGED
@@ -55,4 +55,25 @@ describe AppMap::Config, docker: false do
|
|
55
55
|
|
56
56
|
expect(config.to_h.deep_stringify_keys!).to eq(config_expectation)
|
57
57
|
end
|
58
|
+
|
59
|
+
context do
|
60
|
+
let(:warnings) { @warnings ||= [] }
|
61
|
+
let(:warning) { warnings.join }
|
62
|
+
before do
|
63
|
+
expect(AppMap::Config).to receive(:warn).at_least(1) { |msg| warnings << msg }
|
64
|
+
end
|
65
|
+
it 'prints a warning and uses a default config' do
|
66
|
+
config = AppMap::Config.load_from_file 'no/such/file'
|
67
|
+
expect(config.to_h).to eq(YAML.load(<<~CONFIG))
|
68
|
+
:name: appmap-ruby
|
69
|
+
:packages:
|
70
|
+
- :path: lib
|
71
|
+
:handler_class: AppMap::Handler::Function
|
72
|
+
:shallow: false
|
73
|
+
:functions: []
|
74
|
+
:exclude: []
|
75
|
+
CONFIG
|
76
|
+
expect(warning).to include('NOTICE: The AppMap config file no/such/file was not found!')
|
77
|
+
end
|
78
|
+
end
|
58
79
|
end
|
data/spec/hook_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
21
21
|
def invoke_test_file(file, setup: nil, &block)
|
22
22
|
AppMap.configuration = nil
|
23
23
|
package = AppMap::Config::Package.build_from_path(file)
|
24
|
-
config = AppMap::Config.new('hook_spec', [ package ])
|
24
|
+
config = AppMap::Config.new('hook_spec', packages: [ package ])
|
25
25
|
AppMap.configuration = config
|
26
26
|
tracer = nil
|
27
27
|
AppMap::Hook.new(config).enable do
|
@@ -57,7 +57,7 @@ describe 'AppMap class Hooking', docker: false do
|
|
57
57
|
it 'excludes named classes and methods' do
|
58
58
|
load 'spec/fixtures/hook/exclude.rb'
|
59
59
|
package = AppMap::Config::Package.build_from_path('spec/fixtures/hook/exclude.rb')
|
60
|
-
config = AppMap::Config.new('hook_spec', [ package ], exclude: %w[ExcludeTest])
|
60
|
+
config = AppMap::Config.new('hook_spec', packages: [ package ], exclude: %w[ExcludeTest])
|
61
61
|
AppMap.configuration = config
|
62
62
|
|
63
63
|
expect(config.never_hook?(ExcludeTest, ExcludeTest.new.method(:instance_method))).to be_truthy
|
@@ -62,7 +62,7 @@ describe 'Net::HTTP handler' do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
context 'with trace enabled' do
|
65
|
-
let(:configuration) { AppMap::Config.new('record_net_http_spec'
|
65
|
+
let(:configuration) { AppMap::Config.new('record_net_http_spec') }
|
66
66
|
|
67
67
|
after do
|
68
68
|
AppMap.configuration = nil
|
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.51.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Gilpin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|