semaphore_test_boosters 0.2.0 → 0.3.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
  SHA1:
3
- metadata.gz: 850317895762d06c3ef3617213efd1dac7974784
4
- data.tar.gz: 1a03f9570cbe6fdc73c46131f380eb8a694ad172
3
+ metadata.gz: de95c3faf8fec6fe5d037d492da9433df3028fa2
4
+ data.tar.gz: adbee1c687caf014f5145248b6994001365aa61c
5
5
  SHA512:
6
- metadata.gz: 88f2e599a93f15e0e56c2d0d29cdd0b845f8cea2751c334649580d76ea1e567767b4aa920230111345247163e45a9b9f827b55dae51e0689d3bab9c16698c97e
7
- data.tar.gz: e533bb7990e3ad15e5b53fce537d0c8c855762703e4b0358a82b8693f4f6f18037b2146610a2a7ac92f363658683c1401e995cd18bf9aae21206c5deafeeac88
6
+ metadata.gz: e3f19dac14a29900d51795f3ed105d70df9f09e4b983b6b78e395bae78d3e18af953b9005a7aa649764be2ad247390dea88d57d6da46a08f8566fe1b4393cc3c
7
+ data.tar.gz: 7e70e1209987c81c4a92c5d102ad82966e8fc634985f48f81c04da28938f69ac6f0dcf5dedc8e642c14aa02eb7d7c3c4279ad721d3bbe2625a8a0e7c3d55be1d
@@ -0,0 +1,15 @@
1
+ module Semaphore
2
+ require "optparse"
3
+
4
+ def self.parse
5
+ options = {}
6
+
7
+ parser = OptionParser.new do |opts|
8
+ opts.on("--thread INDEX") { |index| options[:index] = index.to_i }
9
+ end
10
+
11
+ parser.parse!
12
+
13
+ options
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Semaphore
2
+ def self.display_files(title, files)
3
+ puts "#{title} #{files.count}\n"
4
+
5
+ files.each { |file| puts "- #{file}" }
6
+
7
+ puts "\n"
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Semaphore
2
+ def self.execute(command)
3
+ log("Running command: #{command}")
4
+ system(command)
5
+ log("Command finished, exit status : #{$?.exitstatus}")
6
+
7
+ exit($?.exitstatus)
8
+ end
9
+ end
@@ -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
@@ -0,0 +1,7 @@
1
+ module Semaphore
2
+ def self.log(message)
3
+ error_log_path = ENV["ERROR_LOG_PATH"] || "#{ENV["HOME"]}/test_booster_error.log"
4
+
5
+ File.open(error_log_path, "a") { |f| f.write("#{message}\n") }
6
+ end
7
+ end
@@ -1,87 +1,73 @@
1
- #!/usr/bin/env ruby
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
@@ -1,3 +1,3 @@
1
1
  module TestBoosters
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/test_boosters.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "test_boosters/version"
2
+ require "test_boosters/rspec_booster"
2
3
 
3
4
  module TestBoosters
4
5
  # Your code goes here...
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "test_boosters/rspec_booster"
4
+
5
+ cli_options = Semaphore::parse
6
+ thread_index = cli_options[:index] - 1
7
+ rspec_booster = Semaphore::RspecBooster.new(thread_index)
8
+ rspec_booster.run
@@ -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 = ["Predrag Rakic"]
10
- spec.email = ["prakic@renderedtext.com"]
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.}
@@ -0,0 +1 @@
1
+ 12345678901234567890
@@ -0,0 +1 @@
1
+ 123
@@ -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.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
- - Predrag Rakic
7
+ - MAINTAINER Rendered Text
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-14 00:00:00.000000000 Z
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
- - prakic@renderedtext.com
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