selective-ruby-core 0.1.6-x86_64-darwin → 0.1.7-x86_64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/bin/file_correlation_collector.sh +141 -0
- data/lib/selective/ruby/core/controller.rb +32 -78
- data/lib/selective/ruby/core/file_correlator.rb +38 -0
- data/lib/selective/ruby/core/helper.rb +76 -0
- data/lib/selective/ruby/core/version.rb +1 -1
- data/lib/selective-ruby-core.rb +4 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bcee1f0c11ea957dd90a8f41b3c53fe7975117ff67e2e90ef961d1f8658e7a1
|
4
|
+
data.tar.gz: 0e37f18b4198d04bf58855db13b8a4f24a0d9be535938b08543738064e3fec93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de3efdfdea2c7fe2f2556c6ae2679f6239a1b8c89ef0b6b081ef7137fc98f0a1a1ef14c1b7da6d286dffd57c1ff30478e7cc7d97475b385e46508ed34a3a3ec0
|
7
|
+
data.tar.gz: 1d9d4d0c260981f3cff61bb1d02e669925c3aa94d2e323a9866d074d4c10c65b2a6fd20472ddce1ca42969081368160e615e837385b7e0988810dff93c45fc48
|
@@ -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
|
-
|
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
|
-
|
282
|
-
|
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
|
295
|
-
|
296
|
-
|
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
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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
|
+
[]
|
309
|
+
end
|
310
|
+
end
|
349
311
|
end
|
350
312
|
|
351
|
-
def
|
352
|
-
@
|
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
|
data/lib/selective-ruby-core.rb
CHANGED
@@ -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.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: x86_64-darwin
|
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-
|
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
|