appmap_depends 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b1b9b4ea40ab4a29c1a948d170192055e2968066202355029e700f4fc2b81ab7
4
+ data.tar.gz: 6391eccbb15cca43cd41f6bb3f379559186117122388aefd50b7bd5396b135a9
5
+ SHA512:
6
+ metadata.gz: 2c9f085dc5e91d28da82048ff7b91f630caebc8281f126352e03aaedda2303ab8db2d86f5b8e83ac9d5c58e522745ebdcebd59f3fef7a2c76163ff03c5670cce
7
+ data.tar.gz: 68595be48e354a7bcaaa26731347a1e4593f84fa8418c564ee301ae9b4570a5973d3cdf54772a277f5032cc0917c865739bfbe1dbff3d763031e820be9f9e86e
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
10
+ .byebug_history
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.6.6
6
+ before_install: gem install bundler -v 2.1.4
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # v0.2.0
2
+
3
+ * Switch to the monorepo version of `@appland/cli`.
4
+ * Remove the `appmap/depends/task` package. Show the user how to define the Rake tasks with the task body provided by `AppMap::Depends` functions.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in appmap_depends.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "minitest", "~> 5.0"
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Kevin Gilpin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # `appmap_depends`
2
+
3
+ This gem provides Rake tasks called `depends:modified` and `depends:diff`. These Rake tasks automatically compute a list of test cases that need to be re-run based on which source files have been modified. They use [AppMap](https://github.com/applandinc/appmap-ruby) data files, which contain information about test case dependencies on source files, to perform this feat.
4
+
5
+ `appmap_depends` depends on an NPM package called [@appland/cli](https://www.npmjs.com/package/@appland/cli), which does most of the heavy lifting of processing AppMap data.
6
+
7
+ # How it works
8
+
9
+ The Rake tasks `depends:modified` and `depends:diff` require Node.js and the NPM package `@appland/cli`.
10
+
11
+ Each task looks at which source files have been locally modified. The difference between `depends:modified` and `depends:diff` is what source files are considered modified; this difference is described in detail in the next section. The Rake task then scans the AppMaps to figure out which ones are out-of-date with respect to the source files. This is possible since each AppMap contains a `classMap`, which lists all the source files that are included in the recording. Each AppMap has a `source_location` field, which identifies the test case file that was run to generate the AppMap. `depends` prints the list of test case files to standard out.
12
+
13
+ The `depends:modified` task looks at which source files have been locally modified. This task is used in local development. Run it as you work with the code.
14
+
15
+ The `depends:diff` task looks at source files that are modified relative to a base `git` branch. This task is used in CI. Run it before running the full test suite, so that the tests which are most likely to fail will be run first. If any of the tests in this batch fail, fail the build until the developer fixes the tests, then run the full test suite.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ group :development, :test do
23
+ gem 'appmap_depends'
24
+ end
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```sh-session
30
+ $ bundle install
31
+ ```
32
+
33
+ # Usage
34
+
35
+ ## Defining the Rake tasks
36
+
37
+ You need to define the Rake tasks. In Rails, this is done by creating a file like `lib/tasks/appmap.rake`.
38
+
39
+ In the file, check if `appmap_depends` is loaded, and then configure the Rake tasks.
40
+
41
+ ```ruby
42
+ namespace :appmap do
43
+ def depends_tasks
44
+ namespace :depends do
45
+ task :modified do
46
+ @appmap_modified_files = AppMap::Depends.modified
47
+ AppMap::Depends.report_list 'Out of date', @appmap_modified_files
48
+ end
49
+
50
+ task :diff do
51
+ @appmap_modified_files = AppMap::Depends.diff(base: BASE_BRANCH)
52
+ AppMap::Depends.report_list 'Out of date', @appmap_modified_files
53
+ end
54
+
55
+ task :test_file_report do
56
+ @appmap_test_file_report = AppMap::Depends.inspect_test_files
57
+ @appmap_test_file_report.report
58
+ end
59
+
60
+ def run_minitest(test_files)
61
+ raise "RAILS_ENV must be 'test'" unless Rails.env.test?
62
+ $LOAD_PATH << 'test'
63
+ test_files.each do |test_file|
64
+ load test_file
65
+ end
66
+ $ARGV.replace []
67
+ Minitest.autorun
68
+ end
69
+
70
+ run_rspec(test_files)
71
+ system({ 'RAILS_ENV' => 'test', 'APPMAP' => 'true' }, "bundle exec rspec --format Fuubar #{test_files.map(&:shellescape).join(' ')}")
72
+ end
73
+
74
+ task :update_appmaps do
75
+ @appmap_test_file_report.clean_appmaps
76
+
77
+ @appmap_modified_files += @appmap_test_file_report.modified_files
78
+
79
+ if @appmap_modified_files.blank?
80
+ warn 'AppMaps are up to date'
81
+ next
82
+ end
83
+
84
+ AppMap::Depends.run_tests(@appmap_modified_files) do |test_files|
85
+ warn 'To generate AppMaps, uncomment run_minitest or run_rspec as appropriate for your project'
86
+ # run_minitest(test_files)
87
+ # run_rspec(test_files)
88
+ end
89
+ end
90
+ end
91
+
92
+ desc 'Bring AppMaps up to date with local file modifications, and updated derived data such as Swagger files'
93
+ task :modified => [ :'depends:modified', :'depends:test_file_report', :'depends:update_appmaps', :swagger ]
94
+
95
+ desc 'Bring AppMaps up to date with file modifications relative to the base branch'
96
+ task :diff, [ :base ] => [ :'depends:diff', :'depends:update_appmaps', :swagger, :'swagger:uptodate' ]
97
+ end
98
+ end
99
+
100
+ if %w[test development].member?(Rails.env)
101
+ depends_tasks
102
+
103
+ desc 'Bring AppMaps up to date with local file modifications, and updated derived data such as Swagger files'
104
+ task :appmap => :'appmap:depends:modified'
105
+ end
106
+ ```
107
+
108
+ ## Running in CI
109
+
110
+ In the CI environment, run the `appmap:depends:diff` task to compute the list of changed test files, and then
111
+ run those tests directly using the test command.
112
+
113
+ ### RSpec
114
+
115
+ This is easy with RSpec, just pipe the modified files to the `rspec` command:
116
+
117
+ ```sh-session
118
+ $ bundle exec rake appmap:depends:diff | tee /dev/tty | xargs env APPMAP=true bundle exec rspec
119
+ ```
120
+
121
+ ### Minitest
122
+
123
+ Minitest doesn't have a "run the tests" command that's analagous to `rspec`. You can define a Rask task which computes the changed test files and then uses the
124
+ Rake task `Rails::TestUnit::Runner` to run the tests.
125
+
126
+ ```ruby
127
+ namespace :appmap
128
+ if %w[test development].member?(Rails.env)
129
+ desc 'Run minitest tests that are modified relative to the base branch'
130
+ task :'test:diff' => :'test:prepare' do
131
+ task = AppMap::Depends::DiffTask.new
132
+ # This line is only needed if the base is not 'remotes/origin/main' or 'remotes/origin/master'
133
+ task.base = BASE_BRANCH
134
+ files = task.files
135
+ if Rake.verbose == true
136
+ warn 'Out of date tests:'
137
+ warn files.join(' ')
138
+ end
139
+ $: << "test"
140
+ Rails::TestUnit::Runner.rake_run(files)
141
+ end
142
+ end
143
+ end
144
+ ```
145
+
146
+ ## Development
147
+
148
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
149
+
150
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
151
+
152
+ ## Contributing
153
+
154
+ Bug reports and pull requests are welcome on GitHub at https://github.com/applandinc/appmap_depends-ruby.
155
+
156
+
157
+ ## License
158
+
159
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'appmap/depends/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "appmap_depends"
9
+ spec.version = AppMap::Depends::VERSION
10
+ spec.authors = ['Kevin Gilpin']
11
+ spec.email = ['kgilpin@gmail.com']
12
+
13
+ spec.summary = %q{Provides Rake tasks to compute code dependencies based on AppMap data}
14
+ spec.homepage = 'https://github.com/applandinc/appmap_depends-ruby'
15
+ spec.license = 'MIT'
16
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
17
+
18
+ # Specify which files should be added to the gem when it is released.
19
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_dependency 'rake'
28
+ spec.add_dependency 'activesupport'
29
+
30
+ spec.add_development_dependency 'minitest'
31
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "appmap_depends"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppMap
4
+ module Depends
5
+ extend self
6
+
7
+ def modified(appmap_dir: DEFAULT_APPMAP_DIR, base_dir: nil)
8
+ depends = AppMap::Depends::AppMapJSDepends.new(appmap_dir)
9
+ depends.base_dir = base_dir if base_dir
10
+ test_files = depends.depends
11
+
12
+ Set.new prune_directory_prefix(test_files)
13
+ end
14
+
15
+ def diff(appmap_dir: DEFAULT_APPMAP_DIR, base_dir: nil, base_branches: DEFAULT_BASE_BRANCHES, base: nil, head: nil)
16
+ diff = AppMap::Depends::GitDiff.new(base_branches: base_branches, base: base, head: head)
17
+ modified_files = diff.modified_files
18
+
19
+ depends = AppMap::Depends::AppMapJSDepends.new(appmap_dir)
20
+ depends.base_dir = base_dir if base_dir
21
+ test_files = depends.depends(modified_files)
22
+
23
+ Set.new prune_directory_prefix(test_files)
24
+ end
25
+
26
+ def inspect_test_files(appmap_dir = DEFAULT_APPMAP_DIR, test_file_patterns = DEFAULT_TEST_FILE_PATTERNS)
27
+ inspector = AppMap::Depends::TestFileInspector.new(appmap_dir, test_file_patterns)
28
+ inspector.report
29
+ end
30
+
31
+ def report_list(title, files)
32
+ warn [ title, files.to_a.sort.join(' ') ].join(': ') unless files.empty?
33
+ end
34
+
35
+ def run_tests(test_files, appmap_dir: DEFAULT_APPMAP_DIR, &block)
36
+ test_files = test_files.to_a.sort
37
+ warn "Running tests: #{test_files.join(' ')}"
38
+
39
+ yield test_files
40
+
41
+ system(%(./node_modules/@appland/cli/src/cli.js index --appmap-dir #{appmap_dir.shellescape}))
42
+ end
43
+
44
+ protected
45
+
46
+ def prune_directory_prefix(files)
47
+ Util.normalize_path(files)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,49 @@
1
+ APPMAP_JS = './node_modules/@appland/appmap/src/cli.js'
2
+
3
+ module AppMap
4
+ module Depends
5
+ # Utilities for invoking the +@appland/appmap+ CLI.
6
+ module AppMapJS
7
+ APPMAP_JS = './node_modules/@appland/cli/src/cli.js'
8
+
9
+ def detect_nodejs
10
+ do_fail('node', 'please install NodeJS') unless system('node --version 2>&1 > /dev/null')
11
+ true
12
+ end
13
+
14
+ def detect_appmap_js
15
+ do_fail(APPMAP_JS, 'please install @appland/cli from NPM') unless File.exists?(APPMAP_JS)
16
+ true
17
+ end
18
+
19
+ def index_appmaps(appmap_dir)
20
+ appmap_js_command [ 'index', '--appmap-dir', appmap_dir ]
21
+ true
22
+ end
23
+
24
+ def do_fail(command, msg)
25
+ command = command.join(' ') if command.is_a?(Array)
26
+ warn [ command, msg ].join('; ') if Depends.verbose
27
+ raise CommandError.new(command, msg)
28
+ end
29
+
30
+ def appmap_js_command(command, options = {})
31
+ command.unshift << '--verbose' if Depends.verbose
32
+ command.unshift APPMAP_JS
33
+
34
+ warn command.join(' ') if Depends.verbose
35
+ stdout, stderr, status = Open3.capture3({ 'NODE_OPTIONS' => '--trace-warnings' }, *command, options)
36
+ stdout_msg = stdout.split("\n").map {|line| "stdout: #{line}"}.join("\n") unless stdout.blank?
37
+ stderr_msg = stderr.split("\n").map {|line| "stderr: #{line}"}.join("\n") unless stderr.blank?
38
+ if Depends.verbose
39
+ warn stdout_msg if stdout_msg
40
+ warn stderr_msg if stderr_msg
41
+ end
42
+ unless status.exitstatus == 0
43
+ raise CommandError.new(command, [ stdout_msg, stderr_msg ].compact.join("\n"))
44
+ end
45
+ [ stdout, stderr ]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,49 @@
1
+ require 'shellwords'
2
+ require 'appmap/depends/appmap_js'
3
+
4
+ module AppMap
5
+ module Depends
6
+ # +Command+ wraps the Node +depends+ command.
7
+ class AppMapJSDepends
8
+ include AppMapJS
9
+
10
+ # Directory to scan for AppMaps.
11
+ attr_accessor :appmap_dir
12
+ # Directory name to prefix to the list of modified files which is provided to +depends+.
13
+ attr_accessor :base_dir
14
+
15
+ def initialize(appmap_dir)
16
+ @appmap_dir = appmap_dir
17
+ @base_dir = false
18
+ end
19
+
20
+ # Ensures that all dependencies are available.
21
+ def validate
22
+ detect_nodejs
23
+ detect_appmap_js
24
+ end
25
+
26
+ # Returns the source_location field of every AppMap that is "out of date" with respect to one of the
27
+ # +modified_files+.
28
+ def depends(modified_files = nil)
29
+ validate
30
+
31
+ index_appmaps(appmap_dir)
32
+
33
+ cmd = %w[depends --field source_location]
34
+ cmd += [ '--appmap-dir', appmap_dir ] if appmap_dir
35
+ cmd += [ '--base-dir', base_dir ] if base_dir
36
+
37
+ options = {}
38
+ if modified_files
39
+ cmd << '--stdin-files'
40
+ options[:stdin_data] = modified_files.map(&:shellescape).join("\n")
41
+ warn "Checking modified files: #{modified_files.join(' ')}" if Depends.verbose
42
+ end
43
+
44
+ stdout, = appmap_js_command cmd, options
45
+ stdout.split("\n")
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ module AppMap
2
+ module Depends
3
+ # Raised when a system / shell command fails.
4
+ class CommandError < StandardError
5
+ attr_reader :command, :msg
6
+
7
+ def initialize(command, msg = nil)
8
+ super [ "Command failed: #{command}", msg ].compact.join('; ')
9
+
10
+ @command = command
11
+ @msg = msg
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,53 @@
1
+ module AppMap
2
+ module Depends
3
+ class GitDiff
4
+ attr_reader :head, :base_branches
5
+
6
+ def initialize(base_branches: [], base: nil, head: nil)
7
+ @base_branches = base_branches
8
+ @base = base
9
+ @head = head
10
+ end
11
+
12
+ def base=(base)
13
+ @base = base
14
+ end
15
+
16
+ def base
17
+ return @base if @base
18
+
19
+ git_exists = -> { system('git --version 2>&1 > /dev/null') }
20
+ detect_branch = ->(branch) { `git branch -a`.split("\n").map(&:strip).member?(branch) }
21
+ detect_base = lambda do
22
+ return nil unless git_exists.()
23
+
24
+ @base_branches.find(&detect_branch)
25
+ end
26
+ @base = detect_base.()
27
+ raise "Unable to detect base branch. Specify it explicitly as a task argument." unless @base
28
+ @base
29
+ end
30
+
31
+ def modified_files
32
+ warn "Using base #{base.inspect}" if Depends.verbose
33
+ warn "Using head #{head.inspect}" if head && Depends.verbose
34
+
35
+ branches = [ head, base ].compact
36
+ diff_cmd = [ 'git', 'diff', '--name-only', branches.join('..') ]
37
+
38
+ if Depends.verbose
39
+ warn diff_cmd.join(' ')
40
+ warn "Files modified #{head ? 'in ' + head : 'locally'} compared to #{base}:"
41
+ end
42
+
43
+ stdout, stderr, status = Open3.capture3(*diff_cmd)
44
+ if status.exitstatus != 0
45
+ warn stdout
46
+ warn stderr
47
+ raise CommandError.new(diff_cmd)
48
+ end
49
+ stdout.split("\n")
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AppMap
4
+ module Depends
5
+ class TestFileInspector
6
+ TestReport = Struct.new(:metadata_files, :added, :removed, :changed, :failed) do
7
+ private_methods :metadata_files
8
+
9
+ def to_s
10
+ report = []
11
+ report << "Added test files : #{added.to_a.join(' ')}" unless added.empty?
12
+ report << "Removed test files : #{removed.to_a.join(' ')}" unless removed.empty?
13
+ report << "Changed test files : #{changed.to_a.join(' ')}" unless changed.empty?
14
+ report << "Failed test files : #{failed.to_a.join(' ')}" unless failed.empty?
15
+ report.compact.join("\n")
16
+ end
17
+
18
+ def report
19
+ warn to_s unless empty?
20
+ end
21
+
22
+ def empty?
23
+ [ added, removed, changed, failed ].all?(&:empty?)
24
+ end
25
+
26
+ def modified_files
27
+ added + changed + failed
28
+ end
29
+
30
+ # Delete AppMaps which depend on test cases that have been deleted.
31
+ def clean_appmaps
32
+ return if removed.empty?
33
+
34
+ delete_appmap = lambda do |appmap_path|
35
+ FileUtils.rm_rf(appmap_path)
36
+ appmap_file_path = [ appmap_path, 'appmap.json' ].join('.')
37
+ File.unlink(appmap_file_path) if File.exists?(appmap_file_path)
38
+ end
39
+
40
+ count = metadata_files.each_with_object(0) do |metadata_file, count|
41
+ metadata = JSON.parse(File.read(metadata_file))
42
+ source_location = Util.normalize_path(metadata['source_location'])
43
+ appmap_path = File.join(metadata_file.split('/')[0...-1])
44
+
45
+ if removed.member?(source_location)
46
+ delete_appmap.(appmap_path)
47
+ count += 1
48
+ end
49
+ end
50
+ count
51
+ end
52
+ end
53
+
54
+ attr_reader :test_dir
55
+ attr_reader :test_file_patterns
56
+
57
+ def initialize(test_dir, test_file_patterns)
58
+ @test_dir = test_dir
59
+ @test_file_patterns = test_file_patterns
60
+ end
61
+
62
+ def report
63
+ metadata_files = Dir.glob(File.join(test_dir, '**', 'metadata.json'))
64
+ source_locations = Set.new
65
+ changed_test_files = Set.new
66
+ failed_test_files = Set.new
67
+ metadata_files.each do |metadata_file|
68
+ metadata = JSON.parse(File.read(metadata_file))
69
+ appmap_path = File.join(metadata_file.split('/')[0...-1])
70
+
71
+ appmap_mtime = File.read(File.join(appmap_path, 'mtime')).to_i
72
+ source_location = Util.normalize_path(metadata['source_location'])
73
+ test_status = metadata['test_status']
74
+ source_location_mtime = (File.stat(source_location).mtime.to_f * 1000).to_i rescue nil
75
+
76
+ raise "Metadata #{metadata_file} does not contain source_location" unless source_location
77
+ raise "Metadata #{metadata_file} does not contain test_status" unless test_status
78
+
79
+ source_locations << source_location
80
+ if source_location_mtime
81
+ changed_test_files << source_location if source_location_mtime > appmap_mtime
82
+ failed_test_files << source_location unless test_status == 'succeeded'
83
+ end
84
+ end
85
+
86
+ test_files = Set.new(test_file_patterns.map(&Dir.method(:glob)).flatten)
87
+ new_test_files = test_files - source_locations
88
+ obsolete_test_files = source_locations - test_files
89
+
90
+ TestReport.new(metadata_files, new_test_files, obsolete_test_files, changed_test_files, failed_test_files)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,24 @@
1
+ module AppMap
2
+ module Depends
3
+ module Util
4
+ extend self
5
+
6
+ def normalize_path(path, pwd: Dir.pwd)
7
+ normalize_path_fn(pwd).(path)
8
+ end
9
+
10
+ def normalize_paths(paths, pwd: Dir.pwd)
11
+ paths.map(&normalize_path_fn(pwd))
12
+ end
13
+
14
+ private
15
+
16
+ def normalize_path_fn(pwd)
17
+ lambda do |path|
18
+ path = path[pwd.length + 1..-1] if path.index(pwd) == 0
19
+ path.split(':')[0]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ module AppMap
2
+ module Depends
3
+ VERSION = "0.2.0"
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ require 'appmap/depends/version'
2
+
3
+ module AppMap
4
+ module Depends
5
+ # Default directory to scan for appmap.s
6
+ DEFAULT_APPMAP_DIR = File.join('tmp', 'appmap')
7
+ # Default file to write Rake task results.
8
+ DEFAULT_OUTPUT_FILE = File.join('tmp', 'appmap_depends.txt')
9
+ # Default base branches which will be checked for existance.
10
+ DEFAULT_BASE_BRANCHES = %w[remotes/origin/main remotes/origin/master].freeze
11
+ # Default pattern to enumerate test cases.
12
+ DEFAULT_TEST_FILE_PATTERNS = [ 'spec/**/*_spec.rb', 'test/**/*_test.rb' ].freeze
13
+
14
+ def self.verbose(arg = nil)
15
+ @verbose = arg if arg
16
+ @verbose
17
+ end
18
+ end
19
+ end
20
+
21
+ def rake_defined?
22
+ require 'rake'
23
+ true
24
+ rescue LoadError
25
+ false
26
+ end
27
+
28
+ require 'appmap/depends/util'
29
+ require 'appmap/depends/command_error'
30
+ require 'appmap/depends/git_diff'
31
+ require 'appmap/depends/appmap_js_depends'
32
+ require 'appmap/depends/test_file_inspector'
33
+ require 'appmap/depends/api'
34
+
35
+ if rake_defined?
36
+ AppMap::Depends.verbose(Rake.verbose == true)
37
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appmap_depends
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Gilpin
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-05-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - kgilpin@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - CHANGELOG.md
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - appmap_depends.gemspec
70
+ - bin/console
71
+ - bin/setup
72
+ - lib/appmap/depends/api.rb
73
+ - lib/appmap/depends/appmap_js.rb
74
+ - lib/appmap/depends/appmap_js_depends.rb
75
+ - lib/appmap/depends/command_error.rb
76
+ - lib/appmap/depends/git_diff.rb
77
+ - lib/appmap/depends/test_file_inspector.rb
78
+ - lib/appmap/depends/util.rb
79
+ - lib/appmap/depends/version.rb
80
+ - lib/appmap_depends.rb
81
+ homepage: https://github.com/applandinc/appmap_depends-ruby
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 2.3.0
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubygems_version: 3.0.3
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Provides Rake tasks to compute code dependencies based on AppMap data
104
+ test_files: []