semaphore_test_boosters 1.3.0 → 1.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 +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +91 -0
- data/Gemfile +1 -1
- data/README.md +3 -1
- data/config/cucumber.yml +11 -1
- data/config.reek +63 -0
- data/exe/cucumber_booster +1 -1
- data/exe/rspec_booster +4 -8
- data/lib/test_boosters/cucumber_booster.rb +2 -2
- data/lib/test_boosters/insights_uploader.rb +14 -11
- data/lib/test_boosters/leftover_files.rb +3 -3
- data/lib/test_boosters/logger.rb +2 -2
- data/lib/test_boosters/rspec/booster.rb +54 -0
- data/lib/test_boosters/rspec/thread.rb +71 -0
- data/lib/test_boosters/shell.rb +14 -3
- data/lib/test_boosters/split_configuration.rb +12 -9
- data/lib/test_boosters/version.rb +1 -1
- data/lib/test_boosters.rb +2 -2
- data/test_boosters.gemspec +6 -1
- metadata +64 -5
- data/lib/test_boosters/rspec_booster.rb +0 -80
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b7102ce7a40af8dd1a56a451ccd2f3a79720be8a
|
|
4
|
+
data.tar.gz: 0e8af9b06e44e05732e5e4d21afe2bd540cdb358
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 184e035c879e44f5eb661926894c6b60a11c66456a72d99400177260a442908d208c9623b12879ca16cc1dc7bed5d96ee95d98fbf73813e658a66c990f870665
|
|
7
|
+
data.tar.gz: a1f953fa9171e245aa2dfa9d879cc097350ab76c1f1345dce1d1890b89bb9f79f235f832b2aceacad858f7ebc764a4648b77103e78ebd328641c454dc2e6b9b5
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require: rubocop-rspec
|
|
2
|
+
|
|
3
|
+
AllCops:
|
|
4
|
+
DisplayCopNames: true
|
|
5
|
+
|
|
6
|
+
Exclude:
|
|
7
|
+
- "*.gemspec"
|
|
8
|
+
- "vendor/**/*"
|
|
9
|
+
- "lib/test_boosters/cucumber_booster.rb"
|
|
10
|
+
- "test_data_pass/**/*"
|
|
11
|
+
- "test_data_fail/**/*"
|
|
12
|
+
|
|
13
|
+
Style/StringLiterals:
|
|
14
|
+
EnforcedStyle: double_quotes
|
|
15
|
+
|
|
16
|
+
Style/StringLiteralsInInterpolation:
|
|
17
|
+
EnforcedStyle: double_quotes
|
|
18
|
+
|
|
19
|
+
Style/NumericLiterals:
|
|
20
|
+
Enabled: false
|
|
21
|
+
|
|
22
|
+
Style/Documentation:
|
|
23
|
+
Enabled: false
|
|
24
|
+
|
|
25
|
+
Style/HashSyntax:
|
|
26
|
+
EnforcedStyle: hash_rockets
|
|
27
|
+
|
|
28
|
+
Style/CollectionMethods:
|
|
29
|
+
StyleGuide: "https://github.com/bbatsov/ruby-style-guide#map-find-select-reduce-size"
|
|
30
|
+
Enabled: true
|
|
31
|
+
|
|
32
|
+
Metrics/LineLength:
|
|
33
|
+
Max: 120
|
|
34
|
+
|
|
35
|
+
Style/EmptyLinesAroundClassBody:
|
|
36
|
+
Enabled: false
|
|
37
|
+
|
|
38
|
+
Style/EmptyLinesAroundModuleBody:
|
|
39
|
+
Enabled: false
|
|
40
|
+
|
|
41
|
+
Style/MultilineMethodCallIndentation:
|
|
42
|
+
EnforcedStyle: indented
|
|
43
|
+
IndentationWidth: 2
|
|
44
|
+
|
|
45
|
+
Style/SpecialGlobalVars:
|
|
46
|
+
Enabled: false
|
|
47
|
+
|
|
48
|
+
Style/PercentLiteralDelimiters:
|
|
49
|
+
Enabled: false
|
|
50
|
+
|
|
51
|
+
RSpec/InstanceVariable:
|
|
52
|
+
Enabled: false
|
|
53
|
+
|
|
54
|
+
RSpec/MultipleExpectations:
|
|
55
|
+
Max: 5
|
|
56
|
+
|
|
57
|
+
Metrics/BlockLength:
|
|
58
|
+
Exclude:
|
|
59
|
+
- "Rakefile"
|
|
60
|
+
- "**/*.rake"
|
|
61
|
+
- "spec/**/*.rb"
|
|
62
|
+
|
|
63
|
+
Style/EmptyLinesAroundBlockBody:
|
|
64
|
+
Enabled: false
|
|
65
|
+
|
|
66
|
+
RSpec/BeforeAfterAll:
|
|
67
|
+
Enabled: false
|
|
68
|
+
|
|
69
|
+
RSpec/ExampleLength:
|
|
70
|
+
Enabled: false
|
|
71
|
+
|
|
72
|
+
RSpec/DescribedClass:
|
|
73
|
+
Enabled: false
|
|
74
|
+
|
|
75
|
+
Style/IndentArray:
|
|
76
|
+
EnforcedStyle: consistent
|
|
77
|
+
|
|
78
|
+
Style/MultilineMethodCallBraceLayout:
|
|
79
|
+
Enabled: false
|
|
80
|
+
|
|
81
|
+
RSpec/MessageSpies:
|
|
82
|
+
Enabled: false
|
|
83
|
+
|
|
84
|
+
Style/MultilineBlockLayout:
|
|
85
|
+
Enabled: false
|
|
86
|
+
|
|
87
|
+
RSpec/SubjectStub:
|
|
88
|
+
Enabled: false
|
|
89
|
+
|
|
90
|
+
RSpec/DescribeClass:
|
|
91
|
+
Enabled: false
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Test Boosters
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/semaphore_test_boosters)
|
|
2
4
|
|
|
3
5
|
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/test_boosters`. To experiment with that code, run `bin/console` for an interactive prompt.
|
|
4
6
|
|
data/config/cucumber.yml
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
default: --format pretty --profile semaphoreci --profile semaphoreci
|
|
1
|
+
default: --format pretty --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci --profile semaphoreci
|
|
2
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
3
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
4
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
5
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
6
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
7
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
8
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
9
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
10
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
11
|
+
semaphoreci: --format json --out=../cucumber_report.json
|
|
2
12
|
semaphoreci: --format json --out=../cucumber_report.json
|
|
3
13
|
semaphoreci: --format json --out=../cucumber_report.json
|
data/config.reek
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
IrresponsibleModule:
|
|
3
|
+
enabled: false
|
|
4
|
+
|
|
5
|
+
NestedIterators:
|
|
6
|
+
exclude:
|
|
7
|
+
- TestBoosters::CliParser#parse
|
|
8
|
+
- TestBoosters::LeftoverFiles#select
|
|
9
|
+
|
|
10
|
+
TooManyStatements:
|
|
11
|
+
exclude:
|
|
12
|
+
- initialize
|
|
13
|
+
- TestBoosters::CliParser#parse
|
|
14
|
+
- TestBoosters::CucumberBooster#run
|
|
15
|
+
- TestBoosters::CucumberBooster#select
|
|
16
|
+
- TestBoosters::CucumberBooster#with_fallback
|
|
17
|
+
- TestBoosters::LeftoverFiles#select
|
|
18
|
+
- TestBoosters::RspecBooster#run
|
|
19
|
+
- TestBoosters::RspecBooster#run_command
|
|
20
|
+
- TestBoosters::RspecBooster#select
|
|
21
|
+
- TestBoosters::RspecBooster#with_fallback
|
|
22
|
+
|
|
23
|
+
UncommunicativeVariableName:
|
|
24
|
+
exclude:
|
|
25
|
+
- TestBoosters::CucumberBooster#with_fallback
|
|
26
|
+
- TestBoosters::LeftoverFiles#select
|
|
27
|
+
- TestBoosters::LeftoverFiles#sort_descending_by_size
|
|
28
|
+
- TestBoosters::RspecBooster#run
|
|
29
|
+
- TestBoosters::RspecBooster#with_fallback
|
|
30
|
+
|
|
31
|
+
FeatureEnvy:
|
|
32
|
+
enabled: false
|
|
33
|
+
|
|
34
|
+
ControlParameter:
|
|
35
|
+
enabled: false
|
|
36
|
+
|
|
37
|
+
NilCheck:
|
|
38
|
+
exclude:
|
|
39
|
+
- TestBoosters::LeftoverFiles#select
|
|
40
|
+
|
|
41
|
+
UncommunicativeMethodName:
|
|
42
|
+
exclude:
|
|
43
|
+
- a
|
|
44
|
+
- b
|
|
45
|
+
- c
|
|
46
|
+
- Setup#a
|
|
47
|
+
- Setup#b
|
|
48
|
+
- Setup#c
|
|
49
|
+
- Setup::Cucumber#a
|
|
50
|
+
- Setup::Cucumber#b
|
|
51
|
+
- Setup::Cucumber#c
|
|
52
|
+
|
|
53
|
+
UtilityFunction:
|
|
54
|
+
exclude:
|
|
55
|
+
- a
|
|
56
|
+
- b
|
|
57
|
+
- c
|
|
58
|
+
- expected_specs
|
|
59
|
+
- input_specs
|
|
60
|
+
|
|
61
|
+
exclude_paths:
|
|
62
|
+
- vendor
|
|
63
|
+
- .bundle
|
data/exe/cucumber_booster
CHANGED
|
@@ -10,6 +10,6 @@ cucumber_booster = TestBoosters::CucumberBooster.new(thread_index)
|
|
|
10
10
|
exit_status = cucumber_booster.run
|
|
11
11
|
|
|
12
12
|
report_path = cucumber_booster.report_path
|
|
13
|
-
TestBoosters::InsightsUploader.
|
|
13
|
+
TestBoosters::InsightsUploader.upload("cucumber", report_path)
|
|
14
14
|
|
|
15
15
|
exit(exit_status)
|
data/exe/rspec_booster
CHANGED
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "test_boosters"
|
|
4
4
|
|
|
5
|
-
cli_options
|
|
6
|
-
thread_index
|
|
7
|
-
rspec_booster = TestBoosters::
|
|
8
|
-
exit_status = rspec_booster.run
|
|
5
|
+
cli_options = TestBoosters::CliParser.parse
|
|
6
|
+
thread_index = cli_options[:index] - 1
|
|
7
|
+
rspec_booster = TestBoosters::Rspec::Booster.new(thread_index)
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
TestBoosters::InsightsUploader.new.upload("rspec", report_path)
|
|
12
|
-
|
|
13
|
-
exit(exit_status)
|
|
9
|
+
exit(rspec_booster.run)
|
|
@@ -18,7 +18,7 @@ module TestBoosters
|
|
|
18
18
|
else
|
|
19
19
|
exit_code = run_command(features_to_run.join(" "))
|
|
20
20
|
end
|
|
21
|
-
rescue StandardError
|
|
21
|
+
rescue StandardError
|
|
22
22
|
if @thread_index == 0
|
|
23
23
|
exit_code = run_command(@spec_path)
|
|
24
24
|
end
|
|
@@ -65,7 +65,7 @@ module TestBoosters
|
|
|
65
65
|
|
|
66
66
|
puts error
|
|
67
67
|
|
|
68
|
-
error +=
|
|
68
|
+
error += "Exception: #{e.message}"
|
|
69
69
|
|
|
70
70
|
TestBoosters::Logger.error(error)
|
|
71
71
|
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
module TestBoosters
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
@project_hash_id = ENV["SEMAPHORE_PROJECT_UUID"]
|
|
5
|
-
@build_hash_id = ENV["SEMAPHORE_EXECUTABLE_UUID"]
|
|
6
|
-
@job_hash_id = ENV["SEMAPHORE_JOB_UUID"]
|
|
7
|
-
end
|
|
2
|
+
module InsightsUploader
|
|
3
|
+
module_function
|
|
8
4
|
|
|
9
5
|
def upload(booster_type, file)
|
|
10
|
-
|
|
11
|
-
"?job_hash_id=#{@job_hash_id}" +
|
|
12
|
-
"&build_hash_id=#{@build_hash_id}" +
|
|
13
|
-
"&project_hash_id=#{@project_hash_id}"
|
|
14
|
-
cmd = "http POST '#{url}' #{booster_type}:=@#{file}"
|
|
6
|
+
cmd = "http POST '#{insights_url}' #{booster_type}:=@#{file}"
|
|
15
7
|
|
|
16
8
|
TestBoosters::Shell.execute("#{cmd} > ~/insights_uploader.log")
|
|
17
9
|
end
|
|
10
|
+
|
|
11
|
+
def insights_url
|
|
12
|
+
params = {
|
|
13
|
+
:project_hash_id => ENV["SEMAPHORE_PROJECT_UUID"],
|
|
14
|
+
:build_hash_id => ENV["SEMAPHORE_EXECUTABLE_UUID"],
|
|
15
|
+
:job_hash_id => ENV["SEMAPHORE_JOB_UUID"]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
"https://insights-receiver.semaphoreci.com/job_reports?#{URI.encode_www_form(params)}"
|
|
19
|
+
end
|
|
20
|
+
|
|
18
21
|
end
|
|
19
22
|
end
|
|
@@ -9,11 +9,11 @@ module TestBoosters
|
|
|
9
9
|
|
|
10
10
|
files = all_leftover_files
|
|
11
11
|
.each_slice(thread_count)
|
|
12
|
-
.reduce{ |acc, slice| acc.map{|a| a}.zip(slice.reverse) }
|
|
13
|
-
.map{ |f| f.
|
|
12
|
+
.reduce { |acc, slice| acc.map { |a| a }.zip(slice.reverse) }
|
|
13
|
+
.map { |f| f.is_a?(Array) ? f.flatten : [f] } [thread_index]
|
|
14
14
|
|
|
15
15
|
if files.nil? then []
|
|
16
|
-
elsif files.
|
|
16
|
+
elsif files.is_a?(Array) then files.compact
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
data/lib/test_boosters/logger.rb
CHANGED
|
@@ -6,13 +6,13 @@ module TestBoosters
|
|
|
6
6
|
def info(message)
|
|
7
7
|
error_log_path = ENV["ERROR_LOG_PATH"] || "#{ENV["HOME"]}/test_booster_error.log"
|
|
8
8
|
|
|
9
|
-
File.open(error_log_path, "a") { |
|
|
9
|
+
File.open(error_log_path, "a") { |file| file.write("#{message}\n") }
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def error(message)
|
|
13
13
|
error_log_path = ENV["ERROR_LOG_PATH"] || "#{ENV["HOME"]}/test_booster_error.log"
|
|
14
14
|
|
|
15
|
-
File.open(error_log_path, "a") { |
|
|
15
|
+
File.open(error_log_path, "a") { |file| file.write("#{message}\n") }
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module TestBoosters
|
|
2
|
+
module Rspec
|
|
3
|
+
class Booster
|
|
4
|
+
|
|
5
|
+
def initialize(thread_index)
|
|
6
|
+
@thread_index = thread_index
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def run
|
|
10
|
+
unless split_configuration.valid?
|
|
11
|
+
puts "[ERROR] The split configuration file is malformed!"
|
|
12
|
+
|
|
13
|
+
return 1 # failure exit status
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
threads[@thread_index].run
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def thread_count
|
|
20
|
+
@thread_count ||= split_configuration.thread_count
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def threads
|
|
24
|
+
@threads ||= Array.new(thread_count) do |thread_index|
|
|
25
|
+
known_files = all_specs & split_configuration.files_for_thread(thread_index)
|
|
26
|
+
leftover_files = TestBoosters::LeftoverFiles.select(all_leftover_specs, thread_count, thread_index)
|
|
27
|
+
|
|
28
|
+
TestBoosters::Rspec::Thread.new(known_files, leftover_files)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def all_specs
|
|
33
|
+
@all_specs ||= Dir["#{specs_path}/**/*_spec.rb"].sort
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def all_leftover_specs
|
|
37
|
+
@all_leftover_specs ||= all_specs - split_configuration.all_files
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def split_configuration
|
|
41
|
+
@split_configuration ||= TestBoosters::SplitConfiguration.new(split_configuration_path)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def specs_path
|
|
45
|
+
@specs_path ||= ENV["SPEC_PATH"] || "spec"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def split_configuration_path
|
|
49
|
+
ENV["RSPEC_SPLIT_CONFIGURATION_PATH"] || "#{ENV["HOME"]}/rspec_split_configuration.json"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module TestBoosters
|
|
2
|
+
module Rspec
|
|
3
|
+
class Thread
|
|
4
|
+
|
|
5
|
+
attr_reader :files_from_split_configuration
|
|
6
|
+
attr_reader :leftover_files
|
|
7
|
+
|
|
8
|
+
def initialize(files_from_split_configuration, leftover_files)
|
|
9
|
+
@files_from_split_configuration = files_from_split_configuration
|
|
10
|
+
@leftover_files = leftover_files
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# :reek:TooManyStatements { max_statements: 10 }
|
|
14
|
+
def run
|
|
15
|
+
TestBoosters::Shell.display_title("RSpec Booster")
|
|
16
|
+
|
|
17
|
+
if all_files.empty?
|
|
18
|
+
puts("No files to run in this thread!")
|
|
19
|
+
|
|
20
|
+
return 0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
display_thread_info
|
|
24
|
+
|
|
25
|
+
exit_status = run_rspec
|
|
26
|
+
|
|
27
|
+
upload_report
|
|
28
|
+
|
|
29
|
+
exit_status
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def display_thread_info
|
|
33
|
+
TestBoosters::Shell.display_files(
|
|
34
|
+
"Known specs for this thread",
|
|
35
|
+
files_from_split_configuration)
|
|
36
|
+
|
|
37
|
+
TestBoosters::Shell.display_files(
|
|
38
|
+
"Leftover specs for this thread",
|
|
39
|
+
leftover_files)
|
|
40
|
+
|
|
41
|
+
puts "RSpec options: #{rspec_options}"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def run_rspec
|
|
45
|
+
TestBoosters::Shell.display_title("Running RSpec")
|
|
46
|
+
TestBoosters::Shell.execute(rspec_command)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def upload_report
|
|
50
|
+
TestBoosters::InsightsUploader.upload("rspec", report_path)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def all_files
|
|
54
|
+
@all_files ||= files_from_split_configuration + leftover_files
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def rspec_options
|
|
58
|
+
"--format documentation --format json --out #{report_path}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def rspec_command
|
|
62
|
+
"bundle exec rspec #{rspec_options} #{all_files.join(" ")}"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def report_path
|
|
66
|
+
@report_path ||= ENV["REPORT_PATH"] || "#{ENV["HOME"]}/rspec_report.json"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/lib/test_boosters/shell.rb
CHANGED
|
@@ -4,14 +4,25 @@ module TestBoosters
|
|
|
4
4
|
|
|
5
5
|
def execute(command)
|
|
6
6
|
TestBoosters::Logger.info("Running command: #{command}")
|
|
7
|
+
|
|
7
8
|
system(command)
|
|
8
|
-
TestBoosters::Logger.info("Command finished, exit status : #{$?.exitstatus}")
|
|
9
9
|
|
|
10
|
-
$?.exitstatus
|
|
10
|
+
exit_status = $?.exitstatus
|
|
11
|
+
|
|
12
|
+
TestBoosters::Logger.info("Command finished, exit status : #{exit_status}")
|
|
13
|
+
|
|
14
|
+
exit_status
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def display_title(title)
|
|
18
|
+
puts
|
|
19
|
+
puts "========================= #{title} =========================="
|
|
20
|
+
puts
|
|
11
21
|
end
|
|
12
22
|
|
|
13
23
|
def display_files(title, files)
|
|
14
|
-
|
|
24
|
+
puts "#{title} (#{files.count} files):"
|
|
25
|
+
puts
|
|
15
26
|
|
|
16
27
|
files.each { |file| puts "- #{file}" }
|
|
17
28
|
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
module TestBoosters
|
|
2
2
|
class SplitConfiguration
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
path_from_env = ENV["RSPEC_SPLIT_CONFIGURATION_PATH"]
|
|
6
|
-
default_path = "#{ENV["HOME"]}/rspec_split_configuration.json"
|
|
7
|
-
|
|
8
|
-
new(path_from_env || default_path)
|
|
9
|
-
end
|
|
4
|
+
Thread = Struct.new(:files, :thread_index)
|
|
10
5
|
|
|
11
6
|
def self.for_cucumber
|
|
12
7
|
path_from_env = ENV["CUCUMBER_SPLIT_CONFIGURATION_PATH"]
|
|
@@ -15,9 +10,6 @@ module TestBoosters
|
|
|
15
10
|
new(path_from_env || default_path)
|
|
16
11
|
end
|
|
17
12
|
|
|
18
|
-
class Thread < Struct.new(:files, :thread_index)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
13
|
def initialize(path)
|
|
22
14
|
@path = path
|
|
23
15
|
end
|
|
@@ -26,6 +18,13 @@ module TestBoosters
|
|
|
26
18
|
File.exist?(@path)
|
|
27
19
|
end
|
|
28
20
|
|
|
21
|
+
def valid?
|
|
22
|
+
threads # try to load data into memory
|
|
23
|
+
true
|
|
24
|
+
rescue
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
|
|
29
28
|
def all_files
|
|
30
29
|
@all_files ||= threads.map(&:files).flatten.sort
|
|
31
30
|
end
|
|
@@ -40,6 +39,10 @@ module TestBoosters
|
|
|
40
39
|
end
|
|
41
40
|
end
|
|
42
41
|
|
|
42
|
+
def thread_count
|
|
43
|
+
@thread_count ||= threads.count
|
|
44
|
+
end
|
|
45
|
+
|
|
43
46
|
private
|
|
44
47
|
|
|
45
48
|
def load_data
|
data/lib/test_boosters.rb
CHANGED
|
@@ -11,7 +11,8 @@ module TestBoosters
|
|
|
11
11
|
require "test_boosters/shell"
|
|
12
12
|
require "test_boosters/leftover_files"
|
|
13
13
|
|
|
14
|
-
require "test_boosters/
|
|
14
|
+
require "test_boosters/rspec/booster"
|
|
15
|
+
require "test_boosters/rspec/thread"
|
|
15
16
|
require "test_boosters/cucumber_booster"
|
|
16
17
|
require "test_boosters/insights_uploader"
|
|
17
18
|
|
|
@@ -24,5 +25,4 @@ module TestBoosters
|
|
|
24
25
|
|
|
25
26
|
CucumberBoosterConfig::CLI.start ["inject", "."]
|
|
26
27
|
end
|
|
27
|
-
|
|
28
28
|
end
|
data/test_boosters.gemspec
CHANGED
|
@@ -30,7 +30,12 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
spec.add_dependency "semaphore_cucumber_booster_config", "~> 1.1"
|
|
31
31
|
|
|
32
32
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
33
|
-
spec.add_development_dependency "rspec", "~> 3.
|
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
|
34
34
|
spec.add_development_dependency "activesupport", "~> 4.0"
|
|
35
35
|
spec.add_development_dependency "cucumber-rails", "~> 1.4.3"
|
|
36
|
+
|
|
37
|
+
spec.add_development_dependency "rubocop", "~> 0.47.1"
|
|
38
|
+
spec.add_development_dependency "rubocop-rspec", "~> 1.13.0"
|
|
39
|
+
spec.add_development_dependency "reek", "4.5.6"
|
|
40
|
+
spec.add_development_dependency "simplecov", "~> 0.13"
|
|
36
41
|
end
|
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: 1.
|
|
4
|
+
version: 1.4.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-03-
|
|
11
|
+
date: 2017-03-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: semaphore_cucumber_booster_config
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '3.
|
|
47
|
+
version: '3.5'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '3.
|
|
54
|
+
version: '3.5'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: activesupport
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,6 +80,62 @@ dependencies:
|
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: 1.4.3
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 0.47.1
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: 0.47.1
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop-rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: 1.13.0
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: 1.13.0
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: reek
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - '='
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: 4.5.6
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - '='
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: 4.5.6
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: simplecov
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - "~>"
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0.13'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - "~>"
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0.13'
|
|
83
139
|
description: Gem for auto-parallelizing builds across Semaphore jobs.
|
|
84
140
|
email:
|
|
85
141
|
- devops@renderedtext.com
|
|
@@ -91,12 +147,14 @@ extra_rdoc_files: []
|
|
|
91
147
|
files:
|
|
92
148
|
- ".gitignore"
|
|
93
149
|
- ".rspec"
|
|
150
|
+
- ".rubocop.yml"
|
|
94
151
|
- Gemfile
|
|
95
152
|
- LICENSE.txt
|
|
96
153
|
- README.md
|
|
97
154
|
- Rakefile
|
|
98
155
|
- bin/console
|
|
99
156
|
- bin/setup
|
|
157
|
+
- config.reek
|
|
100
158
|
- config/cucumber.yml
|
|
101
159
|
- exe/cucumber_booster
|
|
102
160
|
- exe/rspec_booster
|
|
@@ -106,7 +164,8 @@ files:
|
|
|
106
164
|
- lib/test_boosters/insights_uploader.rb
|
|
107
165
|
- lib/test_boosters/leftover_files.rb
|
|
108
166
|
- lib/test_boosters/logger.rb
|
|
109
|
-
- lib/test_boosters/
|
|
167
|
+
- lib/test_boosters/rspec/booster.rb
|
|
168
|
+
- lib/test_boosters/rspec/thread.rb
|
|
110
169
|
- lib/test_boosters/shell.rb
|
|
111
170
|
- lib/test_boosters/split_configuration.rb
|
|
112
171
|
- lib/test_boosters/version.rb
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
module TestBoosters
|
|
2
|
-
class RspecBooster
|
|
3
|
-
attr_reader :report_path
|
|
4
|
-
|
|
5
|
-
def initialize(thread_index)
|
|
6
|
-
@thread_index = thread_index
|
|
7
|
-
@report_path = ENV["REPORT_PATH"] || "#{ENV["HOME"]}/rspec_report.json"
|
|
8
|
-
@spec_path = ENV["SPEC_PATH"] || "spec"
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def run
|
|
12
|
-
exit_code = true
|
|
13
|
-
begin
|
|
14
|
-
specs_to_run = select
|
|
15
|
-
|
|
16
|
-
if specs_to_run.empty?
|
|
17
|
-
puts "No spec files in this thread!"
|
|
18
|
-
else
|
|
19
|
-
exit_code = run_command(specs_to_run.join(" "))
|
|
20
|
-
end
|
|
21
|
-
rescue StandardError => e
|
|
22
|
-
if @thread_index == 0
|
|
23
|
-
exit_code = run_command(@spec_path)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
exit_code
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def run_command(specs)
|
|
30
|
-
options = "--format documentation --format json --out #{@report_path}"
|
|
31
|
-
puts "Rspec options: #{options}"
|
|
32
|
-
puts
|
|
33
|
-
puts "========================= Running Rspec =========================="
|
|
34
|
-
puts
|
|
35
|
-
|
|
36
|
-
TestBoosters::Shell.execute("bundle exec rspec #{options} #{specs}")
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def select
|
|
40
|
-
with_fallback do
|
|
41
|
-
split_configuration = TestBoosters::SplitConfiguration.for_rspec
|
|
42
|
-
thread_count = split_configuration.threads.count
|
|
43
|
-
|
|
44
|
-
puts "Running RSpec thread #{@thread_index + 1} out of #{thread_count} threads\n"
|
|
45
|
-
|
|
46
|
-
all_specs = Dir["#{@spec_path}/**/*_spec.rb"].sort
|
|
47
|
-
all_known_specs = split_configuration.all_files
|
|
48
|
-
|
|
49
|
-
all_leftover_specs = all_specs - all_known_specs
|
|
50
|
-
thread_leftover_specs = TestBoosters::LeftoverFiles.select(all_leftover_specs, thread_count, @thread_index)
|
|
51
|
-
|
|
52
|
-
thread_specs = all_specs & split_configuration.files_for_thread(@thread_index)
|
|
53
|
-
specs_to_run = thread_specs + thread_leftover_specs
|
|
54
|
-
|
|
55
|
-
TestBoosters::Shell.display_files("This thread specs:", thread_specs)
|
|
56
|
-
TestBoosters::Shell.display_title_and_count("All leftover specs:", all_leftover_specs)
|
|
57
|
-
TestBoosters::Shell.display_files("This thread leftover specs:", thread_leftover_specs)
|
|
58
|
-
|
|
59
|
-
specs_to_run
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def with_fallback
|
|
64
|
-
yield
|
|
65
|
-
rescue StandardError => e
|
|
66
|
-
error = %{
|
|
67
|
-
WARNING: An error detected while parsing the test boosters report file.
|
|
68
|
-
WARNING: All tests will be executed on the first thread.\n
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
error += %{Exception: #{e.message}\n#{e.backtrace.join("\n")}}
|
|
72
|
-
|
|
73
|
-
puts error
|
|
74
|
-
TestBoosters::Logger.error(error)
|
|
75
|
-
|
|
76
|
-
raise
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
end
|
|
80
|
-
end
|