affected_tests 0.1.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af75eb73948c85a496715e0ea5f27610a1edb9ad9db22ddf1529122bc9129fcf
4
- data.tar.gz: 812ebcd3b665254bfc365e10537896bec4d84bbca4efd17b5de46bfa73ed0346
3
+ metadata.gz: fbb2179c4fffe41e99f31697dc10b161f5d0063776a4e844b88591013c33a97c
4
+ data.tar.gz: 1c4b1596a80fea2d05dc754d4ddc7219843dacb53b022afd0ddab06acc663c31
5
5
  SHA512:
6
- metadata.gz: 90130e1a9102afb5afae71d4b0f14bb024c35ae44f807fd8c3fc75d7f143d14636854c84bb67bebfbd5970bc7326b2968cd2f2997345d86d5be41897ec312ab7
7
- data.tar.gz: e4d4f3879148330499743228daf4facabd030a4cd799c3a92bb95f99886bb86760d5f77385037fd5b3982c5d7e3546462fc1f4def93eb7ec048e047a2dc52f3b
6
+ metadata.gz: 58d176dc48c68f09fa0ff3a610879e1c3c90d6d360eb33cc2b48306810996a7dd762b7490dc47fd63c9bddee22a44005bfbce7262c88043ab4352e41ead236bc
7
+ data.tar.gz: 484bade7034e6ccf3259dd84419b2c80cac33f17a0171f842d59d1cad5d2db252dbaf487ec6082cead83bca000ea2540ee718963d6562c7ba4b8a336f7a5d28b
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- affected_tests (0.1.0)
5
- calleree
4
+ affected_tests (0.3.0)
5
+ rotoscope
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- calleree (0.1.0)
11
10
  rake (13.0.6)
11
+ rotoscope (0.3.0)
12
12
 
13
13
  PLATFORMS
14
- arm64-darwin-21
14
+ ruby
15
15
 
16
16
  DEPENDENCIES
17
17
  affected_tests!
data/README.md CHANGED
@@ -29,10 +29,28 @@ require "affected_tests/rspec"
29
29
  AffectedTests.setup(
30
30
  project_path: File.expand_path("../../", __FILE__),
31
31
  test_dir_path: "spec/",
32
- output_path: "log/affected-tests-map.json"
32
+ output_path: "log/affected-tests-map.json",
33
+ revision: "1cf22fdb86e2b2d6107" # or git rev-parse HEAD > REVISION
33
34
  )
34
35
  ```
35
36
 
37
+ this will write associated test files per file on `log/affected-tests-map.json`:
38
+
39
+ ```json
40
+ {
41
+ "revision": "1cf22fdb86e2b2d6107",
42
+ "map": {
43
+ "app/controllers/comments_controller.rb": [
44
+ "spec/requests/comments_spec.rb"
45
+ ],
46
+ "app/views/comments/index.html.erb": [
47
+ "spec/requests/comments_spec.rb",
48
+ "spec/views/comments/index.html.erb_spec.rb"
49
+ ]
50
+ }
51
+ }
52
+ ```
53
+
36
54
  ### Get Diff
37
55
 
38
56
  #### Schema
@@ -76,6 +94,17 @@ pp target_tests
76
94
 
77
95
  See also: `scripts/calculate-target-tests`
78
96
 
97
+ #### Merge results from parallel test
98
+
99
+ ```
100
+ require "affected_tests/map_merger"
101
+
102
+ AffectedTests::MapMerger.run(
103
+ map_file_paths: %w[node1-result.json node2-result.json node3-result.json],
104
+ output_path: "merged-result.json"
105
+ )
106
+ ```
107
+
79
108
  ## Development
80
109
 
81
110
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "set"
5
+
6
+ module AffectedTests
7
+ module MapMerger
8
+ module_function
9
+
10
+ def run(map_file_paths:, output_path:)
11
+ map_infos = map_file_paths.map do |map_file_path|
12
+ JSON.parse(File.read(map_file_path))
13
+ end
14
+
15
+ revisions = map_infos.map { |map_info| map_info["revision"] }.uniq
16
+ raise "map files weren't generated by same revision" if revisions.size != 1
17
+
18
+ keys = map_infos.flat_map { |map_info| map_info["map"].keys }.uniq
19
+
20
+ result_map = {}
21
+ keys.each do |key|
22
+ map_infos.each do |map_info|
23
+ map = map_info["map"]
24
+ next if map[key].nil?
25
+
26
+ result_map[key] ||= Set.new
27
+ map[key].each do |test_file_path|
28
+ result_map[key] << test_file_path
29
+ end
30
+ end
31
+ end
32
+
33
+ result = {
34
+ revision: revisions.first,
35
+ map: result_map.transform_values(&:to_a)
36
+ }
37
+
38
+ File.write(output_path, JSON.dump(result))
39
+ end
40
+ end
41
+ end
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.configure do |config|
4
- config.before(:suite) do
5
- AffectedTests.start
4
+ config.prepend_before(:each) do
5
+ AffectedTests.start_trace
6
6
  end
7
7
 
8
- config.after(:each) do
8
+ config.append_after(:each) do
9
+ AffectedTests.stop_trace
9
10
  target_spec = self.class.declaration_locations.last[0]
10
- AffectedTests.emit(target_spec)
11
+ AffectedTests.checkpoint(target_spec)
11
12
  end
12
13
 
13
14
  config.after(:suite) do
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AffectedTests
4
- VERSION = "0.1.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -3,61 +3,62 @@
3
3
  require "set"
4
4
  require "json"
5
5
 
6
- require "calleree"
6
+ require "rotoscope"
7
7
 
8
8
  require_relative "affected_tests/version"
9
9
 
10
10
  module AffectedTests
11
11
  module_function
12
12
 
13
- def setup(project_path:, test_dir_path:, output_path:)
13
+ def setup(project_path:, test_dir_path:, output_path:, revision: nil)
14
14
  @project_path = project_path
15
15
  @test_dir_path = test_dir_path
16
16
  @output_path = output_path
17
+ @revision = revision || build_revision
18
+ @rotoscope = Rotoscope.new do |call|
19
+ next if self == call.receiver
20
+
21
+ if call.caller_path && target_path?(call.caller_path)
22
+ buffer << call.caller_path
23
+ end
24
+ end
17
25
  end
18
26
 
19
- def start
20
- Calleree.start
27
+ def start_trace
28
+ @rotoscope.start_trace
21
29
  end
22
30
 
23
- def import_from_calleree(target_test_path, result)
24
- caller_in_project = result.select do |(caller_info, _callee_info, _count)|
25
- caller_path = caller_info.first
26
- target_path?(caller_path)
27
- end.map do |(caller_info, _callee_info, _count)|
28
- format_path(caller_info.first)
29
- end
31
+ def stop_trace
32
+ @rotoscope.stop_trace
33
+ end
30
34
 
31
- called_in_project = result.select do |(_caller_info, callee_info, _count)|
32
- callee_path = callee_info.first
33
- target_path?(callee_path)
34
- end.map do |(_caller_info, callee_info, _count)|
35
- format_path(callee_info.first)
35
+ def import_from_rotoscope(target_test_path, result)
36
+ all_related_paths = result.uniq.map do |caller_path|
37
+ format_path(caller_path)
36
38
  end
37
39
 
38
- all_related_paths = (called_in_project + caller_in_project).uniq
39
-
40
- target_test_file_path = format_path(target_test_path)
40
+ formatted_target_test_path = format_path(target_test_path)
41
41
 
42
42
  all_related_paths.each do |path|
43
43
  next if path.start_with?(@test_dir_path)
44
44
 
45
- if path != target_test_file_path
46
- add(target_test_file_path, path)
45
+ if path != formatted_target_test_path
46
+ add(formatted_target_test_path, path)
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
- def emit(target_test_path)
52
- res = Calleree.result(clear: true)
53
- import_from_calleree(target_test_path, res)
51
+ def checkpoint(target_test_path)
52
+ diff = buffer
53
+ import_from_rotoscope(target_test_path, diff)
54
+ buffer.clear
54
55
  end
55
56
 
56
57
  def dump
57
- data = { revision: revision, map: cache.transform_values(&:to_a) }
58
+ data = { revision: @revision, map: cache.transform_values(&:to_a) }
58
59
  File.write(@output_path, JSON.dump(data))
59
60
  ensure
60
- Calleree.stop
61
+ @rotoscope.stop_trace if @rotoscope.tracing?
61
62
  end
62
63
 
63
64
  def format_path(path)
@@ -73,17 +74,25 @@ module AffectedTests
73
74
  cache[callee].add(caller)
74
75
  end
75
76
 
76
- def revision
77
- revision_path = File.expand_path("../../REVISION", __FILE__)
78
- if File.exist?(revision_path)
79
- File.read(revision_path).strip
77
+ def build_revision
78
+ if defined? Rails
79
+ path = Rails.root.join("REVISION")
80
+ if path.exist?
81
+ path.read.chomp
82
+ else
83
+ "UNKNOWN"
84
+ end
80
85
  else
81
86
  "UNKNOWN"
82
87
  end
83
88
  end
84
89
 
90
+ def buffer
91
+ Thread.current[:buffer] ||= []
92
+ end
93
+
85
94
  def cache
86
- @cache ||= {}
95
+ Thread.current[:cache] ||= {}
87
96
  end
88
97
 
89
98
  def bundler_path
@@ -15,11 +15,23 @@ target_sha = ARGV.shift
15
15
 
16
16
  client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
17
17
 
18
- targets = client.compare(repository, base_sha, target_sha).files.map do |info|
19
- {
20
- filename: info.filename,
21
- status: info.status
22
- }
18
+ targets = client.compare(repository, base_sha, target_sha).files.each_with_object([]) do |info, arr|
19
+ # https://docs.github.com/en/rest/commits/commits#get-a-commit
20
+ case info.status
21
+ when "modified", "added", "removed"
22
+ arr << { filename: info.filename, status: info.status }
23
+ when "renamed"
24
+ arr << { filename: info.filename, status: "added" }
25
+ arr << { filename: info.previous_filename, status: "removed" }
26
+ when "copied"
27
+ arr << { filename: info.filename, status: "added" }
28
+ when "changed"
29
+ arr << { filename: info.filename, status: "modified" }
30
+ when "unchanged"
31
+ # do nothing
32
+ else
33
+ raise "Unknown status: #{info.status}"
34
+ end
23
35
  end
24
36
 
25
37
  puts JSON.dump(targets)
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: affected_tests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-19 00:00:00.000000000 Z
11
+ date: 2022-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: calleree
14
+ name: rotoscope
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -39,6 +39,7 @@ files:
39
39
  - Rakefile
40
40
  - lib/affected_tests.rb
41
41
  - lib/affected_tests/differ.rb
42
+ - lib/affected_tests/map_merger.rb
42
43
  - lib/affected_tests/rspec.rb
43
44
  - lib/affected_tests/version.rb
44
45
  - scripts/calculate-target-tests