flakey_spec_catcher 0.8.0 → 0.9.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/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
|