semaphore_test_boosters 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/test_boosters/cli_parser.rb +15 -0
- data/lib/test_boosters/display_files.rb +9 -0
- data/lib/test_boosters/executor.rb +9 -0
- data/lib/test_boosters/leftover_specs.rb +26 -0
- data/lib/test_boosters/logger.rb +7 -0
- data/lib/test_boosters/rspec_booster.rb +70 -84
- data/lib/test_boosters/version.rb +1 -1
- data/lib/test_boosters.rb +1 -0
- data/script/rspec_booster +8 -0
- data/test_boosters.gemspec +2 -2
- data/test_data/a_spec.rb +1 -0
- data/test_data/b_spec.rb +1 -0
- data/test_data/c_spec.rb +1 -0
- metadata +13 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: de95c3faf8fec6fe5d037d492da9433df3028fa2
|
4
|
+
data.tar.gz: adbee1c687caf014f5145248b6994001365aa61c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3f19dac14a29900d51795f3ed105d70df9f09e4b983b6b78e395bae78d3e18af953b9005a7aa649764be2ad247390dea88d57d6da46a08f8566fe1b4393cc3c
|
7
|
+
data.tar.gz: 7e70e1209987c81c4a92c5d102ad82966e8fc634985f48f81c04da28938f69ac6f0dcf5dedc8e642c14aa02eb7d7c3c4279ad721d3bbe2625a8a0e7c3d55be1d
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module LeftoverSpecs
|
2
|
+
def self.select(all_leftover_specs, thread_count, thread_index)
|
3
|
+
all_leftover_specs = sort_by_size(all_leftover_specs)
|
4
|
+
|
5
|
+
return [] if all_leftover_specs.empty?
|
6
|
+
|
7
|
+
specs = all_leftover_specs
|
8
|
+
.each_slice(thread_count)
|
9
|
+
.reduce{|acc, slice| acc.map{|a| a}.zip(slice.reverse)}
|
10
|
+
.map{|f| if f.kind_of?(Array) then f.flatten else [f] end} [thread_index]
|
11
|
+
|
12
|
+
if specs.nil? then []
|
13
|
+
elsif specs.kind_of?(Array) then specs.compact
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.sort_by_size(specs) # descending
|
18
|
+
specs
|
19
|
+
.map{|f| if File.file?(f) then f else nil end}
|
20
|
+
.compact
|
21
|
+
.map{|f| [f, File.size(f)]}
|
22
|
+
.sort_by{|a| a[1]}.map{|a| a[0]}.reverse
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
@@ -1,87 +1,73 @@
|
|
1
|
-
|
1
|
+
module Semaphore
|
2
|
+
require "json"
|
3
|
+
require "test_boosters/cli_parser"
|
4
|
+
require "test_boosters/logger"
|
5
|
+
require "test_boosters/executor"
|
6
|
+
require "test_boosters/display_files"
|
7
|
+
require "test_boosters/leftover_specs"
|
8
|
+
|
9
|
+
class RspecBooster
|
10
|
+
Error = -1
|
11
|
+
|
12
|
+
def initialize(thread_index)
|
13
|
+
@thread_index = thread_index
|
14
|
+
@report_path = ENV["REPORT_PATH"] || "#{ENV["HOME"]}/rspec_report.json"
|
15
|
+
@spec_path = ENV["SPEC_PATH"] || "spec"
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
specs_to_run = select
|
20
|
+
|
21
|
+
if specs_to_run == Error
|
22
|
+
if @thread_index == 0
|
23
|
+
Semaphore::execute("bundle exec rspec #{@spec_path}")
|
24
|
+
end
|
25
|
+
elsif specs_to_run.empty?
|
26
|
+
puts "No spec files in this thread!"
|
27
|
+
else
|
28
|
+
Semaphore::execute("bundle exec rspec #{specs_to_run.join(" ")}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def select
|
33
|
+
with_fallback do
|
34
|
+
rspec_report = JSON.parse(File.read(@report_path))
|
35
|
+
thread_count = rspec_report.count
|
36
|
+
thread = rspec_report[@thread_index]
|
37
|
+
|
38
|
+
all_specs = Dir["#{@spec_path}/**/*_spec.rb"].sort
|
39
|
+
all_known_specs = rspec_report.map { |t| t["files"] }.flatten.sort
|
40
|
+
|
41
|
+
all_leftover_specs = all_specs - all_known_specs
|
42
|
+
thread_leftover_specs = LeftoverSpecs.select(all_leftover_specs, thread_count, @thread_index)
|
43
|
+
thread_specs = all_specs & thread["files"].sort
|
44
|
+
specs_to_run = thread_specs + thread_leftover_specs
|
45
|
+
|
46
|
+
Semaphore::display_files("This thread specs:", thread_specs)
|
47
|
+
Semaphore::display_files("This thread leftover specs:", thread_leftover_specs)
|
48
|
+
Semaphore::display_files("All leftover specs:", all_leftover_specs)
|
49
|
+
|
50
|
+
specs_to_run
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def with_fallback
|
56
|
+
yield
|
57
|
+
rescue StandardError => e
|
58
|
+
error = %{
|
59
|
+
WARNING: An error detected while parsing the test boosters report file.
|
60
|
+
WARNING: All tests will be executed on the first thread.
|
61
|
+
}
|
62
|
+
|
63
|
+
puts error
|
64
|
+
|
65
|
+
error += %{Exception: #{e.message}}
|
66
|
+
|
67
|
+
Semaphore::log(error)
|
68
|
+
|
69
|
+
Error
|
70
|
+
end
|
2
71
|
|
3
|
-
require "optparse"
|
4
|
-
require "json"
|
5
|
-
|
6
|
-
def log(message)
|
7
|
-
error_log_path = ENV["ERROR_LOG_PATH"] || "#{ENV["HOME"]}/test_booster_error.log"
|
8
|
-
|
9
|
-
File.open(error_log_path, "a") { |f| f.write("#{message}\n") }
|
10
|
-
end
|
11
|
-
|
12
|
-
def display_files(title, files)
|
13
|
-
puts "#{title} #{files.count}\n"
|
14
|
-
|
15
|
-
files.each { |file| puts "- #{file}" }
|
16
|
-
|
17
|
-
puts "\n"
|
18
|
-
end
|
19
|
-
|
20
|
-
def execute(command)
|
21
|
-
log("Running command: #{command}")
|
22
|
-
system(command)
|
23
|
-
log("Command finished, exit status : #{$?.exitstatus}")
|
24
|
-
|
25
|
-
exit($?.exitstatus)
|
26
|
-
end
|
27
|
-
|
28
|
-
def parse_cli_options
|
29
|
-
options = {}
|
30
|
-
|
31
|
-
parser = OptionParser.new do |opts|
|
32
|
-
opts.on("--thread INDEX") { |index| options[:index] = index.to_i }
|
33
|
-
end
|
34
|
-
|
35
|
-
parser.parse!
|
36
|
-
|
37
|
-
options
|
38
|
-
end
|
39
|
-
|
40
|
-
def with_fallback
|
41
|
-
yield
|
42
|
-
rescue StandardError => e
|
43
|
-
error = %{
|
44
|
-
WARNING: An error detected while parsing the test boosters report file.
|
45
|
-
WARNING: All tests will be executed on the first thread.
|
46
|
-
}
|
47
|
-
|
48
|
-
puts error
|
49
|
-
|
50
|
-
error += %{
|
51
|
-
Exception:
|
52
|
-
#{e.message}
|
53
|
-
}
|
54
|
-
|
55
|
-
log(error)
|
56
|
-
|
57
|
-
execute("bundle exec rspec") if $cli_options[:index] == 1
|
58
|
-
end
|
59
|
-
|
60
|
-
$cli_options = parse_cli_options
|
61
|
-
|
62
|
-
report_path = ENV["REPORT_PATH"] || "#{ENV["HOME"]}/rspec_report.json"
|
63
|
-
spec_path = ENV["SPEC_PATH"] || "spec"
|
64
|
-
|
65
|
-
with_fallback do
|
66
|
-
rspec_report = JSON.parse(File.read(report_path))
|
67
|
-
|
68
|
-
thread = rspec_report[$cli_options[:index] - 1]
|
69
|
-
|
70
|
-
all_specs = Dir["#{spec_path}/**/*_spec.rb"].sort
|
71
|
-
all_known_specs = rspec_report.map { |t| t["files"] }.flatten.sort
|
72
|
-
|
73
|
-
leftover_specs = all_specs - all_known_specs
|
74
|
-
thread_specs = all_specs & thread["files"].sort
|
75
|
-
specs_to_run = thread_specs + (thread["run_leftover_files"] ? leftover_specs : [])
|
76
|
-
|
77
|
-
display_files("Thread specs:", thread_specs)
|
78
|
-
|
79
|
-
display_files("Leftover specs:", leftover_specs) if thread["run_leftover_files"]
|
80
|
-
|
81
|
-
if specs_to_run.empty?
|
82
|
-
puts "No spec files in this thread!"
|
83
|
-
exit
|
84
72
|
end
|
85
|
-
|
86
|
-
execute("bundle exec rspec #{specs_to_run.join(" ")}")
|
87
73
|
end
|
data/lib/test_boosters.rb
CHANGED
data/test_boosters.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'test_boosters/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "semaphore_test_boosters"
|
8
8
|
spec.version = TestBoosters::VERSION
|
9
|
-
spec.authors = ["
|
10
|
-
spec.email = ["
|
9
|
+
spec.authors = ["MAINTAINER Rendered Text"]
|
10
|
+
spec.email = ["devops@renderedtext.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Semaphore job parallelization.}
|
13
13
|
spec.description = %q{Gem for auto-parallelizing builds across Semaphore jobs.}
|
data/test_data/a_spec.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
12345678901234567890
|
data/test_data/b_spec.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
123
|
data/test_data/c_spec.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
123456789
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: semaphore_test_boosters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- MAINTAINER Rendered Text
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '3.0'
|
55
55
|
description: Gem for auto-parallelizing builds across Semaphore jobs.
|
56
56
|
email:
|
57
|
-
-
|
57
|
+
- devops@renderedtext.com
|
58
58
|
executables: []
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
@@ -69,9 +69,18 @@ files:
|
|
69
69
|
- bin/console
|
70
70
|
- bin/setup
|
71
71
|
- lib/test_boosters.rb
|
72
|
+
- lib/test_boosters/cli_parser.rb
|
73
|
+
- lib/test_boosters/display_files.rb
|
74
|
+
- lib/test_boosters/executor.rb
|
75
|
+
- lib/test_boosters/leftover_specs.rb
|
76
|
+
- lib/test_boosters/logger.rb
|
72
77
|
- lib/test_boosters/rspec_booster.rb
|
73
78
|
- lib/test_boosters/version.rb
|
79
|
+
- script/rspec_booster
|
74
80
|
- test_boosters.gemspec
|
81
|
+
- test_data/a_spec.rb
|
82
|
+
- test_data/b_spec.rb
|
83
|
+
- test_data/c_spec.rb
|
75
84
|
homepage: https://github.com/renderedtext/test-boosters
|
76
85
|
licenses:
|
77
86
|
- MIT
|