bilgerat 0.2.1

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.
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,52 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bilgerat (0.2.1)
5
+ cucumber (>= 1.0.0)
6
+ hipchat (~> 0.7.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ aruba (0.5.3)
12
+ childprocess (>= 0.3.6)
13
+ cucumber (>= 1.1.1)
14
+ rspec-expectations (>= 2.7.0)
15
+ builder (3.2.2)
16
+ childprocess (0.3.9)
17
+ ffi (~> 1.0, >= 1.0.11)
18
+ columnize (0.3.6)
19
+ cucumber (1.3.2)
20
+ builder (>= 2.1.2)
21
+ diff-lcs (>= 1.1.3)
22
+ gherkin (~> 2.12.0)
23
+ multi_json (~> 1.3)
24
+ debugger (1.2.2)
25
+ columnize (>= 0.3.1)
26
+ debugger-linecache (~> 1.1.1)
27
+ debugger-ruby_core_source (~> 1.1.5)
28
+ debugger-linecache (1.1.2)
29
+ debugger-ruby_core_source (>= 1.1.1)
30
+ debugger-ruby_core_source (1.1.7)
31
+ diff-lcs (1.2.4)
32
+ ffi (1.9.0)
33
+ gherkin (2.12.0)
34
+ multi_json (~> 1.3)
35
+ hipchat (0.7.0)
36
+ httparty
37
+ httparty
38
+ httparty (0.11.0)
39
+ multi_json (~> 1.0)
40
+ multi_xml (>= 0.5.2)
41
+ multi_json (1.7.7)
42
+ multi_xml (0.5.4)
43
+ rspec-expectations (2.13.0)
44
+ diff-lcs (>= 1.1.3, < 2.0)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ aruba (~> 0.5)
51
+ bilgerat!
52
+ debugger
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013 Medidata Solutions Worldwide
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,42 @@
1
+ bilgerat
2
+ ========
3
+
4
+ Bilgerat is a [cucumber](http://cukes.info/) output formatter that sends messages about failing scenarios to [HipChat](https://www.hipchat.com/) rooms.
5
+
6
+
7
+ usage
8
+ -----
9
+
10
+ In your Gemfile:
11
+
12
+ ```ruby
13
+ gem 'bilgerat', git: 'git@github.com:mdsol/bilgerat.git'
14
+ ```
15
+
16
+ On the command line:
17
+
18
+ ```
19
+ cucumber --format Bilgerat --out na --format pretty
20
+ ```
21
+
22
+
23
+ configuration
24
+ -----
25
+ You must supply a configuration file that contains credentials to use the HipChat API. By default Bilgerat looks for this file is config/hipchat.yml. You can override this location by setting the HIPCHAT_CONFIG_PATH environment variable.
26
+
27
+ The configuration file contains settings per context. You should set all configuration items in the default context. You can override these settings for other contexts. Use the BILGERAT_CONTEXT environment variable to choose the context.
28
+
29
+ For example our CI server runs cucumber scenarios in parallel for the first round, then reruns failing scenarios in the final round. Our config file looks like this:
30
+
31
+ ```
32
+ default:
33
+ user: 'Bilge Rat #{TEST_ENV_NUMBER}'
34
+ auth_token: 'goes here'
35
+ room: 'test room'
36
+ error_color: 'red'
37
+ first_round:
38
+ error_color: 'purple'
39
+ final_round:
40
+ user: 'Final Bilge Rat'
41
+ ```
42
+
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "bilgerat"
3
+ s.version = '0.2.1'
4
+ s.platform = Gem::Platform::RUBY
5
+ s.required_ruby_version = '>= 1.9.3'
6
+ s.authors = ["Joseph Shraibman"]
7
+ s.email = ["jshraibman@mdsol.com"]
8
+ s.homepage = "https://github.com/mdsol/bilgerat"
9
+ s.summary = "Cucumber output formatter that sends failure messages to Hipchat"
10
+
11
+ s.add_dependency "cucumber", ">= 1.0.0"
12
+ s.add_dependency 'hipchat', '~> 0.7.0'
13
+
14
+ s.add_development_dependency 'aruba', '~> 0.5'
15
+ s.add_development_dependency 'debugger'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
20
+ end
@@ -0,0 +1,21 @@
1
+ Feature: Error handling
2
+
3
+ @announce-stderr
4
+ Scenario: Undefined steps work
5
+ And a file named "features/scenario_with_unmatched_step_def.feature" with:
6
+ """
7
+ Feature: Outline
8
+
9
+ @tagtag
10
+ Scenario: blah blah
11
+ Given this passes
12
+ """
13
+ And a file named "features/step_definitions/steps.rb" with:
14
+ """
15
+ Given /^this passes$/ do
16
+ end
17
+ Given /^this passes$/ do
18
+ end
19
+ """
20
+ When I run bilgerat with: `cucumber --format Bilgerat --out na --format pretty`
21
+ Then there should be a hipchat post matching /.*Ambiguous match of "this passes".*/
@@ -0,0 +1,30 @@
1
+ Feature: Scenario outlines
2
+
3
+ Background:
4
+ Given a standard Cucumber project directory structure
5
+
6
+ Scenario: Full information is only printed for the first example
7
+ And a file named "features/scenario_with_failing_examples.feature" with:
8
+ """
9
+ Feature: Outline
10
+
11
+ @tagtag
12
+ Scenario Outline: blah blah
13
+ Given this <fails or passes>
14
+ Examples:
15
+ | fails or passes |
16
+ | passes |
17
+ | fails |
18
+ | fails |
19
+ """
20
+ And a file named "features/step_definitions/steps.rb" with:
21
+ """
22
+ Given /^this (fails|passes)$/ do |str|
23
+ str.should == 'passes'
24
+ end
25
+ """
26
+ When I run bilgerat with: `cucumber --format Bilgerat --out na --format pretty`
27
+ Then there should be a hipchat post matching /.*@tagtag.*Example #2 failed.*/
28
+ And there should not be a hipchat post matching /@tagtag.*Example #3 failed.*/
29
+ And there should be a hipchat post matching /.*Example #3 failed.*/
30
+
@@ -0,0 +1,34 @@
1
+ def debug_file_name
2
+ '/tmp/tempfile.xml'
3
+ end
4
+
5
+ When /^I run bilgerat with: `(.*)`$/ do |cmd|
6
+ step %Q{I run `env DEBUG_BILGERAT=#{debug_file_name} #{cmd}`}
7
+ end
8
+
9
+ When /^I clear hipchat posts$/ do
10
+ File.delete(debug_file_name) if File.exists?(debug_file_name)
11
+ end
12
+
13
+ Before do
14
+ step 'I clear hipchat posts'
15
+ end
16
+
17
+ # For debugging
18
+ Then /^I print the hipchat posts$/ do
19
+ puts File.read(debug_file_name)
20
+ end
21
+
22
+ Then /^there should (not )?be a hipchat post matching \/(.*)\/$/ do |should_not, pattern|
23
+ file_text = nil
24
+ File.open(debug_file_name, 'r') do |file|
25
+ file_text = file.read
26
+ end
27
+ re = Regexp.new("<HIPPOST>#{pattern}</HIPPOST>", Regexp::MULTILINE)
28
+
29
+ if should_not
30
+ file_text.should_not match(re)
31
+ else
32
+ file_text.should match(re)
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ # Copied from the cucumber project
4
+
5
+ Given /^I am in (.*)$/ do |example_dir_relative_path|
6
+ @current_dir = fixtures_dir(example_dir_relative_path)
7
+ end
8
+
9
+ Given /^a standard Cucumber project directory structure$/ do
10
+ @current_dir = `mktemp -d cuc.XXXXXX`.strip
11
+ #puts "created cuc dir #{@current_dir}"
12
+ in_current_dir do
13
+ FileUtils.rm_rf 'features' if File.directory?('features')
14
+ FileUtils.mkdir_p 'features/support'
15
+ FileUtils.mkdir 'features/step_definitions'
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ require 'aruba/cucumber'
4
+
5
+ After do
6
+ FileUtils.rm_rf @current_dir if @current_dir && File.directory?(@current_dir)
7
+ end
@@ -0,0 +1,5 @@
1
+ default:
2
+ user: 'Bilge Rat #{TEST_ENV_NUMBER}'
3
+ auth_token: 'goes here'
4
+ room: 'test room'
5
+ error_color: 'red'
@@ -0,0 +1,269 @@
1
+ # encoding: utf-8
2
+
3
+ # Based on https://github.com/cucumber/cucumber/blob/master/lib/cucumber/formatter/pretty.rb and the other cucumber
4
+ # built in formatters.
5
+ # There was no handy api so I had to reverse engineer
6
+
7
+ class Bilgerat
8
+
9
+ def initialize(step_mother, path_or_io, options)
10
+ end
11
+
12
+
13
+ def before_background(background)
14
+ @background_failed = nil
15
+ reset_scenario_info
16
+ @in_background = background
17
+ end
18
+
19
+ def after_background(background)
20
+ @in_background = nil
21
+ @background_tags = @tags
22
+ @tags = nil
23
+ end
24
+
25
+ def tag_name(tag)
26
+ (@tags ||= []) << tag
27
+ end
28
+
29
+ def scenario_name(keyword, name, file_colon_line, source_indent)
30
+ reset_scenario_info
31
+ @current_scenario_info = {keyword: keyword, name: name, file_colon_line: file_colon_line, tags: @tags}
32
+ @tags = nil
33
+ end
34
+
35
+ def after_table_row(table_row)
36
+ return unless @in_examples and Cucumber::Ast::OutlineTable::ExampleRow === table_row
37
+ @example_num += 1 if !@header_row
38
+ if table_row.exception
39
+ hipchat_exception(table_row.exception)
40
+ elsif !@header_row && table_row.failed?
41
+ hipchat_exception('<failure had no exception>')
42
+ end
43
+ @header_row = false
44
+ end
45
+
46
+ def before_examples(*args)
47
+ @in_examples = true
48
+ @header_row = true
49
+ end
50
+
51
+ def after_examples(*args)
52
+ @in_examples = false
53
+ end
54
+
55
+ def exception(exception, status)
56
+ hipchat_exception(exception)
57
+ end
58
+
59
+ # file_colon_line is new in cucumber 1.2.0. Give it default of nil to be reverse compatible
60
+ def step_name(keyword, step_match, status, source_indent, background, file_colon_line=nil)
61
+ @current_failed_step_info = nil
62
+ #TODO: detect if we are running in strict mode somehow, and if so also send a message when status == :pending
63
+ if status == :failed
64
+ @current_failed_step_info = {step_match: step_match, file_colon_line: file_colon_line, status: status}
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ # send failure report to hipchat
71
+ def hipchat_exception(exception)
72
+ # If the background fails only send one message the first time
73
+ return if @background_failed
74
+
75
+ # If this is a failing scenario output includes:
76
+ # 1a) file & line number for scenario
77
+ # 1b) all tags, including those declared on the feature
78
+ # 1c) scenario name
79
+ # 2) failing step
80
+ # 3) The exception
81
+
82
+ # If this is a failing example, then output includes:
83
+ # 1) For the first failing example in an outline the same as above, omitted for the subsequent examples
84
+ # 2) "Example #X failed:"
85
+ # 3) the exception
86
+
87
+ # If this was a failing background step:
88
+ # 1a) file & line number for background
89
+ # 1b) "Background step failed:"
90
+ # 2) failing step
91
+ # 3) the exception
92
+
93
+ sb = ''
94
+
95
+ # part 1
96
+ unless @had_failing_example
97
+ if @current_scenario_info
98
+ sb << "# #{ @current_scenario_info[:file_colon_line] }\n"
99
+ all_tags = (@background_tags || []) + (@current_scenario_info[:tags] || [])
100
+ sb << all_tags.join(' ') + "\n" if all_tags.size > 0
101
+ sb << "#{ @current_scenario_info[:keyword]}: #{ @current_scenario_info[:name]}\n"
102
+ elsif @in_background
103
+ sb << "# #{ @in_background.file_colon_line }\nBackground step failed:\n"
104
+ @background_failed = true
105
+ else
106
+ sb = 'error: no scenario info'
107
+ end
108
+ end
109
+
110
+ # part2
111
+ if @current_failed_step_info # Failing scenario or background, not example
112
+ sb << "#{ current_step_match_to_str } # "
113
+ fcl = @current_failed_step_info[:file_colon_line] # line in the feature file, may be nil
114
+ sb << fcl << ' → ' if fcl
115
+ sb << @current_failed_step_info[:step_match].file_colon_line << "\n"
116
+ elsif @example_num
117
+ @had_failing_example = true
118
+ sb << "Example ##{@example_num} failed:\n"
119
+ end
120
+
121
+ adapter.hip_post( "#{ sb }#{ build_exception_detail(exception) }", color: :error )
122
+ end
123
+
124
+ # Convert the step match (saved from step_name(), above into a string for outputting.
125
+ def current_step_match_to_str
126
+ current_step_match = @current_failed_step_info[:step_match]
127
+ # current_step_match might be a StepMatch or a NoStepMatch. If a NoStepMatch we must pass in dummy argument to format_args
128
+ args = current_step_match.is_a?(Cucumber::NoStepMatch)? [nil] : []
129
+ current_step_match.format_args(*args)
130
+ end
131
+
132
+ def adapter
133
+ HipchatAdapter
134
+ end
135
+
136
+ # Based on cucumber code
137
+ def build_exception_detail(exception)
138
+ return exception if exception.is_a? String
139
+ backtrace = Array.new
140
+
141
+ message = exception.message
142
+ if defined?(RAILS_ROOT) && message.include?('Exception caught')
143
+ matches = message.match(/Showing <i>(.+)<\/i>(?:.+) #(\d+)/)
144
+ backtrace += ["#{RAILS_ROOT}/#{matches[1]}:#{matches[2]}"] if matches
145
+ matches = message.match(/<code>([^(\/)]+)<\//m)
146
+ message = matches ? matches[1] : ""
147
+ end
148
+
149
+ unless exception.instance_of?(RuntimeError)
150
+ message = "#{message} (#{exception.class})"
151
+ end
152
+
153
+ message << "\n" << backtrace.join("\n")
154
+ end
155
+
156
+ def reset_scenario_info
157
+ @current_failed_step_info = @current_scenario_info = @example_num = @had_failing_example = nil
158
+ @example_num = 0
159
+ end
160
+
161
+ end
162
+
163
+ # In theory in the future there might be different adapters that can plug in to the output formatter, but for now
164
+ # there is just this one.
165
+ class HipchatAdapter
166
+
167
+ class << self
168
+ DEFAULTS = {
169
+ :message_format => 'text',
170
+ :notify => '1'
171
+ }.freeze
172
+
173
+
174
+ # Send a message to a HipChat room
175
+ # TODO: fork a thread so we don't block tests while we wait for the network. Also on the puts calls because on at
176
+ # least one occasion a call blocked and locked up cucumber.
177
+ def hip_post(message, options = {})
178
+ if ENV['DEBUG_BILGERAT']
179
+ unless @debug_file
180
+ @debug_file = File.open(ENV['DEBUG_BILGERAT'], 'w')
181
+ @debug_file.puts "<debugfile>"
182
+ at_exit { @debug_file.puts "</debugfile>" }
183
+ end
184
+ @debug_file.puts "<HIPPOST>#{ message }</HIPPOST>"
185
+ end
186
+
187
+ return unless configured?
188
+
189
+ def option(sym)
190
+ return options[sym] if options.keys.include?(sym)
191
+ DEFAULTS[sym]
192
+ end
193
+
194
+ # Replace the 'error' color with a real color
195
+ options[:color] = error_color if options[:color] == :error
196
+
197
+ begin
198
+ client[config['room']].send(username, message, DEFAULTS.merge(options))
199
+ #puts "sent msg to hipchat"
200
+ rescue => ex
201
+ STDERR.puts "Caught #{ex.class}; disabling hipchat notification"
202
+ @configured = false
203
+ end
204
+ end
205
+
206
+ # Config hash, from yml file
207
+
208
+ private
209
+
210
+ def error_color
211
+ @error_color ||= config['error_color'] || 'red'
212
+ end
213
+
214
+ # Returns something that looks like a hash. It returns values from the raw bash by first looking under the
215
+ # current context, then under 'default'
216
+ def config
217
+ config_file = ENV['HIPCHAT_CONFIG_PATH'] || 'config/hipchat.yml'
218
+ return nil unless File.exists?(config_file)
219
+
220
+
221
+ @config ||= Class.new do
222
+ @raw_config_yaml = YAML.load_file(config_file)
223
+
224
+ @context = ENV['BILGERAT_CONTEXT'] if ENV['BILGERAT_CONTEXT'] && ENV['BILGERAT_CONTEXT'].length > 0
225
+
226
+ def self.[](sym)
227
+ sym = sym.to_s
228
+ if @context
229
+ hash = @raw_config_yaml[@context]
230
+ return hash[sym] if hash && hash.keys.include?(sym)
231
+ end
232
+ @raw_config_yaml['default'][sym]
233
+ end
234
+ end
235
+ end
236
+
237
+ # Are we configured to send messages to HipChat? If not just drop messages.
238
+ def configured?
239
+ if @configured.nil?
240
+ @configured = !!(config && config['room'] && config['auth_token'])
241
+ else
242
+ @configured
243
+ end
244
+ end
245
+
246
+ def client
247
+ require 'hipchat'
248
+ @client ||= HipChat::Client.new(config['auth_token'])
249
+ end
250
+
251
+ # The username as we want it to appear in the HipChat room.
252
+ def username
253
+ @username ||= begin
254
+ env_var = config['user']
255
+ case env_var
256
+ when nil then
257
+ 'Bilge Rat'
258
+ when Regexp.compile('#{TEST_ENV_NUMBER}') then
259
+ test_env_number = ENV['TEST_ENV_NUMBER']
260
+ test_env_number = '1' if test_env_number == ''
261
+ env_var.gsub('#{TEST_ENV_NUMBER}', test_env_number || '')
262
+ else
263
+ env_var
264
+ end
265
+ end
266
+ end
267
+
268
+ end
269
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bilgerat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joseph Shraibman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cucumber
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: hipchat
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.7.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.7.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: aruba
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '0.5'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.5'
62
+ - !ruby/object:Gem::Dependency
63
+ name: debugger
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description:
79
+ email:
80
+ - jshraibman@mdsol.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - Gemfile
86
+ - Gemfile.lock
87
+ - LICENSE
88
+ - README.md
89
+ - bilgerat.gemspec
90
+ - features/error_handling.feature
91
+ - features/outlines/main.feature
92
+ - features/step_definitions/bilgerat_steps.rb
93
+ - features/step_definitions/cucumber_steps.rb
94
+ - features/support/base.rb
95
+ - hipchat.yml.sample
96
+ - lib/bilgerat.rb
97
+ homepage: https://github.com/mdsol/bilgerat
98
+ licenses: []
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ! '>='
107
+ - !ruby/object:Gem::Version
108
+ version: 1.9.3
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 1.8.24
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Cucumber output formatter that sends failure messages to Hipchat
121
+ test_files:
122
+ - features/error_handling.feature
123
+ - features/outlines/main.feature
124
+ - features/step_definitions/bilgerat_steps.rb
125
+ - features/step_definitions/cucumber_steps.rb
126
+ - features/support/base.rb
127
+ has_rdoc: