appmap 0.50.0 → 0.51.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 +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
|