appmap 0.61.1 → 0.62.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -16
  3. data/ARCHITECTURE.md +68 -0
  4. data/CHANGELOG.md +15 -0
  5. data/exe/appmap-index +7 -0
  6. data/lib/appmap.rb +2 -0
  7. data/lib/appmap/agent.rb +0 -11
  8. data/lib/appmap/command/index.rb +25 -0
  9. data/lib/appmap/command/inspect.rb +0 -1
  10. data/lib/appmap/config.rb +8 -1
  11. data/lib/appmap/depends.rb +2 -0
  12. data/lib/appmap/depends/api.rb +84 -0
  13. data/lib/appmap/depends/configuration.rb +59 -0
  14. data/lib/appmap/depends/node_cli.rb +44 -0
  15. data/lib/appmap/depends/rake_tasks.rb +58 -0
  16. data/lib/appmap/depends/test_file_inspector.rb +89 -0
  17. data/lib/appmap/depends/test_runner.rb +106 -0
  18. data/lib/appmap/depends/util.rb +34 -0
  19. data/lib/appmap/version.rb +1 -1
  20. data/package.json +1 -1
  21. data/spec/depends/api_spec.rb +184 -0
  22. data/spec/depends/spec_helper.rb +27 -0
  23. data/spec/fixtures/depends/.gitignore +2 -0
  24. data/spec/fixtures/depends/app/controllers/api/api_keys_controller.rb +2 -0
  25. data/spec/fixtures/depends/app/controllers/organizations_controller.rb +2 -0
  26. data/spec/fixtures/depends/app/models/api_key.rb +2 -0
  27. data/spec/fixtures/depends/app/models/configuration.rb +2 -0
  28. data/spec/fixtures/depends/app/models/show.rb +2 -0
  29. data/spec/fixtures/depends/app/models/user.rb +2 -0
  30. data/spec/fixtures/depends/revoke_api_key.appmap.json +901 -0
  31. data/spec/fixtures/depends/spec/actual_rspec_test.rb +7 -0
  32. data/spec/fixtures/depends/spec/api_spec.rb +2 -0
  33. data/spec/fixtures/depends/spec/user_spec.rb +2 -0
  34. data/spec/fixtures/depends/test/actual_minitest_test.rb +5 -0
  35. data/spec/fixtures/depends/user_page_scenario.appmap.json +1776 -0
  36. data/spec/fixtures/rails5_users_app/create_app +3 -3
  37. data/spec/fixtures/rails6_users_app/create_app +3 -3
  38. data/spec/fixtures/rails6_users_app/lib/tasks/appmap.rake +11 -1
  39. data/test/test_helper.rb +3 -0
  40. data/yarn.lock +23 -9
  41. metadata +29 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8238a1a1651c5fb157b7603ff92169e3e44097318057eb3ef29d57d600817335
4
- data.tar.gz: dd805a2bfa96ae3da4ea3bc47df524aa606e9b6dc69d943daa0a360f8da98ea5
3
+ metadata.gz: 3a6320c85ad8807149cb904032ad4f9a316b7bcd9454985e0851601745dbca70
4
+ data.tar.gz: 18434ce1e06c9f3580c9d86bca8dc21966f7c728a20e8c0d782638af5ce93a28
5
5
  SHA512:
6
- metadata.gz: 41e1766995e26ebf75d33403c7b4d72e562b8d14202d3e34f094a276254f67e193b957ea1e26b8e0a561328ed7594fb1dce8cf554ee780df7155e276f7e04e5f
7
- data.tar.gz: ba4c314bf9b07b377ea7e3714c082f9121bc082add10d04118e59c9cc0fd4ccdc9575159f6e6023bf0acf25a28cf8559f4d3a00f6942b1f0c17bdd7face0c2f1
6
+ metadata.gz: 6d3069df241f58d2d2e6497713ceeef3a5d97dc3ba5f11acd9eb25834ebc51bca21516717cb5ee941ac4ea4373ec17c5fe956f493705baa858a7ebac69b8c48e
7
+ data.tar.gz: 26dceefdd1aec688c9a7d17aa5ebfddf42310b9557905caccd3594d86b1b048fa72d0ca99004f4aae4f6262dd2f282f03c68d9e0377a70ca854c0713f424b652
data/.travis.yml CHANGED
@@ -14,14 +14,6 @@ addons:
14
14
  services:
15
15
  - docker
16
16
 
17
- # We expect RAILS_ENV to start off unset, then adjust its value as
18
- # necessary.
19
- before_script:
20
- - unset RAILS_ENV
21
-
22
- cache:
23
- bundler: true
24
-
25
17
  before_install:
26
18
  # see https://blog.travis-ci.com/docker-rate-limits
27
19
  # and also https://www.docker.com/blog/what-you-need-to-know-about-upcoming-docker-hub-rate-limiting/
@@ -33,22 +25,20 @@ before_install:
33
25
  fi
34
26
  - |
35
27
  nvm install --lts \
36
- && nvm use --lts
28
+ && nvm use --lts \
29
+ && npm i -g yarn
37
30
 
38
- # GEM_ALTERNATIVE_NAME only needed for deployment
39
31
  jobs:
40
32
  include:
41
33
  - stage: test
42
- script:
43
- - set -e
44
- - mkdir tmp
45
- - npm i -g yarn
46
- - GEM_ALTERNATIVE_NAME='' bundle exec rake gem:build test
34
+ env:
35
+ # GEM_ALTERNATIVE_NAME only needed for deployment
36
+ - GEM_ALTERNATIVE_NAME=''
37
+ script: bundle exec rake
47
38
 
48
39
  before_deploy:
49
40
  - |
50
41
  npm i -g \
51
- yarn \
52
42
  semantic-release \
53
43
  @semantic-release/git \
54
44
  @semantic-release/changelog \
data/ARCHITECTURE.md ADDED
@@ -0,0 +1,68 @@
1
+ # `appmap-ruby` architecture
2
+
3
+ ## Official documentation
4
+
5
+ The official documentation for `appmap-ruby` is at [appland.com/docs](https://appland.com/docs/reference/appmap-ruby.html).
6
+
7
+ ## Integration with appmap-js
8
+
9
+ Most of the analytics functionality for AppMap JSON is implemented in [appmap-js](https://github.com/applandinc/appmap-js/). In particular, `packages/cli`. `appmap-ruby` includes the source code and dependencies of `@appland/cli`. Check the [Rakefile](./Rakefile) for references to npm and/or yarn to see how the packaging works.
10
+
11
+ `appmap-ruby` executes command-line programs provdied by `@appland/cli`; it doesn't attempt to load a Node.js library in-process. `@appland/cli` commands are designed to produce clean output on stdout, which is obtained and processed by `appmap-ruby`.
12
+
13
+ ## Swagger (OpenAPI) generation
14
+
15
+ `appmap-ruby` provides a [Rake task](./lib/appmap/swagger/rake_tasks.rb) to generate Swagger files from AppMaps. The majority of the Swagger is generated by calling out to `appmap-js swagger`. `appmap-ruby` makes it Ruby-friendly by wrapping it with Rake, and by adding doc strings to the Swagger by converting RDoc to HTML. It also post-processes the Swagger to remove volatile parameter examples, producing `openapi_stable.yml`.
16
+
17
+ **Configuration**
18
+
19
+ The Swagger task supports [configuration settings](./lib/appmap/swagger/configuration.rb) via appmap.yml. Put the settings under the `swagger` key.
20
+
21
+ The API version can also be specified explicitly in Ruby code, when the Rake task is defined:
22
+
23
+ ```ruby
24
+ AppMap.configuration.swagger_config.project_version = \
25
+ [
26
+ 'v',
27
+ File.read(File.join(Rails.root, 'VERSION')).strip,
28
+ '_',
29
+ `git rev-parse --short HEAD`.strip
30
+ ].join
31
+ ```
32
+
33
+ **Note** From experience, it seems like almost all of the value of the Swagger gen is provided by openapi_stable. Therefore, in the future this may become the only output from the Rake task, and the RDoc to HTML functionality may be removed.
34
+
35
+ The package `appmap/swagger` is loaded automatically by `appmap`, when Rake is available in the bundle.
36
+
37
+ **Blogs and videos**
38
+
39
+ * [How to auto-generate detailed Swagger/OpenAPI for all your Rails routes (Dev.to)](https://dev.to/appland/how-to-auto-generate-swagger-openapi-doc-for-your-web-services-3npn)
40
+ * [Generate Swagger for your Rails project, with no code changes, in 2 ¹/₂ minutes](https://dev.to/appland/generate-swagger-for-your-rails-project-with-no-code-changes-in-2-minutes-3abj)
41
+
42
+ ## Depends (incremental testing)
43
+
44
+ `appmap-ruby` provides a [Rake task](./lib/appmap/depends/rake_tasks.rb) to automatically run tests and update AppMaps as local source files and test files are modified. It leans heavily on the `depends` command provided by `@appland/cli`. To understand how the Rake tasks work, consider running `appmap-js depends` on your local AppMaps - you can `touch` source files to see the dependency detection in action.
45
+
46
+ However, computing which AppMaps need updating as a result of source files changes is only part of the story. `depends` also has to:
47
+
48
+ * Detect added, changed, and removed test files.
49
+ * Run the tests which are determined to be out of date.
50
+ * Update the AppMap index after updating the AppMaps.
51
+ * Remove any AppMaps which refer to tests that have been deleted.
52
+
53
+ Because `depends` has some complexity, there is an [API](./lib/appmap/depends/api.rb) module that implements key commands. To understand `depends` in further detail, after trying out the `@appland/cli` command, read this API.
54
+
55
+ The package `appmap/depends` is loaded automatically by `appmap`, when Rake is available in the bundle.
56
+
57
+ **Configuration**
58
+
59
+ The Depends task supports [configuration settings](./lib/appmap/depends/configuration.rb) via appmap.yml. Put the settings under the `depends` key. Some configuration settings for Depends are specified as fully-qualified method names (e.g. `Class::Name.method_name`). The Rake task definition code should ensure that the code for any customized methods is loaded and available. At the time of this writing, the primary reasons for overridding the default Depends behavior are:
60
+
61
+ * Inject custom environment variables into the test command.
62
+ * Override the default test command string.
63
+
64
+ There are separate settings for `rspec` and `minitest`.
65
+
66
+ **Blogs and videos**
67
+
68
+ * [July 2021 Roadmap](https://appland.com/videos/2021/07/01/appmap-july-2021-roadmap/)
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # [0.62.0](https://github.com/applandinc/appmap-ruby/compare/v0.61.1...v0.62.0) (2021-07-21)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Update @appland/cli version ([e41fd65](https://github.com/applandinc/appmap-ruby/commit/e41fd6527dfc8730ad57471a62b3a058068829c8))
7
+
8
+
9
+ ### Features
10
+
11
+ * Add 'depends' Rake tasks ([a2e6793](https://github.com/applandinc/appmap-ruby/commit/a2e67939ae4d580eabf666ee52287e66701bca53))
12
+ * Add standalone appmap-index command ([ee497c9](https://github.com/applandinc/appmap-ruby/commit/ee497c9d1bb1eedf426f50fd00775d2421a852bf))
13
+ * Update @appland/cli to 1.3.0 ([5821df3](https://github.com/applandinc/appmap-ruby/commit/5821df304665de6b0c2277da760d34efe1232766))
14
+ * User no longer has to supply the command to run tests ([7ac2fed](https://github.com/applandinc/appmap-ruby/commit/7ac2fed796a09d53faacf40682f27a7c617f63da))
15
+
1
16
  ## [0.61.1](https://github.com/applandinc/appmap-ruby/compare/v0.61.0...v0.61.1) (2021-07-16)
2
17
 
3
18
 
data/exe/appmap-index ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift File.join(__dir__, '../lib')
5
+
6
+ require 'appmap/command/index'
7
+ AppMap::Command::Index.run
data/lib/appmap.rb CHANGED
@@ -18,6 +18,7 @@
18
18
  # - appmap/rspec
19
19
  # - appmap/minitest
20
20
  # - appmap/swagger (Rake task)
21
+ # - appmap/depends (Rake task)
21
22
 
22
23
  require 'appmap/version'
23
24
  require 'appmap/agent'
@@ -70,6 +71,7 @@ lambda do
70
71
 
71
72
  if defined?(::Rake)
72
73
  require 'appmap/swagger'
74
+ require 'appmap/depends'
73
75
  end
74
76
 
75
77
  end.call
data/lib/appmap/agent.rb CHANGED
@@ -57,17 +57,6 @@ module AppMap
57
57
  end
58
58
  end
59
59
 
60
- def config_message(msg)
61
- logger = if defined?(::Rails) && ::Rails.logger
62
- ::Rails.logger
63
- elsif ENV['DEBUG'] == 'true'
64
- method(:warn)
65
- else
66
- ->(msg) { }
67
- end
68
- logger.call(msg)
69
- end
70
-
71
60
  # Used to start tracing, stop tracing, and record events.
72
61
  def tracing
73
62
  @tracing ||= Trace::Tracing.new
@@ -0,0 +1,25 @@
1
+ require 'appmap/version'
2
+ require 'appmap/node_cli'
3
+
4
+ module AppMap
5
+ module Command
6
+ class Index < AppMap::NodeCLI
7
+ class << self
8
+ def run
9
+ command = Index.new(verbose: ENV['DEBUG'] == 'true')
10
+ command.index(ARGV)
11
+ end
12
+ end
13
+
14
+ def index(arguments)
15
+ detect_nodejs
16
+
17
+ arguments.unshift 'index'
18
+ arguments.unshift APPMAP_JS
19
+ arguments.unshift 'node'
20
+
21
+ exec(*arguments)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,5 +1,4 @@
1
1
  require 'appmap/version'
2
- require 'appmap/config'
3
2
  require 'appmap/node_cli'
4
3
 
5
4
  module AppMap
data/lib/appmap/config.rb CHANGED
@@ -7,6 +7,7 @@ require 'appmap/handler/net_http'
7
7
  require 'appmap/handler/rails/template'
8
8
  require 'appmap/service/guesser'
9
9
  require 'appmap/swagger/configuration'
10
+ require 'appmap/depends/configuration'
10
11
 
11
12
  module AppMap
12
13
  class Config
@@ -228,17 +229,19 @@ module AppMap
228
229
  'JSON::Ext::Generator::State' => TargetMethods.new(:generate, Package.build_from_path('json', package_name: 'json', labels: %w[format.json.generate])),
229
230
  }.freeze
230
231
 
231
- attr_reader :name, :appmap_dir, :packages, :exclude, :swagger_config, :hooked_methods, :builtin_hooks
232
+ attr_reader :name, :appmap_dir, :packages, :exclude, :swagger_config, :depends_config, :hooked_methods, :builtin_hooks
232
233
 
233
234
  def initialize(name,
234
235
  packages: [],
235
236
  swagger_config: Swagger::Configuration.new,
237
+ depends_config: Depends::Configuration.new,
236
238
  exclude: [],
237
239
  functions: [])
238
240
  @name = name
239
241
  @appmap_dir = AppMap::DEFAULT_APPMAP_DIR
240
242
  @packages = packages
241
243
  @swagger_config = swagger_config
244
+ @depends_config = depends_config
242
245
  @hook_paths = Set.new(packages.map(&:path))
243
246
  @exclude = exclude
244
247
  @builtin_hooks = BUILTIN_HOOKS
@@ -359,6 +362,10 @@ module AppMap
359
362
  swagger_config = Swagger::Configuration.load(config_data['swagger'])
360
363
  config_params[:swagger_config] = swagger_config
361
364
  end
365
+ if config_data['depends']
366
+ depends_config = Depends::Configuration.load(config_data['depends'])
367
+ config_params[:depends_config] = depends_config
368
+ end
362
369
 
363
370
  Config.new name, config_params
364
371
  end
@@ -0,0 +1,2 @@
1
+ require 'appmap/depends/configuration'
2
+ require 'appmap/depends/rake_tasks'
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'util'
4
+ require_relative 'node_cli'
5
+ require_relative 'test_file_inspector'
6
+ require_relative 'test_runner'
7
+
8
+ module AppMap
9
+ module Depends
10
+ class API
11
+ attr_reader :verbose
12
+
13
+ def initialize(verbose)
14
+ @verbose = verbose
15
+ end
16
+
17
+ # Compute the set of test files which are "out of date" with respect to source files in +base_dir+.
18
+ # Use AppMaps in +appmap_dir+ to make this computation.
19
+ def modified(appmap_dir:, base_dir:)
20
+ depends = AppMap::Depends::NodeCLI.new(verbose: verbose, appmap_dir: appmap_dir)
21
+ depends.base_dir = base_dir if base_dir
22
+ test_files = depends.depends
23
+
24
+ Set.new prune_directory_prefix(test_files)
25
+ end
26
+
27
+ # Compute which test case files have been added, removed, changed, or failed, relative to the
28
+ # AppMaps.
29
+ def inspect_test_files(appmap_dir:, test_file_patterns:)
30
+ inspector = AppMap::Depends::TestFileInspector.new(appmap_dir, test_file_patterns)
31
+ inspector.report
32
+ end
33
+
34
+ # Print a brief report to STDERR.
35
+ def report_list(title, files)
36
+ warn [ title, files.to_a.sort.join(' ') ].join(': ') unless files.empty?
37
+ end
38
+
39
+ # Run the specified test files. After running the tests, update the AppMap index.
40
+ # TODO: If the tests fail, this method will raise, and the index won't be updated.
41
+ # What's the right behavior for the index if there is a test failure? Current behavior may not match
42
+ # user expectations.
43
+ def run_tests(test_files, appmap_dir:)
44
+ test_files = test_files.to_a.sort
45
+ warn "Running tests: #{test_files.join(' ')}"
46
+
47
+ TestRunner.new(test_files).run
48
+
49
+ AppMap::NodeCLI.new(verbose: verbose, appmap_dir: appmap_dir).index_appmaps
50
+ end
51
+
52
+ # Remove out-of-date AppMaps which are unmodified +since+ the start time. This operation is used to remove AppMaps
53
+ # that were previously generated from a test case that has been removed from a test file.
54
+ #
55
+ # * +since+ an instance of Time
56
+ def remove_out_of_date_appmaps(since, appmap_dir:, base_dir:)
57
+ since_ms = ( since.to_f * 1000 ).to_i
58
+
59
+ depends = AppMap::Depends::NodeCLI.new(verbose: verbose, appmap_dir: appmap_dir)
60
+ depends.base_dir = base_dir if base_dir
61
+ depends.field = nil
62
+ out_of_date_appmaps = depends.depends
63
+ removed = []
64
+ out_of_date_appmaps.each do |appmap_path|
65
+ mtime_path = File.join(appmap_path, 'mtime')
66
+ next unless File.exists?(mtime_path)
67
+
68
+ appmap_mtime = File.read(mtime_path).to_i
69
+ if appmap_mtime < since_ms
70
+ Util.delete_appmap appmap_path
71
+ removed << appmap_path
72
+ end
73
+ end
74
+ removed.sort
75
+ end
76
+
77
+ protected
78
+
79
+ def prune_directory_prefix(files)
80
+ Array(files).map(&Util.method(:normalize_path))
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'appmap'
4
+
5
+ module AppMap
6
+ module Depends
7
+ class Configuration
8
+ # Default file to write Rake task results.
9
+ DEFAULT_OUTPUT_FILE = File.join('tmp', 'appmap_depends.txt')
10
+ # Default base branches which will be checked for existance.
11
+ DEFAULT_BASE_BRANCHES = %w[remotes/origin/main remotes/origin/master].freeze
12
+ # Default pattern to enumerate test cases.
13
+ DEFAULT_TEST_FILE_PATTERNS = [ 'spec/**/*_spec.rb', 'test/**/*_test.rb' ].freeze
14
+ DEFAULT_DEPENDENT_TASKS = [ :swagger ].freeze
15
+ DEFAULT_DESCRIPTION = 'Bring AppMaps up to date with local file modifications, and updated derived data such as Swagger files'
16
+ DEFAULT_ENVIRONMENT_METHOD = 'AppMap::Depends.test_env'
17
+ DEFAULT_RSPEC_SELECT_TESTS_METHOD = 'AppMap::Depends.select_rspec_tests'
18
+ DEFAULT_MINITEST_SELECT_TESTS_METHOD = 'AppMap::Depends.select_minitest_tests'
19
+ DEFAULT_RSPEC_TEST_COMMAND_METHOD = 'AppMap::Depends.rspec_test_command'
20
+ DEFAULT_MINITEST_TEST_COMMAND_METHOD = 'AppMap::Depends.minitest_test_command'
21
+
22
+ attr_accessor :base_dir,
23
+ :base_branches,
24
+ :test_file_patterns,
25
+ :dependent_tasks,
26
+ :description,
27
+ :rspec_environment_method,
28
+ :minitest_environment_method,
29
+ :rspec_select_tests_method,
30
+ :minitest_select_tests_method,
31
+ :rspec_test_command_method,
32
+ :minitest_test_command_method,
33
+
34
+ class << self
35
+ def load(config_data)
36
+ Configuration.new.tap do |config|
37
+ config_data.each do |k,v|
38
+ config.send "#{k}=", v
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ def initialize
45
+ @base_dir = nil
46
+ @base_branches = DEFAULT_BASE_BRANCHES
47
+ @test_file_patterns = DEFAULT_TEST_FILE_PATTERNS
48
+ @dependent_tasks = DEFAULT_DEPENDENT_TASKS
49
+ @description = DEFAULT_DESCRIPTION
50
+ @rspec_environment_method = DEFAULT_ENVIRONMENT_METHOD
51
+ @minitest_environment_method = DEFAULT_ENVIRONMENT_METHOD
52
+ @rspec_select_tests_method = DEFAULT_RSPEC_SELECT_TESTS_METHOD
53
+ @minitest_select_tests_method = DEFAULT_MINITEST_SELECT_TESTS_METHOD
54
+ @rspec_test_command_method = DEFAULT_RSPEC_TEST_COMMAND_METHOD
55
+ @minitest_test_command_method = DEFAULT_MINITEST_TEST_COMMAND_METHOD
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'shellwords'
4
+ require 'appmap/node_cli'
5
+
6
+ module AppMap
7
+ module Depends
8
+ # +Command+ wraps the Node +depends+ command.
9
+ class NodeCLI < ::AppMap::NodeCLI
10
+ # Directory name to prefix to the list of modified files which is provided to +depends+.
11
+ attr_accessor :base_dir
12
+ # AppMap field to report.
13
+ attr_accessor :field
14
+
15
+ def initialize(verbose:, appmap_dir:)
16
+ super(verbose: verbose, appmap_dir: appmap_dir)
17
+
18
+ @base_dir = nil
19
+ @field = 'source_location'
20
+ end
21
+
22
+ # Returns the source_location field of every AppMap that is "out of date" with respect to one of the
23
+ # +modified_files+.
24
+ def depends(modified_files = nil)
25
+ index_appmaps
26
+
27
+ cmd = %w[depends]
28
+ cmd += [ '--field', field ] if field
29
+ cmd += [ '--appmap-dir', appmap_dir ] if appmap_dir
30
+ cmd += [ '--base-dir', base_dir ] if base_dir
31
+
32
+ options = {}
33
+ if modified_files
34
+ cmd << '--stdin-files'
35
+ options[:stdin_data] = modified_files.map(&:shellescape).join("\n")
36
+ warn "Checking modified files: #{modified_files.join(' ')}" if verbose
37
+ end
38
+
39
+ stdout, = command cmd, options
40
+ stdout.split("\n")
41
+ end
42
+ end
43
+ end
44
+ end