appmap 0.39.1 → 0.40.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/CONTRIBUTING.md +22 -0
- data/README.md +59 -46
- data/lib/appmap/class_map.rb +25 -8
- data/lib/appmap/rails/request_handler.rb +8 -3
- data/lib/appmap/railtie.rb +1 -5
- data/lib/appmap/version.rb +1 -1
- data/spec/fixtures/hook/labels.rb +6 -0
- data/spec/fixtures/rails5_users_app/Gemfile +2 -3
- data/spec/fixtures/rails5_users_app/config/application.rb +2 -0
- data/spec/fixtures/rails6_users_app/Gemfile +2 -3
- data/spec/fixtures/rails6_users_app/config/application.rb +2 -0
- data/spec/hook_spec.rb +26 -0
- data/spec/spec_helper.rb +1 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b0943dadde84e67780d724918fa26377b869791eaab6edfb714e5081ecb5c80
|
4
|
+
data.tar.gz: c492323d80541a913b800924d04a7c24a6c8682263ba3ec4deabfa8d7ade3908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a27e5b9bc3dafbba8aafd7035732b6ffcb813d57bb216d0e544af30260c0e26f23a920d1b2d6d35882046e74a57f8b492b12b9869de5d820ff6a4e09cafd716
|
7
|
+
data.tar.gz: f1bdc22fda7a6fdf0a37fc1d5bd419947e0fffa16511873dbe8a1549f30bf862566fe74fa4c9952c4338f5263414c99f3d598daec0a599b467e52ebac374b4f7
|
data/CHANGELOG.md
CHANGED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Contributing to appmap-ruby
|
2
|
+
|
3
|
+
We are incredibly thankful for the contributions we receive from the community. Before contributing, please take a moment to read our [Contributor License Agreement](https://github.com/applandorg/community/blob/master/docs/CLA%20Instructions.pdf) and our [Code of Conduct](https://github.com/applandorg/community/blob/master/docs/Code%20of%20Conduct%20for%20Contributors.pdf).
|
4
|
+
|
5
|
+
## Contributor License Agreement
|
6
|
+
We require our external contributors to sign a Contributor License Agreement ("CLA") in order to ensure that
|
7
|
+
our projects remain licensed under Free and Open Source licenses such as while allowing
|
8
|
+
Appland to build a sustainable business.
|
9
|
+
|
10
|
+
AppLand is committed to having a true Free and Open Source Software license for our
|
11
|
+
non-commercial software. A CLA enables AppLand to safely commercialize our products while
|
12
|
+
keeping a standard FOSS license with all the rights that license grants to users.
|
13
|
+
|
14
|
+
* [Contributor License Agreement](https://github.com/applandorg/community/blob/master/docs/CLA%20Instructions.pdf)
|
15
|
+
|
16
|
+
|
17
|
+
## Code of Conduct
|
18
|
+
|
19
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and
|
20
|
+
healthy community.
|
21
|
+
|
22
|
+
* [Code of Conduct](https://github.com/applandorg/community/blob/master/docs/Code%20of%20Conduct%20for%20Contributors.pdf)
|
data/README.md
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
|
2
2
|
- [About](#about)
|
3
|
+
- [Supported versions](#supported-versions)
|
3
4
|
- [Installation](#installation)
|
4
5
|
- [Configuration](#configuration)
|
6
|
+
- [Labels](#labels)
|
5
7
|
- [Running](#running)
|
6
8
|
- [RSpec](#rspec)
|
7
9
|
- [Minitest](#minitest)
|
8
10
|
- [Cucumber](#cucumber)
|
9
11
|
- [Remote recording](#remote-recording)
|
10
|
-
|
12
|
+
- [AppMap for VSCode](#appmap-for-vscode)
|
11
13
|
- [Uploading AppMaps](#uploading-appmaps)
|
12
14
|
- [Development](#development)
|
13
15
|
- [Running tests](#running-tests)
|
@@ -23,21 +25,21 @@
|
|
23
25
|
"AppMap" is a data format which records code structure (modules, classes, and methods), code execution events
|
24
26
|
(function calls and returns), and code metadata (repo name, repo URL, commit
|
25
27
|
SHA, labels, etc). It's more granular than a performance profile, but it's less
|
26
|
-
granular than a full debug trace. It's designed to be optimal for understanding the design intent and
|
28
|
+
granular than a full debug trace. It's designed to be optimal for understanding the design intent and structure of code and key data flows.
|
27
29
|
|
28
30
|
There are several ways to record AppMaps of your Ruby program using the `appmap` gem:
|
29
31
|
|
30
|
-
* Run your RSpec
|
32
|
+
* Run your tests (RSpec, Minitest, Cucumber) with the environment variable `APPMAP=true`. An AppMap will be generated for each spec.
|
31
33
|
* Run your application server with AppMap remote recording enabled, and use the [AppLand
|
32
34
|
browser extension](https://github.com/applandinc/appland-browser-extension) to start,
|
33
35
|
stop, and upload recordings.
|
34
|
-
*
|
36
|
+
* Wrap some code in an `AppMap.record` block, which returns JSON containing the code execution trace.
|
35
37
|
|
36
|
-
Once you have
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
Once you have made a recording, there are two ways to view automatically generated diagrams of the AppMaps.
|
39
|
+
|
40
|
+
The first option is to load the diagrams directly in your IDE, using the [AppMap extension for VSCode](https://marketplace.visualstudio.com/items?itemName=appland.appmap).
|
41
|
+
|
42
|
+
The second option is to upload them to the [AppLand server](https://app.land) using the [AppLand CLI](https://github.com/applandinc/appland-cli/releases).
|
41
43
|
|
42
44
|
### Supported versions
|
43
45
|
|
@@ -48,15 +50,10 @@ Support for new versions is added frequently, please check back regularly for up
|
|
48
50
|
|
49
51
|
# Installation
|
50
52
|
|
51
|
-
|
53
|
+
<a href="https://www.loom.com/share/78ab32a312ff4b85aa8827a37f1cb655"> <p>Quick and easy setup of the AppMap gem for Rails - Watch Video</p> <img style="max-width:300px;" src="https://cdn.loom.com/sessions/thumbnails/78ab32a312ff4b85aa8827a37f1cb655-with-play.gif"> </a>
|
52
54
|
|
53
|
-
**Global installation**
|
54
55
|
|
55
|
-
|
56
|
-
gem 'appmap'
|
57
|
-
```
|
58
|
-
|
59
|
-
**Install in test, development groups**
|
56
|
+
Add `gem 'appmap'` to your Gemfile just as you would any other dependency. We recommend that the Gem be added to the `:development, :test` section.
|
60
57
|
|
61
58
|
```
|
62
59
|
group :development, :test do
|
@@ -72,7 +69,8 @@ If you are using Ruby on Rails, require the railtie after Rails is loaded.
|
|
72
69
|
|
73
70
|
```
|
74
71
|
# application.rb is a good place to do this, along with all the other railties.
|
75
|
-
require 'appmap
|
72
|
+
# Don't require the railtie in environments that don't bundle the appmap gem.
|
73
|
+
require 'appmap/railtie' if defined?(AppMap).
|
76
74
|
```
|
77
75
|
|
78
76
|
# Configuration
|
@@ -85,7 +83,14 @@ name: MyProject
|
|
85
83
|
packages:
|
86
84
|
- path: app/controllers
|
87
85
|
- path: app/models
|
86
|
+
- path: app/jobs
|
87
|
+
- path: app/helpers
|
88
|
+
# Include the gems that you want to see in the dependency maps.
|
89
|
+
# These are just examples.
|
88
90
|
- gem: activerecord
|
91
|
+
- gem: devise
|
92
|
+
- gem: aws-sdk
|
93
|
+
- gem: will_paginate
|
89
94
|
```
|
90
95
|
|
91
96
|
* **name** Provides the project name (required)
|
@@ -104,6 +109,34 @@ Each entry in the `packages` list is a YAML object which has the following keys:
|
|
104
109
|
the same package are not recorded unless code execution leaves the package and re-enters it. Default: `true` when using `gem`,
|
105
110
|
`false` when using `path`.
|
106
111
|
|
112
|
+
# Labels
|
113
|
+
|
114
|
+
The [AppMap data format](https://github.com/applandinc/appmap) provides for class and function `labels`, which can be used to enhance the AppMap visualizations, and to programatically analyze the data.
|
115
|
+
|
116
|
+
You can apply function labels using source code comments in your Ruby code. To apply a labels to a function, add a `@label` or `@labels` line to the comment which immediately precedes a function.
|
117
|
+
|
118
|
+
For example, if you add this comment to your source code:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
class ApiKey
|
122
|
+
# @labels provider.authentication security
|
123
|
+
def authenticate(key)
|
124
|
+
# logic to verify the key here...
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Then the AppMap metadata section for this function will include:
|
130
|
+
|
131
|
+
```json
|
132
|
+
{
|
133
|
+
"name": "authenticate",
|
134
|
+
"type": "function",
|
135
|
+
"labels": [ "provider.authentication", "security" ]
|
136
|
+
}
|
137
|
+
```
|
138
|
+
|
139
|
+
|
107
140
|
# Running
|
108
141
|
|
109
142
|
## RSpec
|
@@ -129,10 +162,7 @@ require 'appmap/rspec'
|
|
129
162
|
require File.expand_path("../../config/environment", __FILE__)
|
130
163
|
```
|
131
164
|
|
132
|
-
2)
|
133
|
-
examples.
|
134
|
-
|
135
|
-
3) Run the tests with the environment variable `APPMAP=true`:
|
165
|
+
2) Run the tests with the environment variable `APPMAP=true`:
|
136
166
|
|
137
167
|
```sh-session
|
138
168
|
$ APPMAP=true bundle exec rspec
|
@@ -145,23 +175,6 @@ $ find tmp/appmap/rspec
|
|
145
175
|
Hello_says_hello_when_prompted.appmap.json
|
146
176
|
```
|
147
177
|
|
148
|
-
If you include the `feature` and `feature_group` metadata, these attributes will be exported to the AppMap file in the
|
149
|
-
`metadata` section. It will look something like this:
|
150
|
-
|
151
|
-
```json
|
152
|
-
{
|
153
|
-
...
|
154
|
-
"metadata": {
|
155
|
-
"name": "Hello app says hello when prompted",
|
156
|
-
"feature": "Hello app says hello",
|
157
|
-
"feature_group": "Hello"
|
158
|
-
},
|
159
|
-
...
|
160
|
-
}
|
161
|
-
```
|
162
|
-
|
163
|
-
If you don't explicitly declare `feature` and `feature_group`, then they will be inferred from the spec name and example descriptions.
|
164
|
-
|
165
178
|
## Minitest
|
166
179
|
|
167
180
|
To record Minitest tests, follow these additional steps:
|
@@ -188,13 +201,13 @@ require_relative '../config/environment'
|
|
188
201
|
2) Run your tests as you normally would with the environment variable `APPMAP=true`. For example:
|
189
202
|
|
190
203
|
```
|
191
|
-
$ APPMAP=true bundle exec rake
|
204
|
+
$ APPMAP=true bundle exec rake test
|
192
205
|
```
|
193
206
|
|
194
207
|
or
|
195
208
|
|
196
209
|
```
|
197
|
-
$ APPMAP=true bundle exec -Ilib -Itest test/*
|
210
|
+
$ APPMAP=true bundle exec ruby -Ilib -Itest test/*_test.rb
|
198
211
|
```
|
199
212
|
|
200
213
|
Each Minitest test will output an AppMap file into the directory `tmp/appmap/minitest`. For example:
|
@@ -251,9 +264,9 @@ To manually record ad-hoc AppMaps of your Ruby app, use AppMap remote recording.
|
|
251
264
|
1. Add the AppMap remote recording middleware. For example, in `config/initializers/appmap_remote_recording.rb`:
|
252
265
|
|
253
266
|
```ruby
|
254
|
-
|
267
|
+
if defined?(AppMap)
|
268
|
+
require 'appmap/middleware/remote_recording'
|
255
269
|
|
256
|
-
unless Rails.env.test?
|
257
270
|
Rails.application.config.middleware.insert_after \
|
258
271
|
Rails::Rack::Logger,
|
259
272
|
AppMap::Middleware::RemoteRecording
|
@@ -274,14 +287,14 @@ $ bundle exec rails server
|
|
274
287
|
|
275
288
|
6. Open the AppLand browser extension and push `Stop`. The recording will be transferred to the AppLand website and opened in your browser.
|
276
289
|
|
277
|
-
|
278
|
-
|
279
|
-
If your app uses Ruby on Rails, the AppMap Railtie will be automatically enabled. Set the Rails config flag `app.config.appmap.enabled = true` to record the entire execution of your Rails app.
|
290
|
+
# AppMap for VSCode
|
280
291
|
|
281
|
-
|
292
|
+
The [AppMap extension for VSCode](https://marketplace.visualstudio.com/items?itemName=appland.appmap) is a great way to onboard developers to new code, and troubleshoot hard-to-understand bugs with visuals.
|
282
293
|
|
283
294
|
# Uploading AppMaps
|
284
295
|
|
296
|
+
[https://app.land](https://app.land) can be used to store, analyze, and share AppMaps.
|
297
|
+
|
285
298
|
For instructions on uploading, see the documentation of the [AppLand CLI](https://github.com/applandinc/appland-cli).
|
286
299
|
|
287
300
|
# Development
|
data/lib/appmap/class_map.rb
CHANGED
@@ -113,17 +113,18 @@ module AppMap
|
|
113
113
|
[ method.defined_class, static ? '.' : '#', method.name ].join
|
114
114
|
end
|
115
115
|
|
116
|
+
source, comment = begin
|
117
|
+
[ method.source, method.comment ]
|
118
|
+
rescue MethodSource::SourceNotFoundError
|
119
|
+
[ nil, nil, ]
|
120
|
+
end
|
121
|
+
|
116
122
|
if include_source
|
117
|
-
|
118
|
-
|
119
|
-
comment = method.comment || ''
|
120
|
-
function_info[:comment] = comment unless comment.empty?
|
121
|
-
rescue MethodSource::SourceNotFoundError
|
122
|
-
# pass
|
123
|
-
end
|
123
|
+
function_info[:source] = source unless source.blank?
|
124
|
+
function_info[:comment] = comment unless comment.blank?
|
124
125
|
end
|
125
126
|
|
126
|
-
function_info[:labels] = package.labels
|
127
|
+
function_info[:labels] = parse_labels(comment) + (package.labels || [])
|
127
128
|
object_infos << function_info
|
128
129
|
|
129
130
|
parent = root
|
@@ -141,6 +142,22 @@ module AppMap
|
|
141
142
|
end
|
142
143
|
end
|
143
144
|
|
145
|
+
# Labels can be embedded in the function comment. Label format is similar to YARD and JavaDoc.
|
146
|
+
# The keyword is @labels or @label. The keyword is followed by space-separated labels.
|
147
|
+
# For example:
|
148
|
+
# @label provider.authentication security
|
149
|
+
def parse_labels(comment)
|
150
|
+
return [] unless comment
|
151
|
+
|
152
|
+
comment
|
153
|
+
.split("\n")
|
154
|
+
.map { |line| line.match(/^\s*#\s*@labels?\s+(.*)/) }
|
155
|
+
.compact
|
156
|
+
.map { |match| match[1] }
|
157
|
+
.inject([]) { |accum, labels| accum += labels.split(/\s+/); accum }
|
158
|
+
.sort
|
159
|
+
end
|
160
|
+
|
144
161
|
def find_or_create(list, info)
|
145
162
|
obj = list.find { |item| item.type == info[:type] && item.name == info[:name] }
|
146
163
|
return obj if obj
|
@@ -47,9 +47,14 @@ module AppMap
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
def normalized_path(request)
|
51
|
-
|
52
|
-
|
50
|
+
def normalized_path(request, router = ::Rails.application.routes.router)
|
51
|
+
router.recognize request do |route, _|
|
52
|
+
app = route.app
|
53
|
+
next unless app.matches? request
|
54
|
+
return normalized_path request, app.rack_app.routes.router if app.engine?
|
55
|
+
|
56
|
+
return route.path.spec.to_s
|
57
|
+
end
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
data/lib/appmap/railtie.rb
CHANGED
@@ -5,13 +5,9 @@ module AppMap
|
|
5
5
|
class Railtie < ::Rails::Railtie
|
6
6
|
config.appmap = ActiveSupport::OrderedOptions.new
|
7
7
|
|
8
|
-
initializer 'appmap.init' do |_| # params: app
|
9
|
-
require 'appmap'
|
10
|
-
end
|
11
|
-
|
12
8
|
# appmap.subscribe subscribes to ActiveSupport Notifications so that they can be recorded as
|
13
9
|
# AppMap events.
|
14
|
-
initializer 'appmap.subscribe'
|
10
|
+
initializer 'appmap.subscribe' do |_| # params: app
|
15
11
|
require 'appmap/rails/sql_handler'
|
16
12
|
require 'appmap/rails/request_handler'
|
17
13
|
ActiveSupport::Notifications.subscribe 'sql.sequel', AppMap::Rails::SQLHandler.new
|
data/lib/appmap/version.rb
CHANGED
@@ -33,11 +33,10 @@ appmap_options = \
|
|
33
33
|
{ path: appmap_path }
|
34
34
|
else
|
35
35
|
{}
|
36
|
-
end.merge(require: %w[appmap
|
37
|
-
|
38
|
-
gem 'appmap', appmap_options
|
36
|
+
end.merge(require: %w[appmap])
|
39
37
|
|
40
38
|
group :development, :test do
|
39
|
+
gem 'appmap', appmap_options
|
41
40
|
gem 'cucumber-rails', require: false
|
42
41
|
gem 'rspec-rails'
|
43
42
|
# Required for Sequel, since without ActiveRecord, the Rails transactional fixture support
|
@@ -34,11 +34,10 @@ appmap_options = \
|
|
34
34
|
{ path: appmap_path }
|
35
35
|
else
|
36
36
|
{}
|
37
|
-
end.merge(require: %w[appmap
|
38
|
-
|
39
|
-
gem 'appmap', appmap_options
|
37
|
+
end.merge(require: %w[appmap])
|
40
38
|
|
41
39
|
group :development, :test do
|
40
|
+
gem 'appmap', appmap_options
|
42
41
|
gem 'cucumber-rails', require: false
|
43
42
|
gem 'rspec-rails'
|
44
43
|
# Required for Sequel, since without ActiveRecord, the Rails transactional fixture support
|
data/spec/hook_spec.rb
CHANGED
@@ -61,6 +61,32 @@ describe 'AppMap class Hooking', docker: false do
|
|
61
61
|
AppMap.configuration = nil
|
62
62
|
end
|
63
63
|
|
64
|
+
it 'parses labels from comments' do
|
65
|
+
_, tracer = invoke_test_file 'spec/fixtures/hook/labels.rb' do
|
66
|
+
ClassWithLabel.new.fn_with_label
|
67
|
+
end
|
68
|
+
class_map = AppMap.class_map(tracer.event_methods).to_yaml
|
69
|
+
expect(Diffy::Diff.new(<<~YAML, class_map).to_s).to eq('')
|
70
|
+
---
|
71
|
+
- :name: spec/fixtures/hook/labels.rb
|
72
|
+
:type: package
|
73
|
+
:children:
|
74
|
+
- :name: ClassWithLabel
|
75
|
+
:type: class
|
76
|
+
:children:
|
77
|
+
- :name: fn_with_label
|
78
|
+
:type: function
|
79
|
+
:location: spec/fixtures/hook/labels.rb:4
|
80
|
+
:static: false
|
81
|
+
:labels:
|
82
|
+
- has-fn-label
|
83
|
+
:comment: "# @label has-fn-label\\n"
|
84
|
+
:source: |2
|
85
|
+
def fn_with_label
|
86
|
+
end
|
87
|
+
YAML
|
88
|
+
end
|
89
|
+
|
64
90
|
it 'hooks an instance method that takes no arguments' do
|
65
91
|
events_yaml = <<~YAML
|
66
92
|
---
|
data/spec/spec_helper.rb
CHANGED
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.40.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Gilpin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01-
|
11
|
+
date: 2021-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -319,6 +319,7 @@ files:
|
|
319
319
|
- ".rubocop.yml"
|
320
320
|
- ".travis.yml"
|
321
321
|
- CHANGELOG.md
|
322
|
+
- CONTRIBUTING.md
|
322
323
|
- Dockerfile.appmap
|
323
324
|
- Gemfile
|
324
325
|
- LICENSE.txt
|
@@ -386,6 +387,7 @@ files:
|
|
386
387
|
- spec/fixtures/hook/constructor.rb
|
387
388
|
- spec/fixtures/hook/exception_method.rb
|
388
389
|
- spec/fixtures/hook/instance_method.rb
|
390
|
+
- spec/fixtures/hook/labels.rb
|
389
391
|
- spec/fixtures/hook/singleton_method.rb
|
390
392
|
- spec/fixtures/rack_users_app/.dockerignore
|
391
393
|
- spec/fixtures/rack_users_app/.gitignore
|