bumps 0.0.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/History.txt +5 -0
- data/Manifest.txt +36 -0
- data/README.rdoc +59 -0
- data/Rakefile +29 -0
- data/TODO +20 -0
- data/examples/feature_server +61 -0
- data/features/pull_remote_features.feature +17 -0
- data/features/push_feature_results.feature +11 -0
- data/features/steps/command_output.rb +3 -0
- data/features/steps/cucumber_run.rb +3 -0
- data/features/steps/env.rb +88 -0
- data/features/steps/feature_report.rb +6 -0
- data/features/steps/feature_server.rb +14 -0
- data/features/steps/helpers/scenario_process.rb +67 -0
- data/lib/bumps.rb +25 -0
- data/lib/bumps/configuration.rb +48 -0
- data/lib/bumps/feature.rb +54 -0
- data/lib/bumps/hook_tasks.rb +25 -0
- data/lib/bumps/pre_feature_load_hook.rb +27 -0
- data/lib/bumps/remote_feature.rb +23 -0
- data/lib/bumps/results_push_formatter.rb +37 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/bumps/configuration_spec.rb +78 -0
- data/spec/bumps/feature_spec.rb +119 -0
- data/spec/bumps/hook_tasks_spec.rb +98 -0
- data/spec/bumps/pre_feature_load_hook_spec.rb +44 -0
- data/spec/bumps/remote_feature_spec.rb +70 -0
- data/spec/bumps/results_push_formatter_spec.rb +126 -0
- data/spec/bumps_spec.rb +20 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- data/tasks/rspec.rake +21 -0
- data/test_features/remote_content/destroy_dr_thaddeus_venture.feature +12 -0
- data/test_features/requires/env.rb +3 -0
- metadata +141 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.rdoc
|
4
|
+
Rakefile
|
5
|
+
TODO
|
6
|
+
examples/feature_server
|
7
|
+
features/pull_remote_features.feature
|
8
|
+
features/push_feature_results.feature
|
9
|
+
features/steps/command_output.rb
|
10
|
+
features/steps/cucumber_run.rb
|
11
|
+
features/steps/env.rb
|
12
|
+
features/steps/feature_report.rb
|
13
|
+
features/steps/feature_server.rb
|
14
|
+
features/steps/helpers/scenario_process.rb
|
15
|
+
lib/bumps.rb
|
16
|
+
lib/bumps/configuration.rb
|
17
|
+
lib/bumps/feature.rb
|
18
|
+
lib/bumps/hook_tasks.rb
|
19
|
+
lib/bumps/pre_feature_load_hook.rb
|
20
|
+
lib/bumps/remote_feature.rb
|
21
|
+
lib/bumps/results_push_formatter.rb
|
22
|
+
script/console
|
23
|
+
script/destroy
|
24
|
+
script/generate
|
25
|
+
spec/bumps/configuration_spec.rb
|
26
|
+
spec/bumps/feature_spec.rb
|
27
|
+
spec/bumps/hook_tasks_spec.rb
|
28
|
+
spec/bumps/pre_feature_load_hook_spec.rb
|
29
|
+
spec/bumps/remote_feature_spec.rb
|
30
|
+
spec/bumps/results_push_formatter_spec.rb
|
31
|
+
spec/bumps_spec.rb
|
32
|
+
spec/spec.opts
|
33
|
+
spec/spec_helper.rb
|
34
|
+
tasks/rspec.rake
|
35
|
+
test_features/remote_content/destroy_dr_thaddeus_venture.feature
|
36
|
+
test_features/requires/env.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= Bumps
|
2
|
+
|
3
|
+
* http://github.com/brentsnook/bumps
|
4
|
+
|
5
|
+
Bumps shakes up {Cucumber}[http://cukes.info] by allowing you to pull feature content and push run results to and from a remote server. This means that your feature files no longer need to live with your steps and other code. This also means that you can publish the results of a Cucumber run to another system.
|
6
|
+
|
7
|
+
See the {wiki}[http://wiki.github.com/brentsnook/bumps] for more details.
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
sudo gem install bumps
|
12
|
+
|
13
|
+
=== Building the Gem yourself
|
14
|
+
|
15
|
+
Grab the code from github:
|
16
|
+
|
17
|
+
git clone git://github.com/brentsnook/bumps.git
|
18
|
+
cd bumps
|
19
|
+
rake install_gem
|
20
|
+
|
21
|
+
== How do I use it?
|
22
|
+
|
23
|
+
First, start up a server that meets the {push/pull contract}[http://wiki.github.com/brentsnook/bumps/push-pull-contract].
|
24
|
+
|
25
|
+
Secondly, bung this inside of your *env.rb* (or equivalent, just make sure it is under the feature directory):
|
26
|
+
|
27
|
+
require 'bumps'
|
28
|
+
Bumps.configure { use_server 'http://mycompliantserver.com' }
|
29
|
+
|
30
|
+
Lastly, just run Cukes as normal.
|
31
|
+
|
32
|
+
cucumber my_feature_directory
|
33
|
+
|
34
|
+
Bumps will pull feature files into the specified feature directory, run cukes and then push the results back to the server.
|
35
|
+
|
36
|
+
== License
|
37
|
+
|
38
|
+
(The MIT License)
|
39
|
+
|
40
|
+
Copyright (c) 2009 Brent Snook http://fuglylogic.com
|
41
|
+
|
42
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
43
|
+
a copy of this software and associated documentation files (the
|
44
|
+
'Software'), to deal in the Software without restriction, including
|
45
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
46
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
47
|
+
permit persons to whom the Software is furnished to do so, subject to
|
48
|
+
the following conditions:
|
49
|
+
|
50
|
+
The above copyright notice and this permission notice shall be
|
51
|
+
included in all copies or substantial portions of the Software.
|
52
|
+
|
53
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
54
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
55
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
56
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
57
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
58
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
59
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/bumps'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('bumps', Bumps::VERSION) do |p|
|
7
|
+
p.developer 'Brent Snook', 'brent@fuglylogic.com'
|
8
|
+
p.summary = %q{Remote feature management for Cucumber.}
|
9
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
10
|
+
p.rubyforge_name = p.name
|
11
|
+
p.extra_deps = [
|
12
|
+
['cucumber', ">= #{Bumps::LOWEST_SUPPORTED_CUCUMBER_VERSION}"],
|
13
|
+
['nokogiri','>= 1.1.1'],
|
14
|
+
]
|
15
|
+
p.extra_dev_deps = [
|
16
|
+
['newgem', ">= #{::Newgem::VERSION}"],
|
17
|
+
['rspec', '>= 1.2.7'],
|
18
|
+
]
|
19
|
+
|
20
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
21
|
+
path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
|
22
|
+
p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
|
23
|
+
p.rsync_args = '-av --delete --ignore-errors'
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'newgem/tasks' # load /tasks/*.rake
|
27
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
28
|
+
|
29
|
+
task :default => [:spec, :features]
|
data/TODO
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
- tag release
|
2
|
+
- release gem on rubyforge
|
3
|
+
|
4
|
+
- register google group and update wiki doco
|
5
|
+
|
6
|
+
|
7
|
+
- add blog post on what it is, how to use it and why
|
8
|
+
|
9
|
+
- publish on twitter
|
10
|
+
- post to wave google group (links to blog)
|
11
|
+
- post to cucumber google group (links to blog)
|
12
|
+
|
13
|
+
--- LATER ---
|
14
|
+
|
15
|
+
- add validation for config and some nicer messages?
|
16
|
+
- get rid of treetop gibberish
|
17
|
+
- can it be more of a synch than a straight clobber??? for speed mainly
|
18
|
+
- extract process control logic out into a new gem
|
19
|
+
- support obtaining details for a single feature ???
|
20
|
+
- create lighthouse project
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
include WEBrick
|
5
|
+
|
6
|
+
class PullServlet < HTTPServlet::AbstractServlet
|
7
|
+
|
8
|
+
def do_GET(request, response)
|
9
|
+
response.body = feature_content
|
10
|
+
response['Content-Type'] = 'text/xml'
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def feature_content
|
16
|
+
content = StringIO.new
|
17
|
+
content.puts '<?xml version="1.0"?>'
|
18
|
+
content.puts '<features>'
|
19
|
+
|
20
|
+
Dir.glob(features_pattern).each do |file|
|
21
|
+
content << feature_within(file) if File.file?(file)
|
22
|
+
end
|
23
|
+
|
24
|
+
content.puts '</features>'
|
25
|
+
|
26
|
+
content.string
|
27
|
+
end
|
28
|
+
|
29
|
+
def feature_within file
|
30
|
+
relative_path = file[(@options[0].length)..-1]
|
31
|
+
"<feature name=\"#{relative_path}\"> #{IO.read(file)}\n </feature>"
|
32
|
+
end
|
33
|
+
|
34
|
+
def features_pattern
|
35
|
+
File.join @options[0], '**', '*'
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class PushServlet < HTTPServlet::AbstractServlet
|
41
|
+
|
42
|
+
def do_POST(request, response)
|
43
|
+
File.open(@options[0], 'w'){ |f| f.write(request.query['results']) }
|
44
|
+
response['Content-Type'] = 'text/html'
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
server = WEBrick::HTTPServer.new :Port => 1981
|
50
|
+
|
51
|
+
server.mount "/features/content", PullServlet, ARGV[0]
|
52
|
+
server.mount "/features/results", PushServlet, ARGV[1]
|
53
|
+
|
54
|
+
%w(INT TERM).each do |signal|
|
55
|
+
trap signal do
|
56
|
+
server.shutdown
|
57
|
+
exit!
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
server.start
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: Pull remote features
|
2
|
+
|
3
|
+
As a developer
|
4
|
+
I want to pull Cucumber features from a remote location
|
5
|
+
So that the features can be authored using a separate tool
|
6
|
+
|
7
|
+
Scenario: Remote features pulled successfully
|
8
|
+
|
9
|
+
Given that a feature server is running
|
10
|
+
When a cucumber run is performed
|
11
|
+
Then the feature report will contain all remote features
|
12
|
+
|
13
|
+
Scenario: Feature server not reachable
|
14
|
+
|
15
|
+
Given that a feature server is not running
|
16
|
+
When a cucumber run is performed
|
17
|
+
Then the command output should show that features could not be pulled
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Feature: Serve feature results
|
2
|
+
|
3
|
+
As a remote feature authoring tool
|
4
|
+
I want to be informed of the results of a feature run
|
5
|
+
So that I can format my local feature data accordingly
|
6
|
+
|
7
|
+
Scenario: Push all feature results after a run
|
8
|
+
|
9
|
+
Given that a feature server is running
|
10
|
+
When a cucumber run is performed
|
11
|
+
Then the results of the feature run will be sent to the feature server
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../lib/bumps"
|
2
|
+
|
3
|
+
gem 'cucumber'
|
4
|
+
require 'cucumber'
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
|
8
|
+
module CucumberWorld
|
9
|
+
|
10
|
+
def feature_report_file
|
11
|
+
File.expand_path File.join(root, 'tmp', 'cucumber.out')
|
12
|
+
end
|
13
|
+
|
14
|
+
def feature_report
|
15
|
+
IO.read feature_report_file
|
16
|
+
end
|
17
|
+
|
18
|
+
def command_output
|
19
|
+
IO.read command_output_file
|
20
|
+
end
|
21
|
+
|
22
|
+
def feature_server_script
|
23
|
+
File.expand_path File.join(root, 'examples', 'feature_server')
|
24
|
+
end
|
25
|
+
|
26
|
+
def push_request_file
|
27
|
+
File.expand_path File.join(root, 'tmp', 'results.xml')
|
28
|
+
end
|
29
|
+
|
30
|
+
def push_request
|
31
|
+
IO.read push_request_file
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_require_file
|
35
|
+
File.expand_path File.join(root, 'test_features', 'requires', 'env.rb')
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_features_directory
|
39
|
+
File.expand_path File.join(root, 'tmp')
|
40
|
+
end
|
41
|
+
|
42
|
+
def feature_server_command
|
43
|
+
"ruby #{feature_server_script} #{remote_features_directory} #{push_request_file}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def each_feature
|
47
|
+
Dir.glob("#{remote_features_directory}/**/*") do |feature_file|
|
48
|
+
content = IO.read(feature_file).strip
|
49
|
+
yield content.first.strip
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def clean
|
54
|
+
FileUtils.remove_entry_secure test_features_directory
|
55
|
+
FileUtils.mkdir test_features_directory
|
56
|
+
[
|
57
|
+
feature_report_file,
|
58
|
+
push_request_file
|
59
|
+
].each do |file|
|
60
|
+
FileUtils.remove_entry_secure file if File.exist? file
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def root
|
67
|
+
File.expand_path File.join(File.dirname(__FILE__), '..', '..')
|
68
|
+
end
|
69
|
+
|
70
|
+
def command_output_file
|
71
|
+
File.expand_path File.join(root, 'tmp', 'cucumber.log')
|
72
|
+
end
|
73
|
+
|
74
|
+
def remote_features_directory
|
75
|
+
File.expand_path File.join(root, 'test_features', 'remote_content')
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
World CucumberWorld
|
81
|
+
|
82
|
+
Before do
|
83
|
+
clean
|
84
|
+
end
|
85
|
+
|
86
|
+
After do
|
87
|
+
ScenarioProcess.kill_all
|
88
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Given /^that a feature server is running$/ do
|
2
|
+
ScenarioProcess.run feature_server_command, 'feature_server'
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^that a feature server is not running$/ do
|
6
|
+
ScenarioProcess.kill feature_server_command
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the results of the feature run will be sent to the feature server$/ do
|
10
|
+
each_feature do |feature|
|
11
|
+
push_request.should match(/#{feature}/)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class ScenarioProcess
|
2
|
+
|
3
|
+
@commands = []
|
4
|
+
|
5
|
+
def initialize command, name
|
6
|
+
@command = command
|
7
|
+
@name = name
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
remove log
|
12
|
+
IO.popen(full_command).sync = true
|
13
|
+
wait_for log
|
14
|
+
end
|
15
|
+
|
16
|
+
def run_and_wait
|
17
|
+
remove log
|
18
|
+
`#{full_command}`
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.run command, name
|
22
|
+
new(command,name).run
|
23
|
+
@commands << command
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.run_and_wait command, name
|
27
|
+
new(command,name).run_and_wait
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.kill_all
|
31
|
+
@commands.each { |command| kill command }
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.kill command
|
35
|
+
# this method of killing stuff sucks, feels brittle
|
36
|
+
|
37
|
+
`ps`.each do |process|
|
38
|
+
# the space at the front of the pattern is essential...
|
39
|
+
# otherwise this will only work intermittently; if the pid you want to kill
|
40
|
+
# is shorter than others in the process list then the group will not capture it
|
41
|
+
matches = process.match /\s*(\d*).*#{Regexp.escape(command)}/
|
42
|
+
`kill #{matches[1]}` if matches
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def log
|
49
|
+
File.expand_path(File.dirname(__FILE__) + "/../../../tmp/#{@name}.log")
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove file
|
53
|
+
FileUtils.rm file, :force => true
|
54
|
+
end
|
55
|
+
|
56
|
+
def full_command
|
57
|
+
"(#{@command}) > #{log} 2>&1"
|
58
|
+
end
|
59
|
+
|
60
|
+
def wait_for file
|
61
|
+
until File.exists? file
|
62
|
+
sleep 0.2
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/bumps.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'cucumber'
|
6
|
+
|
7
|
+
[
|
8
|
+
'remote_feature',
|
9
|
+
'feature',
|
10
|
+
'configuration',
|
11
|
+
'results_push_formatter',
|
12
|
+
'hook_tasks',
|
13
|
+
'pre_feature_load_hook'
|
14
|
+
].each {|file| require "bumps/#{file}"}
|
15
|
+
|
16
|
+
module Bumps
|
17
|
+
|
18
|
+
VERSION = '0.0.1'
|
19
|
+
LOWEST_SUPPORTED_CUCUMBER_VERSION = '0.3.11'
|
20
|
+
|
21
|
+
def self.configure &block
|
22
|
+
Configuration.configure(&block)
|
23
|
+
PreFeatureLoadHook.register_on Cucumber::Cli::Main
|
24
|
+
end
|
25
|
+
end
|