appmap 0.18.1 → 0.19.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 +6 -0
- data/README.md +77 -39
- data/lib/appmap/rspec.rb +47 -14
- data/lib/appmap/trace/tracer.rb +15 -6
- data/lib/appmap/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbd73ea1339788825987a09e80097ad54fcaf6297ae5a7bbe01aa39b5462a8bb
|
4
|
+
data.tar.gz: 6338cbb3203543ce4db169fef9cfcf31acfd6ea44da94220bca5c00638368520
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d0b9d851b266a230a40ac85e9991d183919c67b1c09e155009ffb3cd2de660e40521e6253534ae6a3e06867238810d6f5def1c9b10f094f81ed2498e79ee4ea
|
7
|
+
data.tar.gz: 4a6f75650e36876086782f778eb1fbb90f7d15a9e35eb28f245ce942285b3cfd95c76c16e5d01a5c90867455668609e974a41dfd829a6e7a91487833ebee49c9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# v0.19.0
|
2
|
+
|
3
|
+
* **RSpec** feature and feature group names can be inferred from example group and example names.
|
4
|
+
* Stop using `ActiveSupport::Inflector.transliterate`, since it can cause exceptions.
|
5
|
+
* Handle StandardError which occurs while calling `#inspect` of an object.
|
6
|
+
|
1
7
|
# v0.18.1
|
2
8
|
|
3
9
|
* Now tested with Rails 4, 5, and 6.
|
data/README.md
CHANGED
@@ -1,35 +1,54 @@
|
|
1
1
|
- [About](#about)
|
2
2
|
- [Installation](#installation)
|
3
3
|
- [Configuration](#configuration)
|
4
|
-
- [`packages`](#packages)
|
5
4
|
- [Running](#running)
|
6
5
|
- [RSpec](#rspec)
|
7
|
-
- [
|
8
|
-
- [Uploading](#uploading)
|
6
|
+
- [Remote recording](#remote-recording)
|
7
|
+
- [Uploading AppMaps](#uploading-appmaps)
|
9
8
|
- [Build status](#build-status)
|
10
9
|
|
11
10
|
# About
|
12
11
|
|
13
|
-
`appmap-ruby` is a Ruby
|
14
|
-
|
12
|
+
`appmap-ruby` is a Ruby Gem for recording and uploading
|
13
|
+
[AppMaps](https://github.com/applandinc/appmap) of your code.
|
15
14
|
AppMap is a data format which records code structure (modules, classes, and methods), code execution events
|
16
|
-
(function calls and returns), and code metadata (repo name, repo URL, commit
|
15
|
+
(function calls and returns), and code metadata (repo name, repo URL, commit
|
16
|
+
SHA, etc). It's more granular than a performance profile, but it's less
|
17
|
+
granular than a full debug trace. It's designed to be optimal for understanding the design intent and behavior of code.
|
18
|
+
|
19
|
+
There are several ways to record AppMaps of your Ruby program using the `appmap` gem:
|
17
20
|
|
18
|
-
|
19
|
-
|
21
|
+
* Run your RSpec tests. An AppMap will be generated for each one.
|
22
|
+
* Run your application server with AppMap remote recording enabled, and use the AppMap
|
23
|
+
browser extension to start, stop, and upload recordings.
|
20
24
|
|
21
|
-
|
22
|
-
|
25
|
+
When you record AppMaps on the command line (for example, by running RSpec tests), you use the `appmap upload` command to
|
26
|
+
upload them to the AppLand website. On the AppLand website, you'll be able to
|
27
|
+
visualize the design of your code and share links with collaborators.
|
23
28
|
|
24
29
|
# Installation
|
25
30
|
|
26
|
-
Add `gem 'appmap'` to your Gemfile just as you would any other dependency.
|
31
|
+
Add `gem 'appmap'` to your Gemfile just as you would any other dependency.
|
32
|
+
|
33
|
+
**Global installation**
|
34
|
+
|
35
|
+
```
|
36
|
+
gem 'appmap'
|
37
|
+
```
|
38
|
+
|
39
|
+
**Install in test, development groups**
|
40
|
+
|
41
|
+
```
|
42
|
+
group :development, :test do
|
43
|
+
gem 'appmap'
|
44
|
+
end
|
45
|
+
```
|
27
46
|
|
28
47
|
Then install with `bundle`.
|
29
48
|
|
30
49
|
# Configuration
|
31
50
|
|
32
|
-
When you run
|
51
|
+
When you run your program, the `appmap` gem reads configuration settings from `appmap.yml`. Here's a sample configuration
|
33
52
|
file for a typical Rails project:
|
34
53
|
|
35
54
|
```yaml
|
@@ -44,7 +63,7 @@ packages:
|
|
44
63
|
* **files** A list of individual files which should be instrumented. This is only used for files which are
|
45
64
|
not part of the `packages` list.
|
46
65
|
|
47
|
-
|
66
|
+
**packages**
|
48
67
|
|
49
68
|
Each entry in the `packages` list is a YAML object which has the following keys:
|
50
69
|
|
@@ -61,71 +80,90 @@ Each entry in the `packages` list is a YAML object which has the following keys:
|
|
61
80
|
|
62
81
|
To instrument RSpec tests, follow these steps:
|
63
82
|
|
64
|
-
1) Include the `appmap` gem in your Gemfile
|
65
|
-
2) Require `appmap/rspec` in your `spec_helper.rb
|
66
|
-
3) Add `appmap: true` to the tests you want to instrument
|
67
|
-
4)
|
83
|
+
1) Include the `appmap` gem in your Gemfile.
|
84
|
+
2) Require `appmap/rspec` in your `spec_helper.rb`.
|
85
|
+
3) Add `appmap: true` to the tests you want to instrument.
|
86
|
+
4) Export the environment variable `APPMAP=true`.
|
87
|
+
5) *Optional* Add `feature: '<feature name>'` and `feature_group: '<feature group name>'` annotations to your
|
68
88
|
examples.
|
69
|
-
5) Export the environment variable `APPMAP=true`
|
70
89
|
|
71
90
|
Here's an example of an appmap-enabled RSpec test:
|
72
91
|
|
73
92
|
```ruby
|
74
|
-
describe Hello,
|
75
|
-
|
76
|
-
|
93
|
+
describe Hello, appmap: true do
|
94
|
+
describe 'says hello' do
|
95
|
+
it 'when prompted' do
|
96
|
+
expect(Hello.new.say_hello).to eq('Hello!')
|
97
|
+
end
|
77
98
|
end
|
78
99
|
end
|
79
100
|
```
|
80
101
|
|
81
|
-
|
102
|
+
Run the tests like this:
|
82
103
|
|
83
104
|
```sh-session
|
84
|
-
$ APPMAP=true bundle exec rspec
|
105
|
+
$ APPMAP=true bundle exec rspec -t appmap
|
85
106
|
```
|
86
107
|
|
87
108
|
Each RSpec test will output a data file into the directory `tmp/appmap/rspec`. For example:
|
88
109
|
|
89
110
|
```
|
90
111
|
$ find tmp/appmap/rspec
|
91
|
-
|
112
|
+
Hello_says_hello_when_prompted.appmap.json
|
92
113
|
```
|
93
114
|
|
94
115
|
If you include the `feature` and `feature_group` metadata, these attributes will be exported to the AppMap file in the
|
95
116
|
`metadata` section. It will look something like this:
|
96
117
|
|
97
118
|
```json
|
98
|
-
|
119
|
+
{
|
120
|
+
...
|
121
|
+
"metadata": {
|
122
|
+
"name": "Hello app says hello when prompted",
|
123
|
+
"feature": "Hello app says hello",
|
124
|
+
"feature_group": "Hello"
|
125
|
+
},
|
126
|
+
...
|
127
|
+
}
|
99
128
|
```
|
100
129
|
|
101
|
-
##
|
130
|
+
## Remote recording
|
102
131
|
|
103
|
-
To
|
132
|
+
To manually record ad-hoc AppMaps of your Ruby app, use AppMap remote recording.
|
104
133
|
|
105
|
-
1
|
134
|
+
1. Add the AppMap remote recording middleware. For example, in `config/initializers/appmap_remote_recording.rb`:
|
106
135
|
|
107
136
|
```ruby
|
108
|
-
|
137
|
+
require 'appmap/middleware/remote_recording'
|
138
|
+
|
139
|
+
unless Rails.env.test?
|
140
|
+
Rails.application.config.middleware.insert_after \
|
141
|
+
Rails::Rack::Logger,
|
142
|
+
AppMap::Middleware::RemoteRecording
|
143
|
+
end
|
109
144
|
```
|
110
145
|
|
111
|
-
2
|
146
|
+
2. Start your Rails application server. For example:
|
112
147
|
|
113
148
|
```sh-session
|
114
|
-
$
|
149
|
+
$ bundle exec rails server
|
115
150
|
```
|
116
151
|
|
117
|
-
|
118
|
-
|
152
|
+
3. Open the AppApp browser extension and push `Start`.
|
153
|
+
|
154
|
+
4. Use your app. For example, perform a login flow, or run through a manual UI test.
|
155
|
+
|
156
|
+
5. Open the AppApp browser extension and push `Stop`. The recording will be transferred to the AppLand website and opened in your browser.
|
119
157
|
|
120
|
-
# Uploading
|
158
|
+
# Uploading AppMaps
|
121
159
|
|
122
|
-
To upload an AppMap file to
|
160
|
+
To upload an AppMap file to AppLand, run the `appmap upload` command. For example:
|
123
161
|
|
124
162
|
```sh-session
|
125
|
-
$ appmap upload tmp/appmap/rspec/
|
126
|
-
|
127
|
-
|
128
|
-
|
163
|
+
$ appmap upload tmp/appmap/rspec/Hello_app_says_hello_when_prompted.appmap.json
|
164
|
+
Uploading "tmp/appmap/rspec/Hello_app_says_hello_when_prompted.appmap.json"
|
165
|
+
Scenario Id: 4da4f267-bdea-48e8-bf67-f39463844230
|
166
|
+
Batch Id: a116f1df-ee57-4bde-8eef-851af0f3d7bc
|
129
167
|
```
|
130
168
|
|
131
169
|
# Build status
|
data/lib/appmap/rspec.rb
CHANGED
@@ -29,14 +29,14 @@ module AppMap
|
|
29
29
|
FileUtils.mkdir_p APPMAP_OUTPUT_DIR
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
def save(example_name, events, feature_name: nil, feature_group_name: nil)
|
32
|
+
def save(example_name, events, feature_name: nil, feature_group_name: nil, labels: nil)
|
34
33
|
require 'appmap/command/record'
|
35
34
|
metadata = AppMap::Command::Record.detect_metadata.tap do |m|
|
36
35
|
m[:name] = example_name
|
37
36
|
m[:app] = @config.name
|
38
37
|
m[:feature] = feature_name if feature_name
|
39
38
|
m[:feature_group] = feature_group_name if feature_group_name
|
39
|
+
m[:labels] = labels if labels
|
40
40
|
m[:frameworks] ||= []
|
41
41
|
m[:frameworks] << {
|
42
42
|
name: 'rspec',
|
@@ -58,7 +58,7 @@ module AppMap
|
|
58
58
|
# https://github.com/rails/rails/blob/v5.2.4/activesupport/lib/active_support/inflector/transliterate.rb#L92
|
59
59
|
def sanitize_filename(fname, separator: '_')
|
60
60
|
# Replace accented chars with their ASCII equivalents.
|
61
|
-
fname =
|
61
|
+
fname = fname.encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
62
62
|
|
63
63
|
# Turn unwanted chars into the separator.
|
64
64
|
fname.gsub!(/[^a-z0-9\-_]+/i, separator)
|
@@ -83,6 +83,17 @@ module AppMap
|
|
83
83
|
annotations[:feature]
|
84
84
|
end
|
85
85
|
|
86
|
+
def labels
|
87
|
+
labels = metadata[:appmap]
|
88
|
+
if labels.is_a?(Array)
|
89
|
+
labels
|
90
|
+
elsif labels.is_a?(String) || labels.is_a?(Symbol)
|
91
|
+
[ labels ]
|
92
|
+
else
|
93
|
+
[]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
86
97
|
def feature_group
|
87
98
|
return nil unless annotations
|
88
99
|
|
@@ -119,6 +130,10 @@ module AppMap
|
|
119
130
|
|
120
131
|
alias_method :example_obj, :example
|
121
132
|
|
133
|
+
def description?
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
122
137
|
def description
|
123
138
|
example.description
|
124
139
|
end
|
@@ -255,28 +270,46 @@ module AppMap
|
|
255
270
|
|
256
271
|
example = examples[loc]
|
257
272
|
description = []
|
258
|
-
scope = ScopeExample.new(example)
|
273
|
+
leaf = scope = ScopeExample.new(example)
|
259
274
|
feature_group = feature = nil
|
275
|
+
labels = scope.labels.map(&:to_s).map(&:strip).reject(&:blank?).map(&:downcase).uniq
|
276
|
+
|
260
277
|
while scope
|
261
278
|
description << scope.description
|
262
279
|
feature ||= scope.feature
|
263
280
|
feature_group ||= scope.feature_group
|
264
281
|
scope = scope.parent
|
265
282
|
end
|
266
|
-
description.reject!
|
283
|
+
description.reject!(&:nil?).reject(&:blank?)
|
284
|
+
default_description = description.last
|
267
285
|
description.reverse!
|
268
286
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
287
|
+
normalize = lambda do |desc|
|
288
|
+
desc.gsub('it should behave like', '')
|
289
|
+
.gsub(/Controller$/, '')
|
290
|
+
.gsub(/\s+/, ' ')
|
291
|
+
.strip
|
292
|
+
end
|
293
|
+
|
294
|
+
full_description = normalize.call(description.join(' '))
|
295
|
+
|
296
|
+
compute_feature_name = lambda do
|
297
|
+
return 'unknown' if description.empty?
|
298
|
+
|
299
|
+
feature_description = description.dup
|
300
|
+
num_tokens = [2, feature_description.length - 1].min
|
301
|
+
feature_description[0...num_tokens].map(&:strip).join(' ')
|
274
302
|
end
|
275
|
-
full_description = description.join(' ')
|
276
303
|
|
277
|
-
|
278
|
-
|
279
|
-
|
304
|
+
feature_group ||= normalize.call(default_description).underscore.gsub('/', '_').humanize
|
305
|
+
feature_name = feature || compute_feature_name.call if feature_group
|
306
|
+
feature_name = normalize.call(feature_name) if feature_name
|
307
|
+
|
308
|
+
recorder.save full_description,
|
309
|
+
events,
|
310
|
+
feature_name: feature_name,
|
311
|
+
feature_group_name: feature_group,
|
312
|
+
labels: labels.blank? ? nil : labels
|
280
313
|
end
|
281
314
|
end
|
282
315
|
end
|
data/lib/appmap/trace/tracer.rb
CHANGED
@@ -87,15 +87,24 @@ module AppMap
|
|
87
87
|
def display_string(value)
|
88
88
|
return nil unless value
|
89
89
|
|
90
|
-
|
91
|
-
|
92
|
-
rescue NoMethodError
|
93
|
-
value_string = value.inspect
|
94
|
-
rescue StandardError
|
95
|
-
warn $!.message
|
90
|
+
last_resort_string = lambda do
|
91
|
+
warn "AppMap encountered an error inspecting a #{value.class.name}: #{$!.message}"
|
96
92
|
'*Error inspecting variable*'
|
97
93
|
end
|
98
94
|
|
95
|
+
value_string = \
|
96
|
+
begin
|
97
|
+
value.to_s
|
98
|
+
rescue NoMethodError
|
99
|
+
begin
|
100
|
+
value.inspect
|
101
|
+
rescue StandardError
|
102
|
+
last_resort_string.call
|
103
|
+
end
|
104
|
+
rescue StandardError
|
105
|
+
last_resort_string.call
|
106
|
+
end
|
107
|
+
|
99
108
|
value_string[0...LIMIT].encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
|
100
109
|
end
|
101
110
|
end
|
data/lib/appmap/version.rb
CHANGED