appmap 0.18.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 536929649e77a1a136aabc2ffbf8df4b43a1f51420334b4d556f5978aa205e06
4
- data.tar.gz: b052fa2b3853f962932216a21f2c0d07052e7288695787bc60fccba4ed97cf1f
3
+ metadata.gz: dbd73ea1339788825987a09e80097ad54fcaf6297ae5a7bbe01aa39b5462a8bb
4
+ data.tar.gz: 6338cbb3203543ce4db169fef9cfcf31acfd6ea44da94220bca5c00638368520
5
5
  SHA512:
6
- metadata.gz: fca12acdd2d3a096cc1ecb8bb8d5e19fb5f88ad91e67de83aa71d59e9cdaa0a70733d1904e4d29078ea94eddbc3005d1cb33ea4e86f0fad95270ec7b3bd35e67
7
- data.tar.gz: 395891a44f2d185bcb5bd447bbe39d1d16a07c30c065c6fb7a45ea5979f54f7c1b30efab1baf6043838a9e9d166e1f14ff4412b9a04743d03c8a818a4c082b15
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
- - [Rails](#rails)
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 client for recording and uploading [AppMap](https://github.com/applandinc/appmap) data.
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 SHA, etc).
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
- The normal usage of an AppMap client is to run a test case (such as an RSpec test) with AppMap instrumentation enabled.
19
- The AppMap client will observe and record information about the code execution, and store it in an AppMap file.
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
- The command `appmap upload` is then used to upload the AppMap file to the App.Land server, which processes the file into
22
- useful displays such as graphical depiction of the code structure and execution.
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. You can place the gem in the `test` group.
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 the AppMap client, it will look for configuration settings in `appmap.yml`. Here's a sample configuration
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
- ## `packages`
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` or `rails_helper.rb`
66
- 3) Add `appmap: true` to the tests you want to instrument
67
- 4) Add `feature: '<feature name>'` and `feature_group: '<feature group name>'` to your
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, feature_group: 'Greeting' do
75
- it 'says hello', feature: 'Print a greeting to the console', appmap: true do
76
- expect(Hello.new.say_hello).to eq('Hello!')
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
- Then run the tests:
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
- Hello says hello.json
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
- ## Rails
130
+ ## Remote recording
102
131
 
103
- To capture ad-hoc AppMaps of your Rails app, use the AppMap Railtie.
132
+ To manually record ad-hoc AppMaps of your Ruby app, use AppMap remote recording.
104
133
 
105
- 1) Include the `appmap` gem in your Gemfile and require both `appmap` and `appmap/railtie`, like this:
134
+ 1. Add the AppMap remote recording middleware. For example, in `config/initializers/appmap_remote_recording.rb`:
106
135
 
107
136
  ```ruby
108
- gem "appmap", require: %w[appmap appmap/railtie]
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) Export `APPMAP=true` when you start your Rails application server. For example:
146
+ 2. Start your Rails application server. For example:
112
147
 
113
148
  ```sh-session
114
- $ APPMAP=true bundle exec rails server
149
+ $ bundle exec rails server
115
150
  ```
116
151
 
117
- When the Rails app exits, an `appmap.json` file will be written to the project root directory. You can upload it using
118
- the `appmap upload` command.
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 App.Land, run the `appmap upload` command. For example:
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/Hello says hello.json
126
- Full classMap contains 1 classes
127
- Pruned classMap contains 1 classes
128
- Uploaded new scenario: d49f3d16-e9f2-4775-a731-6cb95193927e
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
- # TODO: Optionally populate the 'layout' from appmap config or RSpec metadata.
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 = ActiveSupport::Inflector.transliterate(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! { |d| d.nil? || d == '' }
283
+ description.reject!(&:nil?).reject(&:blank?)
284
+ default_description = description.last
267
285
  description.reverse!
268
286
 
269
- description.each do |token|
270
- token = token.gsub 'it should behave like', ''
271
- token.gsub! ' ', ' '
272
- token.gsub! '/', '_'
273
- token.strip!
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
- recorder.save full_description, events,
278
- feature_name: feature,
279
- feature_group_name: feature_group
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
@@ -87,15 +87,24 @@ module AppMap
87
87
  def display_string(value)
88
88
  return nil unless value
89
89
 
90
- begin
91
- value_string = value.to_s
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppMap
4
- VERSION = '0.18.1'
4
+ VERSION = '0.19.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.1
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin