flakey_spec_catcher 0.9.8 → 0.11.2
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 +1 -0
- data/flakey_spec_catcher.gemspec +6 -4
- data/lib/flakey_spec_catcher/change_capsule.rb +35 -7
- data/lib/flakey_spec_catcher/cli_override.rb +10 -1
- data/lib/flakey_spec_catcher/git_controller.rb +7 -40
- data/lib/flakey_spec_catcher/rerun_manager.rb +30 -0
- data/lib/flakey_spec_catcher/runner.rb +2 -0
- data/lib/flakey_spec_catcher/user_config.rb +9 -3
- data/lib/flakey_spec_catcher/version.rb +1 -1
- metadata +38 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adf31fd04e49611a2c10622b19350ab444224589815ac5f54948ec6aad53fc3a
|
4
|
+
data.tar.gz: 23526cc9694ac22402e6b47fbe956197af5be8b5648abba785e822884e1cd747
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e15abca29cc1a0186ceadcb83f6238c3a847b4f59747e8c8bc0ef23387ed2a8b5cf3777675d32690bfb529b8e7aba6e6e8ba9970d3d9628628392cfa346506b
|
7
|
+
data.tar.gz: ce915b99014c9eee3210e55663dec289b20dcb39936a28ffd299fc7c0bb003561ef3d67e4a620bf28057e8ae4fe60aca1ed17f2e66436aa6d0f0fdae928e2629
|
data/.gitignore
CHANGED
data/flakey_spec_catcher.gemspec
CHANGED
@@ -28,11 +28,13 @@ Gem::Specification.new do |gem|
|
|
28
28
|
gem.require_paths = ['lib']
|
29
29
|
|
30
30
|
gem.metadata['allowed_push_host'] = 'https://rubygems.org'
|
31
|
-
gem.required_ruby_version = '>= 2.
|
31
|
+
gem.required_ruby_version = '>= 2.6'
|
32
32
|
|
33
|
-
gem.add_dependency 'rspec', '~> 3.
|
33
|
+
gem.add_dependency 'rspec', '~> 3.10'
|
34
|
+
gem.add_development_dependency 'byebug', '~> 11.1'
|
34
35
|
gem.add_development_dependency 'climate_control', '~> 0.2'
|
35
|
-
gem.add_development_dependency 'rake', '~>
|
36
|
-
gem.add_development_dependency '
|
36
|
+
gem.add_development_dependency 'rake', '~> 13.0'
|
37
|
+
gem.add_development_dependency 'rubocop', '~> 0.93.1'
|
38
|
+
gem.add_development_dependency 'simplecov', '~> 0.19'
|
37
39
|
end
|
38
40
|
# rubocop:enable Layout/ExtraSpacing, Layout/SpaceAroundOperators
|
@@ -8,7 +8,7 @@ module FlakeySpecCatcher
|
|
8
8
|
# A ChangeCapsule object will represent the changes made to a block of code. It
|
9
9
|
# accomplishes this using ChangeContext and ChangeSummary objects.
|
10
10
|
class ChangeCapsule
|
11
|
-
attr_reader :file_name, :change_summary, :change_contexts
|
11
|
+
attr_reader :file_name, :change_summary, :change_contexts, :spec_tree
|
12
12
|
SCOPE_SPECIFIERS = %w[it context describe scenario].freeze
|
13
13
|
SHARED_EXAMPLES = %w[include_examples it_behaves_like it_should_behave_like matching].freeze
|
14
14
|
|
@@ -16,6 +16,7 @@ module FlakeySpecCatcher
|
|
16
16
|
@file_name = file_name
|
17
17
|
@change_summary = change_summary
|
18
18
|
@change_contexts = []
|
19
|
+
@spec_tree = {}
|
19
20
|
handle_initial_change_contexts(change_contexts)
|
20
21
|
end
|
21
22
|
|
@@ -23,23 +24,30 @@ module FlakeySpecCatcher
|
|
23
24
|
@change_contexts.map(&:rerun_info)
|
24
25
|
end
|
25
26
|
|
27
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
26
28
|
def fill_contexts
|
27
29
|
change_context_stack = []
|
28
30
|
ignore_scope_closure = 0
|
29
31
|
lines_in_file = File.read(@file_name).split("\n")
|
30
32
|
lines_in_file.each_with_index do |line, index|
|
33
|
+
shared_example_identified = false
|
34
|
+
|
31
35
|
# Check if line matches an rspec example or examplegroup format
|
32
36
|
if line =~ spec_scope
|
33
37
|
handle_change_context(line, index, change_context_stack)
|
34
38
|
# Else, ignore other blocks that might pollute context stack
|
39
|
+
elsif line =~ shared_example_scope
|
40
|
+
handle_change_context(line, index, change_context_stack)
|
41
|
+
shared_example_identified = true
|
35
42
|
elsif line_matches_method_or_block(line)
|
36
43
|
ignore_scope_closure += 1
|
37
44
|
end
|
38
45
|
|
39
46
|
fill_context(line, index, change_context_stack)
|
40
47
|
|
41
|
-
|
42
|
-
|
48
|
+
if shared_example_identified
|
49
|
+
change_context_stack.pop
|
50
|
+
elsif line =~ pop_scope
|
43
51
|
if ignore_scope_closure.positive?
|
44
52
|
ignore_scope_closure -= 1
|
45
53
|
else
|
@@ -48,6 +56,7 @@ module FlakeySpecCatcher
|
|
48
56
|
end
|
49
57
|
end
|
50
58
|
end
|
59
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
51
60
|
|
52
61
|
private
|
53
62
|
|
@@ -69,14 +78,15 @@ module FlakeySpecCatcher
|
|
69
78
|
end
|
70
79
|
|
71
80
|
def spec_scope
|
72
|
-
# Not sure if we need to check for description in quotes
|
73
|
-
# spec_scope = /^\s*(#{SCOPE_SPECIFIERS.join("|")})\s*('.*'|".*").*do\s*$/
|
74
|
-
|
75
81
|
/\s*(#{SCOPE_SPECIFIERS.join("|")}).*\s+do.*$/
|
76
82
|
end
|
77
83
|
|
84
|
+
def shared_example_scope
|
85
|
+
/\s*(#{SHARED_EXAMPLES.join("|")}).*\s+.*$/
|
86
|
+
end
|
87
|
+
|
78
88
|
def line_matches_method_or_block(line)
|
79
|
-
return true if line =~ /\s*do(\s+|$)/ || line =~ /^\s*def\s+/ || line =~ /^\s*if\s+/
|
89
|
+
return true if line =~ /\s*do(\s+|$)/ || line =~ /^\s*def\s+/ || line =~ /^\s*if\s+/ || line =~ /^\s*class\s+/
|
80
90
|
|
81
91
|
false
|
82
92
|
end
|
@@ -112,6 +122,24 @@ module FlakeySpecCatcher
|
|
112
122
|
|
113
123
|
change_context_stack.push(change_context) unless
|
114
124
|
change_context_stack.any? { |c| c == change_context }
|
125
|
+
|
126
|
+
build_spec_tree(change_context_stack)
|
127
|
+
end
|
128
|
+
|
129
|
+
def build_spec_tree(change_contexts)
|
130
|
+
return unless change_contexts.count > 1
|
131
|
+
|
132
|
+
current_scope = change_contexts[-1].rerun_info
|
133
|
+
parent_scope = change_contexts[-2].rerun_info
|
134
|
+
|
135
|
+
# Don't build the file level context into spec tree
|
136
|
+
return unless parent_scope =~ /:/
|
137
|
+
|
138
|
+
@spec_tree[parent_scope] = if @spec_tree[parent_scope]
|
139
|
+
@spec_tree[parent_scope] << current_scope
|
140
|
+
else
|
141
|
+
[current_scope]
|
142
|
+
end
|
115
143
|
end
|
116
144
|
end
|
117
145
|
end
|
@@ -8,7 +8,8 @@ module FlakeySpecCatcher
|
|
8
8
|
# Captures command line arguments for manual re-runs
|
9
9
|
class CliOverride
|
10
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, :verbose, :test_options
|
11
|
+
attr_reader :output_file, :split_nodes, :split_index, :verbose, :test_options, :break_on_first_failure
|
12
|
+
attr_reader :list_child_specs
|
12
13
|
|
13
14
|
def initialize
|
14
15
|
@dry_run = false
|
@@ -56,6 +57,14 @@ module FlakeySpecCatcher
|
|
56
57
|
@repeat_factor = remove_formatter_quotes(repeat).to_i
|
57
58
|
end
|
58
59
|
|
60
|
+
opts.on('--break-on-first-failure', 'Break on first failure') do |break_on_first_failure|
|
61
|
+
@break_on_first_failure = break_on_first_failure
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on('--list-child-specs', 'List Child Specs (Verbose Spec Listing') do |list_child_specs|
|
65
|
+
@list_child_specs = list_child_specs
|
66
|
+
end
|
67
|
+
|
59
68
|
opts.on('-e', '--excluded-tags=EXCLUDED_TAGS',
|
60
69
|
'Specify tags to exclude in a comma separated list') do |tags|
|
61
70
|
@excluded_tags = parse_tags(tags)
|
@@ -56,45 +56,12 @@ module FlakeySpecCatcher
|
|
56
56
|
return nil if @remote.nil?
|
57
57
|
|
58
58
|
working_branch = `git branch | grep '*'`.delete('*').gsub(/\s+/, '')
|
59
|
-
|
60
|
-
|
61
|
-
# Assume master if no matches
|
62
|
-
|
63
|
-
# Example output
|
64
|
-
# * remote origin
|
65
|
-
# Fetch URL: gerrit:repo
|
66
|
-
# Push URL: gerrit:repo
|
67
|
-
# HEAD branch: master
|
68
|
-
# Remote branches:
|
69
|
-
# dev/reports tracked
|
70
|
-
# edge tracked
|
71
|
-
# master tracked
|
72
|
-
# Local branch configured for 'git pull':
|
73
|
-
# master merges with remote master
|
74
|
-
# Local refs configured for 'git push':
|
75
|
-
# dev/reports pushes to dev/reports (up to date)
|
76
|
-
# master pushes to master (up to date)
|
77
|
-
|
78
|
-
remote_branches = `git remote show #{@remote}`.split("\n")
|
79
|
-
|
80
|
-
# Separate 'dev/reports pushes to dev/reports (up to date)' into
|
81
|
-
# ['dev/reports', 'dev/reports'] or [<LOCAL BRANCH>, <REMOTE BRANCH>]
|
82
|
-
remote_pairs = remote_branches.map { |r| r.scan(/(\S*)\s+pushes to\s+(\S*)\s+/).flatten }
|
83
|
-
|
84
|
-
# check if the working branch (currently checked out branch) corresponds to a remote_pair
|
85
|
-
# if so, use that remote pair for comparison, else use master
|
86
|
-
match = remote_pairs.find do |pair|
|
87
|
-
# working branch (pair[0]) pushes to remote (pair[1])
|
88
|
-
pair[0] == working_branch
|
89
|
-
end
|
59
|
+
branch_remote = `git config branch.#{working_branch}.remote`.strip
|
60
|
+
return 'master' unless @remote == branch_remote
|
90
61
|
|
91
|
-
remote_branch =
|
92
|
-
|
93
|
-
|
94
|
-
# match is formatted as [working_branch, remote]
|
95
|
-
match[1]
|
96
|
-
end
|
97
|
-
remote_branch
|
62
|
+
remote_branch = `git config branch.#{branch}.merge`.strip.sub(%r{^refs/heads/}, '')
|
63
|
+
remote_branch = nil if remote_branch.empty?
|
64
|
+
remote_branch || 'master'
|
98
65
|
end
|
99
66
|
|
100
67
|
def initialize_git_comparison(test_mode)
|
@@ -108,7 +75,7 @@ module FlakeySpecCatcher
|
|
108
75
|
@git_comparison = "#{@base_commit_sha}..#{@working_commit_sha}"
|
109
76
|
end
|
110
77
|
|
111
|
-
# rubocop:disable Metrics/
|
78
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
112
79
|
def parse_changes
|
113
80
|
# For each file, get the change block
|
114
81
|
diff_files.each do |filename|
|
@@ -128,7 +95,7 @@ module FlakeySpecCatcher
|
|
128
95
|
end
|
129
96
|
end
|
130
97
|
end
|
131
|
-
# rubocop:enable Metrics/
|
98
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
132
99
|
|
133
100
|
def identify_change_contexts
|
134
101
|
@capsule_manager.change_capsules.each(&:fill_contexts)
|
@@ -39,6 +39,7 @@ module FlakeySpecCatcher
|
|
39
39
|
else
|
40
40
|
all_non_example_groups - identify_tag_excluded_reruns
|
41
41
|
end
|
42
|
+
tests = transform_parent_specs(tests).flatten if @user_config.list_child_specs
|
42
43
|
filter_reruns_by_ignore_files(tests)
|
43
44
|
end
|
44
45
|
|
@@ -171,5 +172,34 @@ module FlakeySpecCatcher
|
|
171
172
|
@rerun_capsules.push(FlakeySpecCatcher::RerunCapsule.new(testcase: testcase, usage: usage))
|
172
173
|
end
|
173
174
|
end
|
175
|
+
|
176
|
+
def transform_file_level_change(test, tree)
|
177
|
+
# Map file level changes to the highest level Example Group in the tree
|
178
|
+
if test =~ /:/
|
179
|
+
test
|
180
|
+
else
|
181
|
+
tree.keys.first
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def transform_parent_specs(tests)
|
186
|
+
transformed_tests = []
|
187
|
+
|
188
|
+
tests.each do |test|
|
189
|
+
capsule = @git_controller.capsule_manager.change_capsules.find { |c| c.file_name == test.split(':')[0] }
|
190
|
+
spec_tree = capsule.spec_tree
|
191
|
+
test = transform_file_level_change(test, spec_tree)
|
192
|
+
# If test is a key in the spec_tree, it's an example group, so we queue up its descendant examples
|
193
|
+
if spec_tree[test]
|
194
|
+
spec_tree[test].each do |child|
|
195
|
+
transformed_tests << transform_parent_specs([child]).flatten
|
196
|
+
end
|
197
|
+
# Else test is just an example
|
198
|
+
else
|
199
|
+
transformed_tests << test
|
200
|
+
end
|
201
|
+
end
|
202
|
+
transformed_tests
|
203
|
+
end
|
174
204
|
end
|
175
205
|
end
|
@@ -36,6 +36,7 @@ module FlakeySpecCatcher
|
|
36
36
|
puts " Current Sha: #{@git_controller.working_commit_sha}"
|
37
37
|
puts " Base Sha: #{@git_controller.base_commit_sha}"
|
38
38
|
puts " Repeat factor: #{@user_config.repeat_factor}"
|
39
|
+
puts " Break on first failure: #{@user_config.break_on_first_failure}" if @user_config.break_on_first_failure
|
39
40
|
puts " Node Total: #{@user_config.split_nodes}" if @user_config.split_nodes
|
40
41
|
puts " Node Index: #{@user_config.split_index}" if @user_config.split_index
|
41
42
|
puts " Changed Specs Detected: #{@git_controller.changed_examples}"
|
@@ -75,6 +76,7 @@ module FlakeySpecCatcher
|
|
75
76
|
@user_config.repeat_factor.times do
|
76
77
|
iteration_status = handle_capsule_rerun(capsule)
|
77
78
|
status = [status, iteration_status].max
|
79
|
+
break if @user_config.break_on_first_failure && !status.zero?
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
@@ -12,10 +12,11 @@ module FlakeySpecCatcher
|
|
12
12
|
attr_reader :manual_rerun_patterns, :manual_rerun_usage
|
13
13
|
attr_reader :enable_runs, :output_file, :use_parent, :dry_run
|
14
14
|
attr_reader :split_nodes, :split_index, :verbose, :test_options
|
15
|
+
attr_reader :break_on_first_failure, :list_child_specs
|
15
16
|
|
16
17
|
USER_CONFIG_ENV_VARS = %w[FSC_REPEAT_FACTOR FSC_IGNORE_FILES FSC_IGNORE_BRANCHES
|
17
18
|
FSC_SILENT_MODE FSC_RERUN_FILE_ONLY FSC_USAGE_PATTERNS
|
18
|
-
FSC_EXCLUDED_TAGS FSC_OUTPUT_FILE].freeze
|
19
|
+
FSC_EXCLUDED_TAGS FSC_OUTPUT_FILE FSC_LIST_CHILD_SPECS].freeze
|
19
20
|
|
20
21
|
def initialize(cli_override: CliOverride.new)
|
21
22
|
apply_env_var_settings
|
@@ -32,6 +33,7 @@ module FlakeySpecCatcher
|
|
32
33
|
@ignore_branches = env_var_string_to_array(ENV['FSC_IGNORE_BRANCHES'])
|
33
34
|
@silent_mode = env_var_string_to_bool(ENV['FSC_SILENT_MODE'])
|
34
35
|
@rerun_file_only = env_var_string_to_bool(ENV['FSC_RERUN_FILE_ONLY'])
|
36
|
+
@list_child_specs = env_var_string_to_bool(ENV['FSC_LIST_CHILD_SPECS'])
|
35
37
|
@rspec_usage_patterns = env_var_string_to_pairs(ENV['FSC_USAGE_PATTERNS'])
|
36
38
|
@excluded_tags = env_var_string_to_tags(ENV['FSC_EXCLUDED_TAGS'])
|
37
39
|
@output_file = ENV['FSC_OUTPUT_FILE']
|
@@ -44,6 +46,8 @@ module FlakeySpecCatcher
|
|
44
46
|
@manual_rerun_usage = @cli_override.rerun_usage
|
45
47
|
@use_parent = @cli_override.use_parent
|
46
48
|
@repeat_factor = @cli_override.repeat_factor if @cli_override.repeat_factor.to_i.positive?
|
49
|
+
@break_on_first_failure = @cli_override.break_on_first_failure
|
50
|
+
@list_child_specs = @cli_override.list_child_specs unless @cli_override.list_child_specs.nil?
|
47
51
|
@enable_runs = @cli_override.enable_runs
|
48
52
|
@dry_run = @cli_override.dry_run
|
49
53
|
@split_nodes = @cli_override.split_nodes unless @cli_override.split_nodes.nil?
|
@@ -168,7 +172,7 @@ module FlakeySpecCatcher
|
|
168
172
|
end
|
169
173
|
end
|
170
174
|
|
171
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
175
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
172
176
|
def override_user_config(env_var, env_value)
|
173
177
|
case env_var
|
174
178
|
when 'FSC_REPEAT_FACTOR'
|
@@ -181,6 +185,8 @@ module FlakeySpecCatcher
|
|
181
185
|
@silent_mode = env_var_string_to_bool(env_value)
|
182
186
|
when 'FSC_RERUN_FILE_ONLY'
|
183
187
|
@rerun_file_only = env_var_string_to_bool(env_value)
|
188
|
+
when 'FSC_LIST_CHILD_SPECS'
|
189
|
+
@list_child_specs = env_var_string_to_bool(env_value)
|
184
190
|
when 'FSC_USAGE_PATTERNS'
|
185
191
|
@rspec_usage_patterns = env_var_string_to_pairs(env_value)
|
186
192
|
when 'FSC_EXCLUDED_TAGS'
|
@@ -189,6 +195,6 @@ module FlakeySpecCatcher
|
|
189
195
|
@output_file = env_value
|
190
196
|
end
|
191
197
|
end
|
192
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
198
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
193
199
|
end
|
194
200
|
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.11.2
|
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:
|
13
|
+
date: 2021-10-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -18,14 +18,28 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '3.
|
21
|
+
version: '3.10'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '3.
|
28
|
+
version: '3.10'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: byebug
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '11.1'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '11.1'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: climate_control
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -46,28 +60,42 @@ dependencies:
|
|
46
60
|
requirements:
|
47
61
|
- - "~>"
|
48
62
|
- !ruby/object:Gem::Version
|
49
|
-
version: '
|
63
|
+
version: '13.0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '13.0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rubocop
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - "~>"
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.93.1
|
50
78
|
type: :development
|
51
79
|
prerelease: false
|
52
80
|
version_requirements: !ruby/object:Gem::Requirement
|
53
81
|
requirements:
|
54
82
|
- - "~>"
|
55
83
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
84
|
+
version: 0.93.1
|
57
85
|
- !ruby/object:Gem::Dependency
|
58
86
|
name: simplecov
|
59
87
|
requirement: !ruby/object:Gem::Requirement
|
60
88
|
requirements:
|
61
89
|
- - "~>"
|
62
90
|
- !ruby/object:Gem::Version
|
63
|
-
version: '0.
|
91
|
+
version: '0.19'
|
64
92
|
type: :development
|
65
93
|
prerelease: false
|
66
94
|
version_requirements: !ruby/object:Gem::Requirement
|
67
95
|
requirements:
|
68
96
|
- - "~>"
|
69
97
|
- !ruby/object:Gem::Version
|
70
|
-
version: '0.
|
98
|
+
version: '0.19'
|
71
99
|
description:
|
72
100
|
email:
|
73
101
|
- bwatson@instructure.com
|
@@ -115,14 +143,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
115
143
|
requirements:
|
116
144
|
- - ">="
|
117
145
|
- !ruby/object:Gem::Version
|
118
|
-
version: '2.
|
146
|
+
version: '2.6'
|
119
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
148
|
requirements:
|
121
149
|
- - ">="
|
122
150
|
- !ruby/object:Gem::Version
|
123
151
|
version: '0'
|
124
152
|
requirements: []
|
125
|
-
rubygems_version: 3.0.
|
153
|
+
rubygems_version: 3.0.1
|
126
154
|
signing_key:
|
127
155
|
specification_version: 4
|
128
156
|
summary: Run new or changed specs many times to prevent unreliable specs
|