flakey_spec_catcher 0.9.2 → 0.9.3

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: 924bcd5b7fe71399bc43663478b9b238731e9920e4fcc8c54ba8977a345ee065
4
- data.tar.gz: '080682849736c9d46acd6eeeb8ccc8e98115fb9558004e821f4beed33dfd455e'
3
+ metadata.gz: 6afbdca4bb65ca89de114e1dcfbdbffb93e5dbfbe7f39cc4c4511e018f422bf3
4
+ data.tar.gz: 3e6b37e7f310e74b2711139e6d45b94028d22a3624e7bcd08494e8bef49bc26a
5
5
  SHA512:
6
- metadata.gz: 68cf5c4b41ae6b158a501bab2a6134a40dd1d0ca3d7ce26452948b986ddf713d443458643d2a27a8ff565b9856c647867630015c78dc2f9e7784bf31b0d772e4
7
- data.tar.gz: cee42fcbf243eaa03e56745491515ae7580e2e7974d751faef5f2387c40f07cb20b9f225d188e04009950b7cfd339720e406b789f4e7fa2ec537c2c109b81c18
6
+ metadata.gz: d37a8bfaffe6c700ce2f748b96cac49838db1bbb45f4f96d50b87029f13b01e57507e08e939f9316e7ec3a523ed6d2b34ab0f1d090e461e5405442cad588f565
7
+ data.tar.gz: b84ce73838ec8ff524c444a207627eadefd15f91dd9b7358493280e562c0eadd1a85a72aca6c2a8072d95e9f26e2b3965983389aeb7ac384876a40ec5a737079
data/README.md CHANGED
@@ -152,9 +152,14 @@ FSC_USAGE_PATTERNS = '{ spec/ui => bundle exec rspec }, { spec/api => parallel_r
152
152
  ```
153
153
  -t, --test=TEST_NAME Specify one or more specs in comma separated list
154
154
  -u, --usage=USAGE Specify a re-run usage for the manual re-run
155
+ --use-parent Use the parent of commit for git diff instead of the Head of SCM
155
156
  -r, --repeat=REPEAT_FACTOR Specify a repeat factor for the manual re-run(s)
156
157
  -e, --excluded-tags=EXCLUDED Specify tags to exclude in a comma separated list
157
158
  -o, --output=PATH_TO_OUTPUT Direct all re-run output to a specific file
159
+ --node-total Specify now many nodes the run is being split into
160
+ --node-index Specify the index this node represents in a split run
161
+ -d, --dry-run Performs all setup but doesn't run any tests
162
+ --dry-run-quiet Prints list of tests to be run
158
163
  -v, --version Prints current flakey_spec_catcher_version
159
164
  -h, --help Displays available flakey_spec_catcher cli overrides
160
165
  ```
@@ -195,6 +200,36 @@ flakey_spec_catcher --test='api/spec/*_spec.rb' --usage='bundle exec parallel_rs
195
200
  flakey_spec_catcher --test='api/spec/admin_spec.rb' --repeat='10' --usage='rspec'
196
201
  ```
197
202
 
203
+ ### Running on multiple nodes:
204
+
205
+ If there are a lot of tests required to be checked, then you may want to run the
206
+ tests on multiple nodes. this can be done with the combination of the `--node-total`
207
+ and `--node-index` arguments.
208
+
209
+ Usage Examples:
210
+ ```sh
211
+ # if you have 30 tests to run
212
+
213
+ # this will be tests 0-9
214
+ bundle exec flakey_spec_catcher --node-total=3 --node-index=0
215
+ # this will be tests 10-19
216
+ bundle exec flakey_spec_catcher --node-total=3 --node-index=1
217
+ # this will be tests 20-29
218
+ bundle exec flakey_spec_catcher --node-total=3 --node-index=2
219
+ ```
220
+
221
+ Note that the last node may have a different number of tests that it runs:
222
+ ```sh
223
+ # if you have 20 tests to run
224
+
225
+ # this will be tests 0-6 (7 tests)
226
+ bundle exec flakey_spec_catcher --node-total=3 --node-index=0
227
+ # this will be tests 7-13 (7 tests)
228
+ bundle exec flakey_spec_catcher --node-total=3 --node-index=1
229
+ # this will be tests 14-19 (6 tests)
230
+ bundle exec flakey_spec_catcher --node-total=3 --node-index=2
231
+ ```
232
+
198
233
  ### Additional Git Detection Examples
199
234
 
200
235
  ```sh
@@ -9,4 +9,6 @@ if app.user_config.enable_runs
9
9
  app.show_settings
10
10
  app.rerun_preview
11
11
  exit app.run_specs
12
+ elsif app.user_config.dry_run
13
+ app.show_test_list
12
14
  end
@@ -7,14 +7,16 @@ module FlakeySpecCatcher
7
7
  #
8
8
  # Captures command line arguments for manual re-runs
9
9
  class CliOverride
10
- attr_reader :rerun_patterns, :rerun_usage, :repeat_factor, :enable_runs, :excluded_tags, :use_parent
11
- attr_reader :output_file
10
+ attr_reader :rerun_patterns, :rerun_usage, :repeat_factor, :enable_runs, :excluded_tags, :use_parent, :dry_run
11
+ attr_reader :output_file, :split_nodes, :split_index
12
12
 
13
13
  def initialize
14
+ @dry_run = false
14
15
  @enable_runs = true
15
16
  @excluded_tags = []
16
17
  @use_parent = false
17
18
  parse_command_line_args
19
+ validate_arguments
18
20
  end
19
21
 
20
22
  private
@@ -36,15 +38,20 @@ module FlakeySpecCatcher
36
38
  end
37
39
 
38
40
  opts.on('-u', '--usage=USAGE', 'Specify a re-run usage for the manual re-run') do |usage|
39
- raise ArgumentError if @rerun_patterns.nil?
40
-
41
41
  @rerun_usage = remove_formatter_quotes(usage)
42
42
  end
43
43
 
44
+ opts.on('--node-total=SPLIT_NODES', 'Specify now many nodes the run is being split into') do |nodes|
45
+ @split_nodes = remove_formatter_quotes(nodes).to_i
46
+ end
47
+
48
+ opts.on('--node-index=SPLIT_INDEX', 'Specify the index this node represents in a split run') do |index|
49
+ @split_index = remove_formatter_quotes(index).to_i
50
+ end
51
+
44
52
  opts.on('-r', '--repeat=REPEAT_FACTOR',
45
53
  'Specify a repeat factor for the manual re-run(s)') do |repeat|
46
- parsed_repeat_factor = remove_formatter_quotes(repeat).to_i
47
- @repeat_factor = parsed_repeat_factor if parsed_repeat_factor.positive?
54
+ @repeat_factor = remove_formatter_quotes(repeat).to_i
48
55
  end
49
56
 
50
57
  opts.on('-e', '--excluded-tags=EXCLUDED_TAGS',
@@ -62,12 +69,36 @@ module FlakeySpecCatcher
62
69
  @enable_runs = false
63
70
  end
64
71
 
72
+ opts.on('-d', '--dry-run', "Performs all setup but doesn't run any tests") do
73
+ @dry_run = true
74
+ end
75
+
76
+ opts.on('--dry-run-quiet', 'Prints list of tests to be run') do
77
+ @enable_runs = false
78
+ @dry_run = true
79
+ end
80
+
65
81
  opts.on('-h', '--help', 'Displays available flakey_spec_catcher cli overrides') do
66
82
  puts opts
67
83
  @enable_runs = false
68
84
  end
69
85
  end.parse!
70
86
  end
87
+
88
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
89
+ def validate_arguments
90
+ if !@rerun_usage.nil? && @rerun_patterns.nil?
91
+ raise ArgumentError, 'rerun usage can only be specified with rerun patterns'
92
+ end
93
+ raise ArgumentError, 'repeat factor must be positive' if !@repeat_factor.nil? && @repeat_factor.negative?
94
+ raise ArgumentError, 'split index and split nodes must be specified together' if @split_nodes.nil? != @split_index.nil?
95
+
96
+ splitting = !@split_nodes.nil? && !@split_index.nil?
97
+ raise ArgumentError, 'split total must be positive' if splitting && @split_nodes.negative?
98
+ raise ArgumentError, 'split index must be positive' if splitting && @split_index.negative?
99
+ raise ArgumentError, 'split index must be less than split nodes' if splitting && @split_index >= @split_nodes
100
+ end
101
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
71
102
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/BlockLength
72
103
 
73
104
  def remove_formatter_quotes(env_var)
@@ -26,6 +26,9 @@ module FlakeySpecCatcher
26
26
  @remote = find_git_remote
27
27
  @branch = find_remote_branch
28
28
  @capsule_manager = capsule_manager
29
+ # we don't need to do any git comparisons if we have manually specified tests to run.
30
+ return unless @user_config.manual_rerun_patterns.nil? || @user_config.manual_rerun_patterns.empty?
31
+
29
32
  initialize_git_comparison(test_mode)
30
33
  parse_changes
31
34
  identify_change_contexts
@@ -17,6 +17,7 @@ module FlakeySpecCatcher
17
17
  @user_config = user_config
18
18
  @rerun_capsules = []
19
19
  determine_rerun_usage
20
+ split!
20
21
  end
21
22
 
22
23
  def determine_rerun_usage
@@ -110,6 +111,37 @@ module FlakeySpecCatcher
110
111
 
111
112
  private
112
113
 
114
+ # rubocop:disable Metrics/AbcSize
115
+ def split!
116
+ return unless !@user_config.split_nodes.nil? && !@user_config.split_index.nil?
117
+
118
+ # we create this restriction for simplicity. if we have multiple capsules then
119
+ # we have to split while being aware of splitting across capsules.
120
+ # if we absolutely need to split with different usage types, then we can implement that later..
121
+ raise ArgumentError('can only split on one usage type') if @rerun_capsules.size != 1
122
+
123
+ # ensure everything is sorted consistently before splitting
124
+ capsule = @rerun_capsules[0]
125
+ capsule.testcase.sort!
126
+
127
+ # compute the total tests that are changing
128
+ test_count = capsule.testcase.size
129
+
130
+ # the last node is going to be different from the previous nodes.
131
+ # for instance, if there are 13 test to run and you want 3 nodes:
132
+ # node1 -> 5
133
+ # node2 -> 5
134
+ # node3 -> 3
135
+ # it may be more efficient to split differently, but for now this will work.
136
+ node_test_count = (test_count / @user_config.split_nodes.to_f).ceil
137
+
138
+ skipping = @user_config.split_index * node_test_count
139
+ skipping_until = (@user_config.split_index + 1) * node_test_count
140
+ split_tests = capsule.testcase[skipping...skipping_until]
141
+ @rerun_capsules = [FlakeySpecCatcher::RerunCapsule.new(usage: capsule.usage, testcase: split_tests)]
142
+ end
143
+ # rubocop:enable Metrics/AbcSize
144
+
113
145
  def filter_reruns_by_ignore_files(reruns)
114
146
  return reruns if @user_config.ignore_files.count.zero?
115
147
 
@@ -10,7 +10,7 @@ require_relative './event_listener.rb'
10
10
 
11
11
  module FlakeySpecCatcher
12
12
  class Runner
13
- attr_reader :user_config, :rerun_manager, :git_controller
13
+ attr_reader :user_config, :rerun_manager, :git_controller, :test_run_count
14
14
 
15
15
  def initialize(test_mode: false,
16
16
  user_config: FlakeySpecCatcher::UserConfig.new,
@@ -23,6 +23,7 @@ module FlakeySpecCatcher
23
23
  @user_config = user_config
24
24
  @rerun_manager = rerun_manager
25
25
  @rspec_result_manager = result_manager
26
+ @test_run_count = 0
26
27
  end
27
28
 
28
29
  # Debug Methods
@@ -34,6 +35,8 @@ module FlakeySpecCatcher
34
35
  puts " Current Sha: #{@git_controller.working_commit_sha}"
35
36
  puts " Base Sha: #{@git_controller.base_commit_sha}"
36
37
  puts " Repeat factor: #{@user_config.repeat_factor}"
38
+ puts " Node Total: #{@user_config.split_nodes}" if @user_config.split_nodes
39
+ puts " Node Index: #{@user_config.split_index}" if @user_config.split_index
37
40
  puts " Changed Specs Detected: #{@git_controller.changed_examples}"
38
41
  return if @user_config.output_file == '/dev/null'
39
42
 
@@ -55,7 +58,17 @@ module FlakeySpecCatcher
55
58
  end
56
59
  # end Debug methods
57
60
 
61
+ def show_test_list
62
+ @rerun_manager.rerun_capsules.each do |capsule|
63
+ capsule.testcase.each do |test|
64
+ puts test
65
+ end
66
+ end
67
+ end
68
+
58
69
  def run_specs
70
+ return 0 if @user_config.dry_run
71
+
59
72
  status = 0
60
73
  @rerun_manager.rerun_capsules.sort.each do |capsule|
61
74
  @user_config.repeat_factor.times do
@@ -95,6 +108,7 @@ module FlakeySpecCatcher
95
108
  end
96
109
 
97
110
  def handle_capsule_rerun(capsule)
111
+ @test_run_count += 1
98
112
  if capsule.default_usage?
99
113
  invoke_rspec_runner(capsule.testcase)
100
114
  else
@@ -10,7 +10,8 @@ module FlakeySpecCatcher
10
10
  attr_reader :repeat_factor, :ignore_files, :ignore_branches, :silent_mode
11
11
  attr_reader :rerun_file_only, :rspec_usage_patterns, :excluded_tags
12
12
  attr_reader :manual_rerun_patterns, :manual_rerun_usage
13
- attr_reader :enable_runs, :output_file, :use_parent
13
+ attr_reader :enable_runs, :output_file, :use_parent, :dry_run
14
+ attr_reader :split_nodes, :split_index
14
15
 
15
16
  USER_CONFIG_ENV_VARS = %w[FSC_REPEAT_FACTOR FSC_IGNORE_FILES FSC_IGNORE_BRANCHES
16
17
  FSC_SILENT_MODE FSC_RERUN_FILE_ONLY FSC_USAGE_PATTERNS
@@ -34,14 +35,8 @@ module FlakeySpecCatcher
34
35
  @rspec_usage_patterns = env_var_string_to_pairs(ENV['FSC_USAGE_PATTERNS'])
35
36
  @excluded_tags = env_var_string_to_tags(ENV['FSC_EXCLUDED_TAGS'])
36
37
  @output_file = ENV['FSC_OUTPUT_FILE']
37
- end
38
- # rubocop:enable Metrics/AbcSize
39
-
40
- def override_settings
41
- apply_cli_override
42
- return unless @manual_rerun_patterns.nil?
43
-
44
- parse_commit_message
38
+ @split_nodes = env_var_string_to_int_or_nil('FSC_NODE_TOTAL')
39
+ @split_index = env_var_string_to_int_or_nil('FSC_NODE_INDEX')
45
40
  end
46
41
 
47
42
  def apply_cli_override
@@ -50,6 +45,9 @@ module FlakeySpecCatcher
50
45
  @use_parent = @cli_override.use_parent
51
46
  @repeat_factor = @cli_override.repeat_factor if @cli_override.repeat_factor.to_i.positive?
52
47
  @enable_runs = @cli_override.enable_runs
48
+ @dry_run = @cli_override.dry_run
49
+ @split_nodes = @cli_override.split_nodes unless @cli_override.split_nodes.nil?
50
+ @split_index = @cli_override.split_index unless @cli_override.split_index.nil?
53
51
  @excluded_tags = if @cli_override.excluded_tags.empty?
54
52
  @excluded_tags
55
53
  else
@@ -57,6 +55,14 @@ module FlakeySpecCatcher
57
55
  end
58
56
  @output_file = set_output_file
59
57
  end
58
+ # rubocop:enable Metrics/AbcSize
59
+
60
+ def override_settings
61
+ apply_cli_override
62
+ return unless @manual_rerun_patterns.nil?
63
+
64
+ parse_commit_message
65
+ end
60
66
 
61
67
  def set_output_file
62
68
  if !@cli_override.output_file.nil?
@@ -76,6 +82,18 @@ module FlakeySpecCatcher
76
82
  env_var.to_i.positive? ? env_var.to_i : 20
77
83
  end
78
84
 
85
+ def env_var_string_to_int_or_nil(env_var_name)
86
+ env_var = ENV[env_var_name]
87
+ if env_var.nil? || env_var.empty?
88
+ nil
89
+ else
90
+ check = env_var.to_i
91
+ raise ArgumentError, "#{env_var_name} must be positive" if check.negative?
92
+
93
+ check
94
+ end
95
+ end
96
+
79
97
  def env_var_string_to_array(env_var)
80
98
  if env_var.nil? || env_var.empty?
81
99
  []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FlakeySpecCatcher
4
- VERSION = '0.9.2'
4
+ VERSION = '0.9.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flakey_spec_catcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Watson
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-02-18 00:00:00.000000000 Z
13
+ date: 2020-02-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec