flakey_spec_catcher 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/flakey_spec_catcher/change_capsule.rb +1 -1
- data/lib/flakey_spec_catcher/cli_override.rb +0 -2
- data/lib/flakey_spec_catcher/git_controller.rb +15 -3
- data/lib/flakey_spec_catcher/rerun_capsule.rb +9 -3
- data/lib/flakey_spec_catcher/rerun_manager.rb +23 -23
- data/lib/flakey_spec_catcher/runner.rb +10 -10
- data/lib/flakey_spec_catcher/user_config.rb +0 -2
- data/lib/flakey_spec_catcher/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f845e77fb2900e6e7fca4c3de62b8104dd1c1844fba4b0881d9d9c77d3b65c0
|
4
|
+
data.tar.gz: 3611db64df625c5cc1506e400a5cd5d664da15bf254431835f245d6539b9fdaa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b314f343b5630fab71d1d95eeb0b08f371d7bf314b2b5045e33fbc7eaa6d088c17d86244ee0826cb338f0e74b515f66f2fa1e0b76874fe128cbb0cfac534aedb
|
7
|
+
data.tar.gz: 9efea9ff0b95595f1535fdff9ada0bd86822b716c01c7faec2edc48d6600c82a2b6dea07e0fba1a225f63a936720f75e8d74577b8102b3833bc693564e3bcf93
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ There are two primary usecases for flakey_spec_catcher (FSC):
|
|
11
11
|
commit many times.
|
12
12
|
|
13
13
|
2. Manual Re-runs - Specify a test to re-run many times regardless of whether it has
|
14
|
-
corresponding changes in
|
14
|
+
corresponding changes in your commit.
|
15
15
|
|
16
16
|
FSC detects changes by running the equivalent of a git diff
|
17
17
|
between the current branch's commit and the HEAD of Source Control Management (SCM)
|
@@ -70,7 +70,7 @@ you'll also need to ensure that FSC has access to any needed gems.
|
|
70
70
|
It's best to do this by adding flakey_speec_catcher to your Gemfile via bundler
|
71
71
|
and then running it with `bundle exec flakey_spec_catcher`
|
72
72
|
|
73
|
-
### In what cases
|
73
|
+
### In what cases is FSC not suitable?
|
74
74
|
|
75
75
|
Since FSC by default re-runs tests at the smallest possible level of
|
76
76
|
change (a single test case or example), it is not suitable to allow it to run
|
@@ -72,7 +72,7 @@ module FlakeySpecCatcher
|
|
72
72
|
# Not sure if we need to check for description in quotes
|
73
73
|
# spec_scope = /^\s*(#{SCOPE_SPECIFIERS.join("|")})\s*('.*'|".*").*do\s*$/
|
74
74
|
|
75
|
-
/\s*(#{SCOPE_SPECIFIERS.join("|")}).*\s+do
|
75
|
+
/\s*(#{SCOPE_SPECIFIERS.join("|")}).*\s+do.*$/
|
76
76
|
end
|
77
77
|
|
78
78
|
def line_matches_method_or_block(line)
|
@@ -37,8 +37,6 @@ module FlakeySpecCatcher
|
|
37
37
|
|
38
38
|
opts.on('-r', '--repeat=REPEAT_FACTOR',
|
39
39
|
'Specify a repeat factor for the manual re-run(s)') do |repeat|
|
40
|
-
raise ArgumentError if @rerun_patterns.nil?
|
41
|
-
|
42
40
|
parsed_repeat_factor = remove_formatter_quotes(repeat).to_i
|
43
41
|
@repeat_factor = parsed_repeat_factor if parsed_repeat_factor.positive?
|
44
42
|
end
|
@@ -20,8 +20,8 @@ module FlakeySpecCatcher
|
|
20
20
|
attr_reader :capsule_manager
|
21
21
|
|
22
22
|
def initialize(test_mode: false, capsule_manager: FlakeySpecCatcher::CapsuleManager.new)
|
23
|
+
@remote = find_git_remote
|
23
24
|
@branch = find_remote_branch
|
24
|
-
@remote = `git remote`.gsub(/\s+/, '')
|
25
25
|
@capsule_manager = capsule_manager
|
26
26
|
initialize_git_comparison(test_mode)
|
27
27
|
parse_changes
|
@@ -34,7 +34,19 @@ module FlakeySpecCatcher
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
+
# Use 'origin' unless otherwise specified
|
38
|
+
def find_git_remote
|
39
|
+
if ENV['FSC_GIT_REMOTE'].nil? || ENV['FSC_GIT_REMOTE'].strip.empty?
|
40
|
+
remotes = `git remote show`.split
|
41
|
+
remotes.empty? ? nil : remotes[0]
|
42
|
+
else
|
43
|
+
ENV['FSC_GIT_REMOTE']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
37
47
|
def find_remote_branch
|
48
|
+
return nil if @remote.nil?
|
49
|
+
|
38
50
|
working_branch = `git branch | grep '*'`.delete('*').gsub(/\s+/, '')
|
39
51
|
# `git remote show origin` will show us if our branch is configured to push
|
40
52
|
# to a non-master branch. Note that our push destination is what we're interested in
|
@@ -55,7 +67,7 @@ module FlakeySpecCatcher
|
|
55
67
|
# dev/reports pushes to dev/reports (up to date)
|
56
68
|
# master pushes to master (up to date)
|
57
69
|
|
58
|
-
remote_branches = `git remote show
|
70
|
+
remote_branches = `git remote show #{@remote}`.split("\n")
|
59
71
|
|
60
72
|
# Separate 'dev/reports pushes to dev/reports (up to date)' into
|
61
73
|
# ['dev/reports', 'dev/reports'] or [<LOCAL BRANCH>, <REMOTE BRANCH>]
|
@@ -78,7 +90,7 @@ module FlakeySpecCatcher
|
|
78
90
|
end
|
79
91
|
|
80
92
|
def initialize_git_comparison(test_mode)
|
81
|
-
if !test_mode
|
93
|
+
if !test_mode && !@remote.nil?
|
82
94
|
@working_commit_sha = `git rev-parse @`.gsub(/\s+/, '')
|
83
95
|
@base_commit_sha = `git rev-parse #{@remote}/#{@branch}`.gsub(/\s+/, '')
|
84
96
|
else
|
@@ -9,7 +9,7 @@ module FlakeySpecCatcher
|
|
9
9
|
include Comparable
|
10
10
|
attr_reader :usage, :testcase
|
11
11
|
|
12
|
-
def initialize(usage: nil, testcase:
|
12
|
+
def initialize(usage: nil, testcase: [])
|
13
13
|
@usage = initialize_usage(usage)
|
14
14
|
@testcase = initialize_testcase(testcase)
|
15
15
|
end
|
@@ -30,6 +30,10 @@ module FlakeySpecCatcher
|
|
30
30
|
@testcase <=> other.testcase
|
31
31
|
end
|
32
32
|
|
33
|
+
def ==(other)
|
34
|
+
usage == other.usage && testcase == other.testcase
|
35
|
+
end
|
36
|
+
|
33
37
|
private
|
34
38
|
|
35
39
|
def initialize_usage(usage)
|
@@ -42,9 +46,11 @@ module FlakeySpecCatcher
|
|
42
46
|
|
43
47
|
def initialize_testcase(testcase)
|
44
48
|
if testcase.nil? || testcase.empty?
|
45
|
-
|
46
|
-
|
49
|
+
[]
|
50
|
+
elsif testcase.is_a?(Array)
|
47
51
|
testcase
|
52
|
+
else
|
53
|
+
raise "Error: expected array for testcase not #{testcase.class}"
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
@@ -23,7 +23,7 @@ module FlakeySpecCatcher
|
|
23
23
|
if @user_config.manual_rerun_patterns.nil?
|
24
24
|
pair_reruns_with_usages
|
25
25
|
else
|
26
|
-
@rerun_capsules
|
26
|
+
@rerun_capsules = []
|
27
27
|
inject_manual_reruns(@user_config.manual_rerun_patterns,
|
28
28
|
@user_config.manual_rerun_usage)
|
29
29
|
end
|
@@ -59,57 +59,52 @@ module FlakeySpecCatcher
|
|
59
59
|
def pair_reruns_with_usages
|
60
60
|
reruns = tests_for_rerun
|
61
61
|
configured_usage_patterns = @user_config.rspec_usage_patterns
|
62
|
-
|
63
62
|
if configured_usage_patterns.count.zero?
|
64
63
|
add_capsules_with_default_usage(reruns)
|
65
64
|
return
|
66
65
|
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
pattern, usage = usage_pattern_pair
|
74
|
-
if rerun =~ /#{pattern}/
|
75
|
-
add_rerun_capsule(testcase: rerun, usage: usage)
|
76
|
-
match_found = true
|
77
|
-
end
|
67
|
+
configured_usage_patterns.each do |usage_pattern_pair|
|
68
|
+
tests = []
|
69
|
+
pattern, usage = usage_pattern_pair
|
70
|
+
reruns.each do |rerun|
|
71
|
+
tests.push rerun if rerun =~ /#{pattern}/
|
78
72
|
end
|
79
|
-
|
73
|
+
reruns -= tests
|
74
|
+
add_rerun_capsule(testcase: tests, usage: usage)
|
80
75
|
end
|
76
|
+
add_rerun_capsule(testcase: reruns) if reruns.any?
|
81
77
|
end
|
82
78
|
|
83
79
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
84
80
|
def inject_manual_reruns(patterns, usage)
|
81
|
+
tests = []
|
85
82
|
patterns.tr(' ', '').split(',').each do |pattern|
|
86
83
|
# Check if file exists first and handle if user supplies testcase:line_number
|
87
84
|
file_name = pattern.split(':')[0]
|
88
85
|
line_number_present = pattern.split(':').count > 1
|
89
86
|
matching_files = Dir.glob(file_name)
|
90
|
-
|
91
87
|
# If no file matches are run, don't queue up re-runs
|
92
88
|
if matching_files.count.zero?
|
93
89
|
puts "Specified pattern #{pattern} did not match an existing file"
|
94
90
|
raise ArgumentError
|
95
91
|
end
|
96
|
-
|
97
92
|
# It won't make sense to have multiple files to run with one specific line number
|
98
93
|
if line_number_present
|
99
94
|
if matching_files.count > 1
|
100
95
|
puts "Specified pattern #{pattern} matched multiple files but a line number was given"
|
101
96
|
raise ArgumentError
|
102
97
|
else
|
103
|
-
|
98
|
+
tests.push pattern
|
104
99
|
end
|
105
|
-
|
106
100
|
# No line numbers, queue up all matching files
|
107
101
|
else
|
108
102
|
matching_files.each do |file|
|
109
|
-
|
103
|
+
tests.push file
|
110
104
|
end
|
111
105
|
end
|
112
106
|
end
|
107
|
+
add_rerun_capsule(testcase: tests, usage: usage)
|
113
108
|
end
|
114
109
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
115
110
|
|
@@ -131,13 +126,18 @@ module FlakeySpecCatcher
|
|
131
126
|
end
|
132
127
|
|
133
128
|
def add_capsules_with_default_usage(reruns)
|
134
|
-
|
135
|
-
@rerun_capsules.push(FlakeySpecCatcher::RerunCapsule.new(testcase: rerun))
|
136
|
-
end
|
129
|
+
@rerun_capsules.push(FlakeySpecCatcher::RerunCapsule.new(testcase: reruns)) unless reruns.empty?
|
137
130
|
end
|
138
131
|
|
139
|
-
def add_rerun_capsule(testcase:
|
140
|
-
|
132
|
+
def add_rerun_capsule(testcase: [], usage: nil)
|
133
|
+
return if testcase.empty?
|
134
|
+
|
135
|
+
capsule = @rerun_capsules.find { |cap| cap.usage == usage }
|
136
|
+
if capsule
|
137
|
+
capsule.testcase.push(testcase)
|
138
|
+
else
|
139
|
+
@rerun_capsules.push(FlakeySpecCatcher::RerunCapsule.new(testcase: testcase, usage: usage))
|
140
|
+
end
|
141
141
|
end
|
142
142
|
end
|
143
143
|
end
|
@@ -44,10 +44,12 @@ module FlakeySpecCatcher
|
|
44
44
|
def rerun_preview
|
45
45
|
puts "\n********************************************"
|
46
46
|
puts "Re-run Preview\n"
|
47
|
-
@rerun_manager.rerun_capsules.
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
@rerun_manager.rerun_capsules.each do |capsule|
|
48
|
+
capsule.testcase.each do |test|
|
49
|
+
rerun_msg = " Running #{test} #{@user_config.repeat_factor} times "
|
50
|
+
rerun_msg += "using `#{capsule.usage}`" unless capsule.default_usage?
|
51
|
+
puts rerun_msg
|
52
|
+
end
|
51
53
|
end
|
52
54
|
puts "\n********************************************"
|
53
55
|
end
|
@@ -55,8 +57,8 @@ module FlakeySpecCatcher
|
|
55
57
|
|
56
58
|
def run_specs
|
57
59
|
status = 0
|
58
|
-
@
|
59
|
-
@
|
60
|
+
@rerun_manager.rerun_capsules.sort.each do |capsule|
|
61
|
+
@user_config.repeat_factor.times do
|
60
62
|
iteration_status = handle_capsule_rerun(capsule)
|
61
63
|
status = [status, iteration_status].max
|
62
64
|
end
|
@@ -85,11 +87,9 @@ module FlakeySpecCatcher
|
|
85
87
|
end
|
86
88
|
|
87
89
|
def invoke_custom_rspec_runner(usage, testcase)
|
88
|
-
custom_usage_output = `#{usage} #{testcase}`
|
90
|
+
custom_usage_output = `#{usage} #{testcase.join(' ')}`
|
89
91
|
|
90
|
-
if @user_config.output_file != '/dev/null'
|
91
|
-
File.open(@user_config.output_file, 'a') { |f| f.puts custom_usage_output }
|
92
|
-
end
|
92
|
+
File.open(@user_config.output_file, 'a') { |f| f.puts custom_usage_output } if @user_config.output_file != '/dev/null'
|
93
93
|
|
94
94
|
$?.exitstatus # rubocop:disable Style/SpecialGlobalVars
|
95
95
|
end
|
@@ -6,7 +6,6 @@ module FlakeySpecCatcher
|
|
6
6
|
#
|
7
7
|
# Captures user-defined settings to configure RSpec re-run settings.
|
8
8
|
|
9
|
-
# rubocop:disable Metrics/ClassLength
|
10
9
|
class UserConfig
|
11
10
|
attr_reader :repeat_factor, :ignore_files, :ignore_branches, :silent_mode
|
12
11
|
attr_reader :rerun_file_only, :rspec_usage_patterns, :excluded_tags
|
@@ -171,5 +170,4 @@ module FlakeySpecCatcher
|
|
171
170
|
end
|
172
171
|
# rubocop:enable Metrics/CyclomaticComplexity
|
173
172
|
end
|
174
|
-
# rubocop:enable Metrics/ClassLength
|
175
173
|
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.
|
4
|
+
version: 0.9.0
|
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-
|
13
|
+
date: 2020-02-07 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -122,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '0'
|
124
124
|
requirements: []
|
125
|
-
|
126
|
-
rubygems_version: 2.7.7
|
125
|
+
rubygems_version: 3.0.4
|
127
126
|
signing_key:
|
128
127
|
specification_version: 4
|
129
128
|
summary: Run new or changed specs many times to prevent unreliable specs
|