diff_test 0.2.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 +7 -0
- data/.standard.yml +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +208 -0
- data/Rakefile +10 -0
- data/lib/diff_test/api_client.rb +38 -0
- data/lib/diff_test/configuration.rb +178 -0
- data/lib/diff_test/file_hash_computer.rb +21 -0
- data/lib/diff_test/helper.rb +37 -0
- data/lib/diff_test/impacted_file_tracker.rb +34 -0
- data/lib/diff_test/integrations/integration.rb +29 -0
- data/lib/diff_test/integrations/minitest/integration.rb +26 -0
- data/lib/diff_test/integrations/minitest/lifecycle.rb +77 -0
- data/lib/diff_test/integrations/rails_js/annotator.rb +43 -0
- data/lib/diff_test/integrations/rails_js/body_processor.rb +69 -0
- data/lib/diff_test/integrations/rails_js/integration.rb +25 -0
- data/lib/diff_test/integrations/rails_js/js_files.rake +48 -0
- data/lib/diff_test/integrations/rails_js/middleware.rb +43 -0
- data/lib/diff_test/integrations/rails_js/processing_skip_analyzer.rb +31 -0
- data/lib/diff_test/integrations/rails_js/railtie.rb +17 -0
- data/lib/diff_test/js_version_hash_computer.rb +24 -0
- data/lib/diff_test/project_version_hash_computer.rb +26 -0
- data/lib/diff_test/should_run_decider.rb +44 -0
- data/lib/diff_test/test_execution.rb +92 -0
- data/lib/diff_test/test_suite_execution.rb +114 -0
- data/lib/diff_test/trackers/base.rb +23 -0
- data/lib/diff_test/trackers/js_file.rb +7 -0
- data/lib/diff_test/trackers/ruby_file.rb +50 -0
- data/lib/diff_test/trackers/singleton_base.rb +43 -0
- data/lib/diff_test/version.rb +5 -0
- data/lib/diff_test.rb +32 -0
- data/sig/diff_test.rbs +4 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cac8148799f86b799f536964cbaf80ee3b77d99f915f33eb3c4e54c76cafd465
|
4
|
+
data.tar.gz: 52332e3b52034d18dd9572b85e9f2d4cf807000fd2049c27d6177a6f48caf1c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c9059223409cd8347bfe233adf8d65d19577d90cefa72e1b1cacd3a660cb33a018d0609d75710154f9addcbb057e207cbbb449b3c8d8cc7f7fd695fd3ae210f1
|
7
|
+
data.tar.gz: 89a3b42a009650ea1a6cd970627c40474b563d8afafa24371103dbfd933287b601359c220afeb6af19a52b2f78e19478290c343bd6c9cb14df115956664b624a
|
data/.standard.yml
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2025 Owais
|
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,208 @@
|
|
1
|
+
# DiffTest
|
2
|
+
|
3
|
+
## Configuration
|
4
|
+
|
5
|
+
### enabled
|
6
|
+
```ruby
|
7
|
+
DiffTest.configure do |config|
|
8
|
+
config.enabled = ENV['CI'].present?
|
9
|
+
|
10
|
+
config.project_root = Rails.root
|
11
|
+
|
12
|
+
config.vendor_bundle_path = File.join(Rails.root, 'vendor')
|
13
|
+
|
14
|
+
# Default: All files generated by git
|
15
|
+
config.project_files = [
|
16
|
+
-> { `git -C "#{Rails.root}" ls-files`.split("\n") }
|
17
|
+
]
|
18
|
+
|
19
|
+
# These paths don't factor into determining if tests should be run at all.
|
20
|
+
# Its as if they aren't even there.
|
21
|
+
config.ignored_paths = [
|
22
|
+
'db/migrate/**/*',
|
23
|
+
'**/*.md',
|
24
|
+
# 'doc/**/*',
|
25
|
+
# 'services/video_encoding/**/*
|
26
|
+
# 'simplero-mobile-app/**/*
|
27
|
+
# **/*.css
|
28
|
+
# **/*.scss
|
29
|
+
]
|
30
|
+
|
31
|
+
# Add patterns where you ruby/template files live.
|
32
|
+
# If you change any file that does not match these patterns, we will run all the tests.
|
33
|
+
config.tracked_paths = [
|
34
|
+
'app/**/*.rb',
|
35
|
+
'app/**/*.html.erb',
|
36
|
+
'lib/**/*.rb',
|
37
|
+
'lib/**/*.html.erb',
|
38
|
+
'test/**/*.rb',
|
39
|
+
]
|
40
|
+
|
41
|
+
# For this to work correctly,
|
42
|
+
# You need to ensure that these files are annotated
|
43
|
+
# You can automatically annotate your files with
|
44
|
+
# rake diff_test:annotate
|
45
|
+
# This also happens automatically when you run RAILS_ENV=test rails assets:precompile
|
46
|
+
config.tracked_js_paths = [
|
47
|
+
'app/javascript/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
|
48
|
+
'app/assets/javascripts/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
|
49
|
+
]
|
50
|
+
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
# TODO
|
55
|
+
* Testing strategy
|
56
|
+
* Documentation
|
57
|
+
--
|
58
|
+
* Fixture tracker
|
59
|
+
* Factory tracker
|
60
|
+
* CSS tracker
|
61
|
+
|
62
|
+
- TracePointTracker
|
63
|
+
- ConstantTracker (depends_on TracePointTracker)
|
64
|
+
- FileTracker
|
65
|
+
- FixtureTracker
|
66
|
+
- JavascriptTracker
|
67
|
+
-
|
68
|
+
|
69
|
+
- ImpactedFileTracker
|
70
|
+
- FileTracker
|
71
|
+
- ConstantTracker
|
72
|
+
- TracePointTracker
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
Number of commits (out of last 2000) with any changes NOT matching allowed patterns:
|
81
|
+
base_only => 592
|
82
|
+
with_factories_fixtures => 583
|
83
|
+
with_js_ts => 422
|
84
|
+
with_js_ts_css => 325
|
85
|
+
with_js_css_db_except_schema => 298
|
86
|
+
with_factories_fixtures_js_css => 316
|
87
|
+
with_factories_fixtures_js_css_db_except_schema => 288
|
88
|
+
with_factories_fixtures_except_schema => 558
|
89
|
+
with_factories_fixtures_css_except_schema => 487
|
90
|
+
with_css => 521
|
91
|
+
with_css_except_schema => 497
|
92
|
+
ruby cookbooks/track_non_matching.rb 1000 23.75s user 8.41s system 95% cpu 33.642 total
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
######
|
100
|
+
|
101
|
+
* Write tests on diff_test_web
|
102
|
+
* These are all system tests.
|
103
|
+
* Creates test suite executions
|
104
|
+
* Creates test executions
|
105
|
+
* Runs tests when impacted files change
|
106
|
+
* Runs tests when project files change
|
107
|
+
* Runs system test when js version change (in unrelated file) but no previous js run
|
108
|
+
* Skips system test when no js version change
|
109
|
+
* Runs system test when related js file changes
|
110
|
+
* Skip system test when related js file changes after a succesful run
|
111
|
+
|
112
|
+
* ImpactedFileTracker
|
113
|
+
- Ruby
|
114
|
+
- HTML
|
115
|
+
- Javascript
|
116
|
+
|
117
|
+
|
118
|
+
### Test TODO
|
119
|
+
|
120
|
+
Test rails app
|
121
|
+
[ ] UserTest model
|
122
|
+
- class access
|
123
|
+
[ ] AccountTest model
|
124
|
+
- calls searchable
|
125
|
+
- uses fixtures for users and accounts
|
126
|
+
[ ] Controller/Integration test
|
127
|
+
[ ] System test
|
128
|
+
- AccountController#index - views, controller, js, css, fixtures
|
129
|
+
- AccountController#partial
|
130
|
+
- AccountController#stream
|
131
|
+
- AccountController#components
|
132
|
+
- AccountController#layouts
|
133
|
+
- AccountController#helpers
|
134
|
+
[ ] Mailer test
|
135
|
+
[ ] Job test
|
136
|
+
|
137
|
+
|
138
|
+
# Tasks
|
139
|
+
X Allow login
|
140
|
+
X Allow signup
|
141
|
+
xpassword confirmation controller
|
142
|
+
X Allow account creation
|
143
|
+
xhandle check controller
|
144
|
+
xinherit from controller
|
145
|
+
X Account#show
|
146
|
+
xMake account#show view render a user_card partial
|
147
|
+
X Allow customer creation (assoc to user & account)
|
148
|
+
x Write model unit tests for User
|
149
|
+
x Write model unit tests for Account
|
150
|
+
x View component with html
|
151
|
+
x View component with call
|
152
|
+
x Write integration tests for AccountController around the handle_connect helper
|
153
|
+
x Make a mailer that sends a email about the details of a newly created account
|
154
|
+
x Make a job that runs every hour deleting accounts with invalid users
|
155
|
+
x View comopnent test
|
156
|
+
x Write system test for signup
|
157
|
+
password mismatch test
|
158
|
+
x Write system test for login
|
159
|
+
x Write system test for account creation
|
160
|
+
- handle check
|
161
|
+
- currency (USD)
|
162
|
+
- user
|
163
|
+
x Write system test for customer creation
|
164
|
+
-
|
165
|
+
|
166
|
+
|
167
|
+
|
168
|
+
DiffTestWeb
|
169
|
+
[ ] Test each test written above
|
170
|
+
assert impacted file.
|
171
|
+
run it again
|
172
|
+
assert skipped
|
173
|
+
change some unrelated files
|
174
|
+
run it again
|
175
|
+
change some related files
|
176
|
+
assert not skipped
|
177
|
+
|
178
|
+
[ ] Test various configurations
|
179
|
+
Changing JS version hash
|
180
|
+
Changing project version hash
|
181
|
+
All JS files annotated tracking
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
# Works locally
|
187
|
+
# Won't auto-annotate files locally
|
188
|
+
# Annotate files in CI through precompile or db:prepare
|
189
|
+
|
190
|
+
|
191
|
+
### LAter
|
192
|
+
# config.enabled = Rails.env.test?
|
193
|
+
# config.enabled = Rails.env.test? && ENV['CI'].present?
|
194
|
+
|
195
|
+
|
196
|
+
# Annotates JS files so they are be able to tracked as well.
|
197
|
+
# By default, we only do this in CI env.
|
198
|
+
# As an alternative, you can run `bundle exec rake diff_test:annotate` manually.
|
199
|
+
# To unannotate, simply run `bundle exec rake diff_test:unannoate`
|
200
|
+
# config.auto_annotate_js_files = :ci
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
# TODO
|
205
|
+
- Initialier/install script
|
206
|
+
- Set unskippable
|
207
|
+
- Skip from branch/commit/author name
|
208
|
+
- Unskippable branches
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module DiffTest
|
4
|
+
class ApiClient
|
5
|
+
include HTTParty
|
6
|
+
|
7
|
+
def self.get(path, options = {}, &block)
|
8
|
+
set_api_key_in_headers(options)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.post(path, options = {}, &block)
|
13
|
+
set_api_key_in_headers(options)
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.put(path, options = {}, &block)
|
18
|
+
set_api_key_in_headers(options)
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.patch(path, options = {}, &block)
|
23
|
+
set_api_key_in_headers(options)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.delete(path, options = {}, &block)
|
28
|
+
set_api_key_in_headers(options)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.set_api_key_in_headers(options)
|
33
|
+
base_uri "http://localhost:#{DiffTest.configuration.port}"
|
34
|
+
options[:headers] ||= {}
|
35
|
+
options[:headers]['X-Diff-Test-Api-Key'] = DiffTest.configuration.api_key
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module DiffTest
|
2
|
+
class Configuration
|
3
|
+
attr_writer \
|
4
|
+
:api_key,
|
5
|
+
:port,
|
6
|
+
:project_root,
|
7
|
+
:vendor_bundle_path,
|
8
|
+
:project_files,
|
9
|
+
:ignored_files,
|
10
|
+
:tracked_files,
|
11
|
+
:tracked_js_files
|
12
|
+
|
13
|
+
def api_key
|
14
|
+
@api_key || ENV['DIFF_TEST_API_KEY']
|
15
|
+
end
|
16
|
+
|
17
|
+
def port
|
18
|
+
@port || 8085
|
19
|
+
end
|
20
|
+
|
21
|
+
def project_root
|
22
|
+
return @project_root if @project_root
|
23
|
+
|
24
|
+
@project_root = ::Rails.root.to_s if defined?(::Rails)
|
25
|
+
|
26
|
+
unless @project_root
|
27
|
+
raise "Please specify a project root in config/environments/test.rb using
|
28
|
+
DiffTest.configure do |config|
|
29
|
+
config.project_root = '/path/to/your/project'
|
30
|
+
end
|
31
|
+
"
|
32
|
+
end
|
33
|
+
|
34
|
+
@project_root
|
35
|
+
end
|
36
|
+
|
37
|
+
def vendor_bundle_path
|
38
|
+
return @vendor_bundle_path if @vendor_bundle_path
|
39
|
+
|
40
|
+
@vendor_bundle_path = File.join(project_root, 'vendor', 'bundle').to_s if defined?(::Rails)
|
41
|
+
end
|
42
|
+
|
43
|
+
def project_files
|
44
|
+
@expanded_project_files ||=
|
45
|
+
begin
|
46
|
+
@project_files ||= [-> { `git -C "#{project_root}" ls-files`.split("\n") }]
|
47
|
+
|
48
|
+
expand_files(@project_files)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def ignored_files
|
53
|
+
@expanded_ignored_files ||=
|
54
|
+
begin
|
55
|
+
@ignored_files ||= ['db/migrate/**/*', '**/*.md']
|
56
|
+
filter_from_project_files(@ignored_files)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def tracked_files
|
61
|
+
@expanded_tracked_files ||=
|
62
|
+
begin
|
63
|
+
@tracked_files ||= [
|
64
|
+
'app/**/*.rb',
|
65
|
+
'app/**/*.html.erb',
|
66
|
+
'lib/**/*.rb',
|
67
|
+
'lib/**/*.html.erb',
|
68
|
+
'test/**/*.rb',
|
69
|
+
'!test/fixtures/**/*',
|
70
|
+
'!test/factories/**/*',
|
71
|
+
'!test/factories.rb',
|
72
|
+
]
|
73
|
+
filter_from_project_files(@tracked_files)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def tracked_js_files
|
78
|
+
@expanded_js_files ||=
|
79
|
+
begin
|
80
|
+
@tracked_js_files ||= [
|
81
|
+
'app/components/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
|
82
|
+
'app/javascript/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}',
|
83
|
+
'app/assets/javascripts/**/*.{js,jsx,ts,tsx,mjs,cjs,coffee}'
|
84
|
+
]
|
85
|
+
filter_from_project_files(@tracked_js_files)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def system_test_paths
|
90
|
+
@expanded_system_test_paths ||=
|
91
|
+
begin
|
92
|
+
@system_test_paths ||= [
|
93
|
+
'test/system/**/*.rb',
|
94
|
+
'test/system/**/*.html.erb'
|
95
|
+
]
|
96
|
+
filter_from_project_files(@system_test_paths)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def ci_platform
|
101
|
+
if ENV['CIRCLECI']
|
102
|
+
'circleci'
|
103
|
+
elsif ENV['GITHUB_ACTIONS']
|
104
|
+
'github-actions'
|
105
|
+
elsif ENV['TRAVIS']
|
106
|
+
'travis'
|
107
|
+
elsif ENV['BUILDKITE']
|
108
|
+
'buildkite'
|
109
|
+
elsif ENV['JENKINS_URL']
|
110
|
+
'jenkins'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def auto_annotate_js_files?
|
115
|
+
case auto_annotate_js_files
|
116
|
+
when :ci
|
117
|
+
!!ci_platform
|
118
|
+
else
|
119
|
+
auto_annotate_js_files
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def auto_annotate_js_files
|
124
|
+
return :ci if @auto_annotate_js_files.nil?
|
125
|
+
@auto_annotate_js_files
|
126
|
+
end
|
127
|
+
|
128
|
+
def auto_annotate_js_files=(value)
|
129
|
+
@auto_annotate_js_files = value.nil? ? !!value : value
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def file_matches_pattern?(file_path, pattern)
|
135
|
+
File.fnmatch?(pattern, file_path, File::Constants::FNM_PATHNAME | File::Constants::FNM_EXTGLOB)
|
136
|
+
end
|
137
|
+
|
138
|
+
def file_matches_any_patterns?(file_path, patterns)
|
139
|
+
patterns.any? { |pattern| file_matches_pattern?(file_path, pattern) }
|
140
|
+
end
|
141
|
+
|
142
|
+
def file_matches_any_negative_patterns?(file_path, negative_patterns)
|
143
|
+
negative_patterns.any? { |pattern| file_matches_pattern?(file_path, pattern[1..-1]) }
|
144
|
+
end
|
145
|
+
|
146
|
+
def filter_from_project_files(patterns)
|
147
|
+
negative_patterns, positive_patterns = patterns.partition { |pattern| pattern.start_with?('!') }
|
148
|
+
|
149
|
+
project_files.select do |file_path|
|
150
|
+
file_matches_any_patterns?(file_path, positive_patterns) &&
|
151
|
+
!file_matches_any_negative_patterns?(file_path, negative_patterns)
|
152
|
+
end.to_set
|
153
|
+
end
|
154
|
+
|
155
|
+
def expand_files(files)
|
156
|
+
files = files.flat_map do |file|
|
157
|
+
if file.is_a?(Proc)
|
158
|
+
file.call
|
159
|
+
elsif file.is_a?(String) && file.start_with?('!')
|
160
|
+
file
|
161
|
+
else
|
162
|
+
Dir.glob(file, base: project_root)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
negative_patterns, files = files.partition { |file| file.is_a?(String) && file.start_with?('!') }
|
167
|
+
|
168
|
+
files = files.reject do |file|
|
169
|
+
file_matches_any_negative_patterns?(file, negative_patterns)
|
170
|
+
end unless negative_patterns.empty?
|
171
|
+
|
172
|
+
files.select do |file_path|
|
173
|
+
File.file?(DiffTest::Helper.expand_path(file_path))
|
174
|
+
end.to_set
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'xxhash'
|
2
|
+
|
3
|
+
module DiffTest
|
4
|
+
class FileHashComputer
|
5
|
+
# Save hashesh in a global cache. If available use it, otherwise compute it.
|
6
|
+
#
|
7
|
+
def self.compute(file_path)
|
8
|
+
return @cache[file_path] if @cache&.key?(file_path)
|
9
|
+
|
10
|
+
content = File.read(file_path)
|
11
|
+
content = DiffTest::Integrations::RailsJs::Annotator.unannotate(content)
|
12
|
+
|
13
|
+
@cache ||= {}
|
14
|
+
@cache[file_path] = XXhash.xxh64(content).to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.compute_relative(file_path)
|
18
|
+
self.compute(DiffTest::Helper.absolute_path_from_project_root(file_path))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module DiffTest
|
2
|
+
module Helper
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def test_id(test_file_path, test_name)
|
6
|
+
[test_file_path, test_name].join(':')
|
7
|
+
end
|
8
|
+
|
9
|
+
def relative_path_from_project_root(file_path)
|
10
|
+
raise 'Expected file_path to be an absolute path' unless file_path.start_with?('/')
|
11
|
+
|
12
|
+
Pathname.new(file_path).relative_path_from(DiffTest.configuration.project_root).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def relative_const_source_path_from_project_root(const_name)
|
16
|
+
relative_path_from_project_root(const_source_path(const_name))
|
17
|
+
end
|
18
|
+
|
19
|
+
def const_source_path(const_name)
|
20
|
+
Module.const_source_location(const_name).first
|
21
|
+
end
|
22
|
+
|
23
|
+
def absolute_path_from_project_root(file_path)
|
24
|
+
File.join(DiffTest.configuration.project_root, file_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def file_in_project?(file_path)
|
28
|
+
file_path &&
|
29
|
+
file_path.start_with?(DiffTest.configuration.project_root) &&
|
30
|
+
!file_path.start_with?(DiffTest.configuration.vendor_bundle_path)
|
31
|
+
end
|
32
|
+
|
33
|
+
def expand_path(file_path)
|
34
|
+
File.expand_path(file_path, DiffTest.configuration.project_root)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative 'file_hash_computer'
|
2
|
+
require_relative 'trackers/ruby_file'
|
3
|
+
require_relative 'trackers/js_file'
|
4
|
+
|
5
|
+
module DiffTest
|
6
|
+
class ImpactedFileTracker
|
7
|
+
attr_reader :trackers
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@trackers = [
|
11
|
+
DiffTest::Trackers::RubyFile.new,
|
12
|
+
DiffTest::Trackers::JsFile.new
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
def save_payload
|
17
|
+
impacted_files.each_with_object({}) do |file_path, payload|
|
18
|
+
payload[file_path] = FileHashComputer.compute(file_path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def impacted_files
|
23
|
+
trackers.map(&:impacted_files).reduce(Set.new, :|)
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
trackers.each(&:enable)
|
28
|
+
end
|
29
|
+
|
30
|
+
def stop
|
31
|
+
trackers.each(&:disable)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DiffTest
|
2
|
+
module Integrations
|
3
|
+
class Integration
|
4
|
+
def supported?
|
5
|
+
Gem.loaded_specs[gem_name]&.version > minimum_compatible_version
|
6
|
+
end
|
7
|
+
|
8
|
+
def gem_name
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def loaded?
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def integrate
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def integrate_if_ready
|
21
|
+
integrate if supported? && loaded?
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.instance
|
25
|
+
@instance ||= new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../integration'
|
2
|
+
require_relative 'lifecycle'
|
3
|
+
|
4
|
+
module DiffTest
|
5
|
+
module Integrations
|
6
|
+
module Minitest
|
7
|
+
class Integration < DiffTest::Integrations::Integration
|
8
|
+
def gem_name
|
9
|
+
'minitest'
|
10
|
+
end
|
11
|
+
|
12
|
+
def minimum_compatible_version
|
13
|
+
'5.0.0'
|
14
|
+
end
|
15
|
+
|
16
|
+
def loaded?
|
17
|
+
supported? && defined?(::Minitest) && defined?(::Minitest::Test)
|
18
|
+
end
|
19
|
+
|
20
|
+
def integrate
|
21
|
+
::Minitest::Test.include(DiffTest::Integrations::Minitest::Lifecycle)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module DiffTest
|
2
|
+
module Integrations
|
3
|
+
module Minitest
|
4
|
+
module Lifecycle
|
5
|
+
def self.included(base)
|
6
|
+
base.prepend(InstanceMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
def before_setup
|
11
|
+
super
|
12
|
+
|
13
|
+
unless DiffTest::TestSuiteExecution.current
|
14
|
+
tests = ::Minitest::Test.runnables.flat_map do |runnable|
|
15
|
+
next if runnable.runnable_methods.empty?
|
16
|
+
|
17
|
+
test_file_path = Helper.relative_const_source_path_from_project_root(runnable.name)
|
18
|
+
|
19
|
+
runnable.runnable_methods.map do |test_name|
|
20
|
+
DiffTest::Helper.test_id(test_file_path, test_name)
|
21
|
+
end
|
22
|
+
end.compact
|
23
|
+
|
24
|
+
test_suite_execution = DiffTest::TestSuiteExecution.find_or_create(tests)
|
25
|
+
|
26
|
+
at_exit do
|
27
|
+
DiffTest::TestSuiteExecution.current.save
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
raise "Expected DiffTest::TestExecution to be nil. Please report this issue." if DiffTest::TestExecution.current
|
32
|
+
|
33
|
+
test_file_path = Helper.relative_const_source_path_from_project_root(self.class.name)
|
34
|
+
test_name = self.name
|
35
|
+
|
36
|
+
DiffTest::TestExecution.current = execution = DiffTest::TestExecution.new(test_file_path:, test_name:)
|
37
|
+
|
38
|
+
if execution.should_run?
|
39
|
+
DiffTest::TestSuiteExecution.current.ensure_application_eager_loaded!
|
40
|
+
else
|
41
|
+
if defined?(ActiveSupport::TestCase) && respond_to?(:run_callbacks)
|
42
|
+
# ActionMailer::TestCase has setup/teardown hook
|
43
|
+
# Since we call skip here, the setup hook won't be called.
|
44
|
+
# This is cause the ActiveSupport::Testcase's before_setup is higher up in the call chain and is invoked first
|
45
|
+
# But if calls super before run_callbacks. which leads to this method being called.
|
46
|
+
# But then since we skip here, we never reach the run_callbacks call because skip raises an exception.
|
47
|
+
run_callbacks(:setup)
|
48
|
+
end
|
49
|
+
skip("Impacted files have not changed. Skipping...")
|
50
|
+
end
|
51
|
+
ensure
|
52
|
+
execution.start
|
53
|
+
end
|
54
|
+
|
55
|
+
def after_teardown
|
56
|
+
execution = DiffTest::TestExecution.current
|
57
|
+
|
58
|
+
if execution.should_run?
|
59
|
+
if skipped?
|
60
|
+
execution.skipped!
|
61
|
+
elsif passed?
|
62
|
+
execution.passed!
|
63
|
+
else
|
64
|
+
execution.failed!
|
65
|
+
end
|
66
|
+
else
|
67
|
+
execution.not_run!
|
68
|
+
end
|
69
|
+
execution.stop
|
70
|
+
DiffTest::TestExecution.current = nil
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|