selective-ruby-core 0.1.6-x86_64-linux → 0.1.8-x86_64-linux

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ec7acf96ff854b3c63a2c89560440378444ec9544694bb4c2107b456c067bcb
4
- data.tar.gz: c607a7497f234d12f5d7d5011e125a9734f31e0a8ef0070767149bb7dc48a059
3
+ metadata.gz: 8fc1593cbdf10f86bea4aa1bda2da083d9adbd598a5a4c18898968b214b32a6b
4
+ data.tar.gz: 1974dcafb418d40f3434a5b97c0afb50f3cadb50da7bea4d2687ea2199723657
5
5
  SHA512:
6
- metadata.gz: 3c653ea2a4a1cf52ff46e27715619fa70ff20d26fa6f3b363486fef7832f25140a033475af9050d8da912cf5c0e10e69501bb1f040b1766e999ccc0527d7c99c
7
- data.tar.gz: 86060d98bb070045ba93ebc1d9cd2949d5d5c5cf0f09a99598e732a1c610164f3a9548d69a2d965e90d360d31255b13567f1fbf10e3ac2e8ef922474d046ddd0
6
+ metadata.gz: 753cf27d67588c65727223edc78821eb2e0b03921466bec6b952a4c9299c45c04e43584cd7412f9b4cc1398d481b3cac0ebdf7149f88548c05c3223386d0d734
7
+ data.tar.gz: 36940e88e60ee06fbad277099ceafcef7677ba8be9d7a82a61df1afd3dd6b09d458cb806f13de80542177a35332d6d9be440777b3039cd4702a503f2e9f8742f
@@ -0,0 +1,141 @@
1
+ #!/bin/bash
2
+
3
+ # The first argument is the number of commits to process
4
+ branch=$1
5
+ num_commits=$2
6
+
7
+ # Initialize an associative array to hold the files to check
8
+ declare -A files_to_check
9
+
10
+ # Populate the array with the script arguments, starting from the second argument
11
+ for file in "${@:3}"
12
+ do
13
+ files_to_check["$file"]=1
14
+ done
15
+
16
+ # Get a list of all commit hashes, in reverse order
17
+ all_commits=$(git log origin/$branch --no-merges --format=%H --reverse -n $num_commits)
18
+
19
+ # Initialize an associative array to store the test files
20
+ declare -A test_files
21
+ declare -A uncorrelated_test_files
22
+
23
+ # Initialize an array to store the files changed in the previous commit
24
+ prev_changed_files=()
25
+
26
+ # For each commit...
27
+ for commit in $all_commits
28
+ do
29
+ # Get a list of all files that were changed in the current commit
30
+ files=$(git diff-tree --no-commit-id --name-only -r $commit)
31
+
32
+ declare -A correlated_test_files
33
+
34
+ # # For each file in the list of files changed in the previous commit...
35
+ for file in "${prev_changed_files[@]}"
36
+ do
37
+ # If the file is in the list of files to check...
38
+ if [[ ${files_to_check[$file]} ]]; then
39
+ # For each file...
40
+ for test_file in $files
41
+ do
42
+ # If the file is in the test/ directory and ends with _test.rb...
43
+ if [[ $test_file == spec/*_spec.rb ]]
44
+ then
45
+ # Increment the count in the associative array
46
+ test_files["$file|$test_file"]=$((test_files["$file|$test_file"]+1))
47
+ # Add the test file to the correlated_test_files array
48
+ correlated_test_files["$test_file"]=1
49
+ fi
50
+ done
51
+ fi
52
+ done
53
+
54
+ # For each file in the list of files changed in the current commit...
55
+ for file in $files
56
+ do
57
+ # If the file is in the list of files to check...
58
+ if [[ ${files_to_check[$file]} ]]; then
59
+ # For each file...
60
+ for test_file in $files
61
+ do
62
+ # If the file is in the test/ directory and ends with _test.rb...
63
+ if [[ $test_file == spec/*_spec.rb ]]
64
+ then
65
+ # Increment the count in the associative array
66
+ test_files["$file|$test_file"]=$((test_files["$file|$test_file"]+1))
67
+ # Add the test file to the correlated_test_files array
68
+ correlated_test_files["$test_file"]=1
69
+ fi
70
+ done
71
+ fi
72
+ done
73
+
74
+ # For each file...
75
+ for test_file in $files
76
+ do
77
+ # If the file is in the test/ directory and ends with _test.rb...
78
+ if [[ $test_file == spec/*_spec.rb ]]
79
+ then
80
+ # If the test file is not correlated to any of the files to check in the current commit...
81
+ if [[ -z ${correlated_test_files[$test_file]} ]]
82
+ then
83
+ # Increment the count in the associative array
84
+ uncorrelated_test_files["$test_file"]=$((uncorrelated_test_files["$test_file"]+1))
85
+ fi
86
+ fi
87
+ done
88
+
89
+ # Clear the correlated_test_files array for the next commit
90
+ unset correlated_test_files
91
+
92
+ # Store the list of files changed in this commit for the next iteration
93
+ prev_changed_files=($files)
94
+ done
95
+
96
+ # OUTPUT
97
+
98
+ # Initialize an associative array to hold the JSON strings for each file
99
+ declare -A file_jsons
100
+
101
+ # Add the test_files to the file_jsons associative array
102
+ for key in "${!test_files[@]}"
103
+ do
104
+ file=${key%|*}
105
+ test_file=${key#*|}
106
+ count=${test_files[$key]}
107
+ # Append to the JSON string for this file
108
+ file_jsons["$file"]+="\"$test_file\": $count,"
109
+ done
110
+
111
+ # Initialize an empty string for the test_files JSON
112
+ correlated_files_json=""
113
+
114
+ # Add the file_jsons to the correlated_files_json string
115
+ for file in "${!file_jsons[@]}"
116
+ do
117
+ # Remove the trailing comma from the JSON string for this file
118
+ file_json=${file_jsons[$file]%?}
119
+ # Append to the correlated_files_json string
120
+ correlated_files_json+="\"$file\": { $file_json },"
121
+ done
122
+
123
+ # Remove the trailing comma from the correlated_files_json string
124
+ correlated_files_json=${correlated_files_json%?}
125
+
126
+ # Initialize an empty string for the uncorrelated_test_files JSON
127
+ uncorrelated_files_json=""
128
+
129
+ # Add the uncorrelated_test_files to the uncorrelated_files_json string
130
+ for key in "${!uncorrelated_test_files[@]}"
131
+ do
132
+ count=${uncorrelated_test_files[$key]}
133
+ # Append to the uncorrelated_files_json string
134
+ uncorrelated_files_json+="\"$key\": $count,"
135
+ done
136
+
137
+ # Remove the trailing comma from the uncorrelated_files_json string
138
+ uncorrelated_files_json=${uncorrelated_files_json%?}
139
+
140
+ # Output the JSON
141
+ echo "{ \"correlated_files\": { $correlated_files_json }, \"uncorrelated_files\": { $uncorrelated_files_json } }"
@@ -1,13 +1,12 @@
1
1
  require "logger"
2
2
  require "uri"
3
- require "json"
4
3
  require "fileutils"
5
- require "open3"
6
4
 
7
5
  module Selective
8
6
  module Ruby
9
7
  module Core
10
8
  class Controller
9
+ include Helper
11
10
  @@selective_suppress_reporting = false
12
11
 
13
12
  def initialize(runner, debug: false, log: false)
@@ -51,9 +50,7 @@ module Selective
51
50
 
52
51
  private
53
52
 
54
- attr_reader :runner, :pipe, :transport_pid, :retries, :logger, :runner_id
55
-
56
- ROOT_GEM_PATH = Gem.loaded_specs["selective-ruby-core"].full_gem_path
53
+ attr_reader :runner, :pipe, :transport_pid, :retries, :logger, :runner_id, :diff
57
54
 
58
55
  def get_runner_id
59
56
  runner_id = build_env.delete("runner_id")
@@ -242,7 +239,11 @@ module Selective
242
239
  self.class.restore_reporting!
243
240
  @logger.info("Sending Response: test_manifest")
244
241
  data = {test_cases: runner.manifest["examples"]}
245
- data[:modified_test_files] = modified_test_files unless modified_test_files.nil?
242
+ num_commits = build_env["num_commits"] || 1000
243
+ if (diff = get_diff(num_commits))
244
+ data[:modified_test_files] = modified_test_files(diff)
245
+ data[:correlated_files] = correlated_files(diff, num_commits)
246
+ end
246
247
  write({type: "test_manifest", data: data})
247
248
  end
248
249
 
@@ -271,93 +272,46 @@ module Selective
271
272
  :break
272
273
  end
273
274
 
275
+ def correlated_files(diff, num_commits)
276
+ Selective::Ruby::Core::FileCorrelator.new(diff, num_commits, build_env["target_branch"]).correlate
277
+ end
278
+
274
279
  def test_case_callback(test_case)
275
280
  @logger.info("Sending Response: test_case_result: #{test_case[:id]}")
276
281
  write({type: "test_case_result", data: test_case})
277
282
  end
278
283
 
279
- def modified_test_files
284
+ def modified_test_files(diff)
280
285
  @modified_test_files ||= begin
281
- target_branch = build_env["target_branch"]
282
- return [] if target_branch.nil? || target_branch.empty?
283
-
284
- output, status = Open3.capture2e("git diff #{target_branch} --name-only")
285
-
286
- if status.success?
287
- output.split("\n").filter do |f|
288
- f.match?(/^#{runner.base_test_path}/)
289
- end
286
+ diff.filter do |f|
287
+ f.match?(/^#{runner.base_test_path}/)
290
288
  end
291
289
  end
292
290
  end
293
291
 
294
- def debug?
295
- @debug
296
- end
292
+ def get_diff(num_commits)
293
+ target_branch = build_env["target_branch"]
294
+ return if target_branch.nil? || target_branch.empty?
297
295
 
298
- def safe_filename(filename)
299
- filename
300
- .gsub(/[\/\\:*?"<>|\n\r]+/, '_')
301
- .gsub(/^\.+|\.+$/, '')
302
- .strip[0, 255]
303
- end
304
-
305
- def with_error_handling(include_header: true)
306
- yield
307
- rescue => e
308
- raise e if debug?
309
- header = <<~TEXT
310
- An error occurred. Please rerun with --debug
311
- and contact support at https://selective.ci/support
312
- TEXT
313
-
314
- unless @banner_displayed
315
- header = <<~TEXT
316
- #{banner}
317
-
318
- #{header}
319
- TEXT
296
+ Open3.capture2e("git fetch origin #{target_branch} --depth=#{num_commits}").then do |output, status|
297
+ unless status.success?
298
+ print_warning "Selective was unable to fetch the target branch. This may result in a sub-optimal test order. If the issue persists, please contact support. The output was:\n\n#{output}"
299
+ return
300
+ end
320
301
  end
321
302
 
322
- puts_indented <<~TEXT
323
- \e[31m
324
- #{header if include_header}
325
- #{e.message}
326
- \e[0m
327
- TEXT
328
-
329
- exit 1
330
- end
331
-
332
- def print_warning(message)
333
- puts_indented <<~TEXT
334
- \e[33m
335
- #{message}
336
- \e[0m
337
- TEXT
338
- end
339
-
340
- def print_notice(message)
341
- puts_indented <<~TEXT
342
- #{banner}
343
- #{message}
344
- TEXT
345
- end
346
-
347
- def puts_indented(text)
348
- puts text.gsub(/^/, " ")
303
+ Open3.capture2e("git diff origin/#{target_branch} --name-only").then do |output, status|
304
+ if status.success?
305
+ output.split("\n")
306
+ else
307
+ print_warning "Selective was unable to diff with the target branch. This may result in a sub-optimal test order. If the issue persists, please contact support. The output was:\n\n#{output}"
308
+ nil
309
+ end
310
+ end
349
311
  end
350
312
 
351
- def banner
352
- @banner_displayed = true
353
- <<~BANNER
354
- ____ _ _ _
355
- / ___| ___| | ___ ___| |_(_)_ _____
356
- \\___ \\ / _ \\ |/ _ \\/ __| __| \\ \\ / / _ \\
357
- ___) | __/ | __/ (__| |_| |\\ V / __/
358
- |____/ \\___|_|\\___|\\___|\\__|_| \\_/ \\___|
359
- ________________________________________
360
- BANNER
313
+ def debug?
314
+ @debug
361
315
  end
362
316
  end
363
317
  end
@@ -0,0 +1,38 @@
1
+ module Selective
2
+ module Ruby
3
+ module Core
4
+ class FileCorrelator
5
+ include Helper
6
+
7
+ class FileCorrelatorError < StandardError; end
8
+
9
+ FILE_CORRELATION_COLLECTOR_PATH = File.join(ROOT_GEM_PATH, "lib", "bin", "file_correlation_collector.sh")
10
+
11
+ def initialize(diff, num_commits, target_branch)
12
+ @diff = diff
13
+ @num_commits = num_commits
14
+ @target_branch = target_branch
15
+ end
16
+
17
+ def correlate
18
+ JSON.parse(get_correlated_files, symbolize_names: true)
19
+ rescue FileCorrelatorError, JSON::ParserError
20
+ print_warning "Selective was unable to correlate the diff to test files. This may result in a sub-optimal test order. If the issue persists, please contact support."
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :diff, :num_commits, :target_branch
26
+
27
+ def get_correlated_files
28
+ Open3.capture2e("#{FILE_CORRELATION_COLLECTOR_PATH} #{target_branch} #{num_commits} #{diff.join(" ")}").then do |output, status|
29
+
30
+ raise FileCorrelatorError unless status.success?
31
+
32
+ output
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,76 @@
1
+ module Selective
2
+ module Ruby
3
+ module Core
4
+ module Helper
5
+ def safe_filename(filename)
6
+ filename
7
+ .gsub(/[\/\\:*?"<>|\n\r]+/, '_')
8
+ .gsub(/^\.+|\.+$/, '')
9
+ .strip[0, 255]
10
+ end
11
+
12
+ def with_error_handling(include_header: true)
13
+ yield
14
+ rescue => e
15
+ raise e if debug?
16
+ header = <<~TEXT
17
+ An error occurred. Please rerun with --debug
18
+ and contact support at https://selective.ci/support
19
+ TEXT
20
+
21
+ unless $selective_banner_displayed
22
+ header = <<~TEXT
23
+ #{banner}
24
+
25
+ #{header}
26
+ TEXT
27
+ end
28
+
29
+ puts_indented <<~TEXT
30
+ \e[31m
31
+ #{header if include_header}
32
+ #{e.message}
33
+ \e[0m
34
+ TEXT
35
+
36
+ exit 1
37
+ end
38
+
39
+ def print_warning(message)
40
+ puts_indented <<~TEXT
41
+ \e[33m
42
+ #{message}
43
+ \e[0m
44
+ TEXT
45
+ end
46
+
47
+ def print_notice(message)
48
+ puts_indented <<~TEXT
49
+ #{banner unless $selective_banner_displayed}
50
+ #{message}
51
+ TEXT
52
+ end
53
+
54
+ def puts_indented(text)
55
+ puts text.gsub(/^/, " ")
56
+ end
57
+
58
+ def banner
59
+ Helper.banner
60
+ end
61
+
62
+ def self.banner
63
+ $selective_banner_displayed = true
64
+ <<~BANNER
65
+ ____ _ _ _
66
+ / ___| ___| | ___ ___| |_(_)_ _____
67
+ \\___ \\ / _ \\ |/ _ \\/ __| __| \\ \\ / / _ \\
68
+ ___) | __/ | __/ (__| |_| |\\ V / __/
69
+ |____/ \\___|_|\\___|\\___|\\__|_| \\_/ \\___|
70
+ ________________________________________
71
+ BANNER
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -3,7 +3,7 @@
3
3
  module Selective
4
4
  module Ruby
5
5
  module Core
6
- VERSION = "0.1.6"
6
+ VERSION = "0.1.8"
7
7
  end
8
8
  end
9
9
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "zeitwerk"
4
+ require "json"
5
+ require "open3"
4
6
  require "#{__dir__}/selective/ruby/core/version"
5
7
 
6
8
  loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
@@ -13,6 +15,8 @@ module Selective
13
15
  module Core
14
16
  class Error < StandardError; end
15
17
 
18
+ ROOT_GEM_PATH = Gem.loaded_specs["selective-ruby-core"].full_gem_path
19
+
16
20
  @@available_runners = {}
17
21
 
18
22
  def self.register_runner(name, runner_class)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selective-ruby-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Benjamin Wood
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2024-01-04 00:00:00.000000000 Z
12
+ date: 2024-01-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: zeitwerk
@@ -41,9 +41,12 @@ files:
41
41
  - Rakefile
42
42
  - exe/selective
43
43
  - lib/bin/build_env.sh
44
+ - lib/bin/file_correlation_collector.sh
44
45
  - lib/bin/transport
45
46
  - lib/selective-ruby-core.rb
46
47
  - lib/selective/ruby/core/controller.rb
48
+ - lib/selective/ruby/core/file_correlator.rb
49
+ - lib/selective/ruby/core/helper.rb
47
50
  - lib/selective/ruby/core/named_pipe.rb
48
51
  - lib/selective/ruby/core/version.rb
49
52
  homepage: https://www.selective.ci