guillaumegentil-rspactor 0.4.3 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +4 -3
- data/bin/rspactor +3 -1
- data/lib/rspactor.rb +2 -0
- data/lib/rspactor/celerity.rb +29 -0
- data/lib/rspactor/inspector.rb +19 -8
- data/lib/rspactor/interactor.rb +13 -3
- data/lib/rspactor/runner.rb +15 -9
- data/lib/rspactor/spork.rb +25 -0
- data/spec/inspector_spec.rb +2 -1
- data/spec/runner_spec.rb +4 -4
- metadata +9 -9
- data/bin/rspactor-system +0 -93
data/Rakefile
CHANGED
@@ -9,9 +9,10 @@ desc "generates .gemspec file"
|
|
9
9
|
task :gemspec => "version:read" do
|
10
10
|
spec = Gem::Specification.new do |gem|
|
11
11
|
gem.name = "rspactor"
|
12
|
-
gem.summary = "RSpactor is a command line tool to automatically run your changed specs (much like autotest)."
|
13
|
-
gem.
|
14
|
-
gem.
|
12
|
+
gem.summary = "RSpactor is a command line tool to automatically run your changed specs & cucumber features (much like autotest)."
|
13
|
+
gem.description = "read summary!"
|
14
|
+
gem.email = "guillaumegentil@gmail.com"
|
15
|
+
gem.homepage = "http://github.com/guillaumegentil/rspactor"
|
15
16
|
gem.authors = ["Mislav Marohnić", "Andreas Wolff", "Pelle Braendgaard", "Thibaud Guillaume-Gentil"]
|
16
17
|
gem.has_rdoc = false
|
17
18
|
|
data/bin/rspactor
CHANGED
@@ -3,7 +3,9 @@ require 'rspactor/runner'
|
|
3
3
|
|
4
4
|
RSpactor::Runner.start({
|
5
5
|
:coral => ARGV.delete('--coral'),
|
6
|
-
:
|
6
|
+
:celerity => ARGV.delete('--celerity'),
|
7
|
+
:spork => ARGV.delete('--drb'),
|
8
|
+
:view => ARGV.delete('--view'), # by default, rspactor didn't catch specs view
|
7
9
|
:clear => ARGV.delete('--clear'),
|
8
10
|
:run_in => ARGV.last
|
9
11
|
})
|
data/lib/rspactor.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rspactor'
|
2
|
+
|
3
|
+
module RSpactor
|
4
|
+
class Celerity
|
5
|
+
|
6
|
+
def self.start(dir)
|
7
|
+
pid_path = "#{dir}/tmp/pids/mongrel_celerity.pid"
|
8
|
+
if File.exist?(pid_path)
|
9
|
+
system("kill $(head #{pid_path}) >/dev/null 2>&1")
|
10
|
+
system("rm #{pid_path} >/dev/null 2>&1")
|
11
|
+
end
|
12
|
+
# kill other mongrels
|
13
|
+
system("kill $(ps aux | grep 'mongrel_rails' | grep -v grep | awk '//{print $2;}') >/dev/null 2>&1")
|
14
|
+
system("rake celerity_server:start >/dev/null 2>&1 &")
|
15
|
+
Interactor.ticker_msg "** Starting celerity server"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.restart
|
19
|
+
system("rake celerity_server:stop >/dev/null 2>&1 && rake celerity_server:start >/dev/null 2>&1 &")
|
20
|
+
Interactor.ticker_msg "** Restarting celerity server"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.kill_jruby
|
24
|
+
system("kill $(ps aux | grep jruby | grep -v grep | awk '//{print $2;}') >/dev/null 2>&1")
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/rspactor/inspector.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
+
require 'rspactor'
|
2
|
+
|
1
3
|
module RSpactor
|
2
4
|
# Maps the changed filenames to list of specs to run in the next go.
|
3
5
|
# Assumes Rails-like directory structure
|
4
6
|
class Inspector
|
5
7
|
EXTENSIONS = %w(rb erb builder haml rhtml rxml yml conf opts feature)
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
attr_reader :runner, :root
|
10
|
+
|
11
|
+
def initialize(runner)
|
12
|
+
@runner = runner
|
13
|
+
@root = runner.dir
|
9
14
|
end
|
10
15
|
|
11
16
|
def determine_files(file)
|
@@ -16,17 +21,17 @@ module RSpactor
|
|
16
21
|
end
|
17
22
|
files = candidates.select { |candidate| File.exists? candidate }
|
18
23
|
|
19
|
-
if files.empty? && !cucumberable
|
24
|
+
if files.empty? && !candidates.empty? && !cucumberable
|
20
25
|
$stderr.puts "doesn't exist: #{candidates.inspect}"
|
21
26
|
end
|
22
27
|
|
23
28
|
files << 'cucumber' if cucumberable
|
24
|
-
files
|
29
|
+
files
|
25
30
|
end
|
26
31
|
|
27
32
|
# mappings for Rails are inspired by autotest mappings in rspec-rails
|
28
33
|
def translate(file)
|
29
|
-
file = file.sub(%r:^#{Regexp.escape(
|
34
|
+
file = file.sub(%r:^#{Regexp.escape(root)}/:, '')
|
30
35
|
candidates = []
|
31
36
|
|
32
37
|
if spec_file?(file)
|
@@ -42,7 +47,7 @@ module RSpactor
|
|
42
47
|
candidates << 'controllers'
|
43
48
|
elsif file == 'app/helpers/application_helper.rb'
|
44
49
|
candidates << 'helpers' << 'views'
|
45
|
-
|
50
|
+
elsif !file.include?("app/views/") || runner.options[:view]
|
46
51
|
candidates << spec_file.sub('app/', '')
|
47
52
|
|
48
53
|
if file =~ %r:^app/(views/.+\.[a-z]+)\.[a-z]+$:
|
@@ -63,6 +68,12 @@ module RSpactor
|
|
63
68
|
candidates << 'controllers' << 'helpers' << 'views' << 'routing'
|
64
69
|
when 'config/database.yml', 'db/schema.rb', 'spec/factories.rb'
|
65
70
|
candidates << 'models'
|
71
|
+
when 'config/boot.rb', 'config/environment.rb', %r:^config/environments/:, %r:^config/initializers/:, %r:^vendor/:
|
72
|
+
Spork.reload if runner.options[:spork]
|
73
|
+
Celerity.restart if runner.options[:celerity]
|
74
|
+
candidates << 'spec'
|
75
|
+
when %r:^config/:
|
76
|
+
# nothing
|
66
77
|
when %r:^(spec/(spec_helper|shared/.*)|config/(boot|environment(s/test)?))\.rb$:, 'spec/spec.opts'
|
67
78
|
candidates << 'spec'
|
68
79
|
else
|
@@ -74,9 +85,9 @@ module RSpactor
|
|
74
85
|
if candidate == 'cucumber'
|
75
86
|
candidate
|
76
87
|
elsif candidate.index('spec') == 0
|
77
|
-
File.join(
|
88
|
+
File.join(root, candidate)
|
78
89
|
else
|
79
|
-
File.join(
|
90
|
+
File.join(root, 'spec', candidate)
|
80
91
|
end
|
81
92
|
end
|
82
93
|
end
|
data/lib/rspactor/interactor.rb
CHANGED
@@ -10,10 +10,20 @@ module RSpactor
|
|
10
10
|
ticker
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
13
|
+
def self.ticker_msg(msg, seconds_to_wait = 2)
|
14
|
+
$stdout.print msg
|
15
|
+
seconds_to_wait.times do
|
16
|
+
$stdout.print('.')
|
17
|
+
$stdout.flush
|
18
|
+
sleep 1
|
19
|
+
end
|
20
|
+
$stdout.puts "\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
def wait_for_enter_key(msg, seconds_to_wait, clear = runner.options[:clear])
|
14
24
|
begin
|
15
25
|
Timeout::timeout(seconds_to_wait) do
|
16
|
-
system("clear;") if
|
26
|
+
system("clear;") if clear
|
17
27
|
ticker(:start => true, :msg => msg)
|
18
28
|
$stdin.gets
|
19
29
|
return true
|
@@ -37,7 +47,7 @@ module RSpactor
|
|
37
47
|
when "ca\n" # Cucumber All: ~pending tagged feature
|
38
48
|
runner.run_cucumber_command('~pending')
|
39
49
|
else
|
40
|
-
if wait_for_enter_key("** Running all specs
|
50
|
+
if wait_for_enter_key("** Running all specs... Hit <enter> again to exit RSpactor", 1)
|
41
51
|
@main_thread.exit
|
42
52
|
exit
|
43
53
|
end
|
data/lib/rspactor/runner.rb
CHANGED
@@ -18,19 +18,24 @@ module RSpactor
|
|
18
18
|
def start
|
19
19
|
load_dotfile
|
20
20
|
puts "** RSpactor is now watching at '#{dir}'"
|
21
|
+
Spork.start if options[:spork]
|
22
|
+
Celerity.start(dir) if options[:celerity]
|
21
23
|
start_interactor
|
22
24
|
start_listener
|
23
25
|
end
|
24
26
|
|
25
27
|
def start_interactor
|
26
28
|
@interactor = Interactor.new(self)
|
27
|
-
aborted = @interactor.wait_for_enter_key("** Hit <enter> to skip initial spec run", 2)
|
29
|
+
aborted = @interactor.wait_for_enter_key("** Hit <enter> to skip initial spec & cucumber run", 2, false)
|
28
30
|
@interactor.start_termination_handler
|
29
|
-
|
31
|
+
unless aborted
|
32
|
+
run_all_specs
|
33
|
+
run_cucumber_command('~pending', false)
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def start_listener
|
33
|
-
@inspector = Inspector.new(
|
38
|
+
@inspector = Inspector.new(self)
|
34
39
|
|
35
40
|
Listener.new(Inspector::EXTENSIONS) do |files|
|
36
41
|
changed_files(files) unless git_head_changed?
|
@@ -62,13 +67,13 @@ module RSpactor
|
|
62
67
|
end
|
63
68
|
end
|
64
69
|
|
65
|
-
def run_cucumber_command(tags = 'current')
|
66
|
-
system("clear;") if
|
67
|
-
puts "#{tags} tagged features"
|
70
|
+
def run_cucumber_command(tags = 'current', clear = @options[:clear])
|
71
|
+
system("clear;") if clear
|
72
|
+
puts "** Running all #{tags} tagged features..."
|
68
73
|
cmd = [ruby_opts, cucumber_runner, cucumber_opts(tags)].flatten.join(' ')
|
69
74
|
@last_run_failed = run_command(cmd)
|
70
|
-
# Workaround for killing jruby process when used with celerity
|
71
|
-
|
75
|
+
# Workaround for killing jruby process when used with celerity and spork
|
76
|
+
Celerity.kill_jruby if options[:celerity] && options[:spork]
|
72
77
|
end
|
73
78
|
|
74
79
|
def last_run_failed?
|
@@ -96,6 +101,7 @@ module RSpactor
|
|
96
101
|
# specs files
|
97
102
|
unless files.empty?
|
98
103
|
system("clear;") if @options[:clear]
|
104
|
+
files.uniq!
|
99
105
|
puts files.map { |f| f.to_s.gsub(/#{dir}/, '') }.join("\n")
|
100
106
|
|
101
107
|
previous_run_failed = last_run_failed?
|
@@ -128,7 +134,7 @@ module RSpactor
|
|
128
134
|
if File.exist?('features/support/cucumber.opts')
|
129
135
|
opts = File.read('features/support/cucumber.opts').gsub("\n", ' ')
|
130
136
|
else
|
131
|
-
opts = "--format progress --drb "
|
137
|
+
opts = "--color --format progress --drb "
|
132
138
|
end
|
133
139
|
|
134
140
|
opts << " --tags #{tags}"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rspactor'
|
2
|
+
|
3
|
+
module RSpactor
|
4
|
+
class Spork
|
5
|
+
|
6
|
+
def self.start
|
7
|
+
kill_and_launch
|
8
|
+
Interactor.ticker_msg "** Launching Spork for rspec & cucumber"
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.reload
|
12
|
+
kill_and_launch
|
13
|
+
Interactor.ticker_msg "** Reloading Spork for rspec & cucumber"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def self.kill_and_launch
|
19
|
+
system("kill $(ps aux | awk '/spork/&&!/awk/{print $2;}') >/dev/null 2>&1")
|
20
|
+
system("spork >/dev/null 2>&1 < /dev/null &")
|
21
|
+
system("spork cu >/dev/null 2>&1 < /dev/null &")
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/spec/inspector_spec.rb
CHANGED
@@ -2,7 +2,8 @@ require 'rspactor/inspector'
|
|
2
2
|
|
3
3
|
describe RSpactor::Inspector do
|
4
4
|
before(:all) do
|
5
|
-
|
5
|
+
options = { :view => true }
|
6
|
+
@inspector = described_class.new(mock('Runner', :dir => '/project', :options => options))
|
6
7
|
end
|
7
8
|
|
8
9
|
def translate(file)
|
data/spec/runner_spec.rb
CHANGED
@@ -75,16 +75,16 @@ describe RSpactor::Runner do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
it "should start Interactor" do
|
78
|
-
@interactor.should_receive(:wait_for_enter_key).with(instance_of(String), 2)
|
78
|
+
@interactor.should_receive(:wait_for_enter_key).with(instance_of(String), 2, false)
|
79
79
|
setup
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
it "should run all specs if Interactor isn't interrupted" do
|
83
83
|
@interactor.should_receive(:wait_for_enter_key).and_return(nil)
|
84
84
|
@runner.should_receive(:run_spec_command).with('/my/path/spec')
|
85
85
|
setup
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
it "should skip running all specs if Interactor is interrupted" do
|
89
89
|
@interactor.should_receive(:wait_for_enter_key).and_return(true)
|
90
90
|
@runner.should_not_receive(:run_spec_command)
|
@@ -95,7 +95,7 @@ describe RSpactor::Runner do
|
|
95
95
|
it "should initialize Inspector" do
|
96
96
|
@runner.stub!(:load_dotfile)
|
97
97
|
@runner.stub!(:start_interactor)
|
98
|
-
RSpactor::Inspector.should_receive(:new)
|
98
|
+
RSpactor::Inspector.should_receive(:new)
|
99
99
|
RSpactor::Listener.stub!(:new).and_return(mock('Listener').as_null_object)
|
100
100
|
setup
|
101
101
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: guillaumegentil-rspactor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Mislav Marohni\xC4\x87"
|
@@ -12,15 +12,14 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2009-08-
|
16
|
-
default_executable:
|
15
|
+
date: 2009-08-12 00:00:00 -07:00
|
16
|
+
default_executable: rspactor
|
17
17
|
dependencies: []
|
18
18
|
|
19
|
-
description:
|
20
|
-
email:
|
19
|
+
description: read summary!
|
20
|
+
email: guillaumegentil@gmail.com
|
21
21
|
executables:
|
22
22
|
- rspactor
|
23
|
-
- rspactor-system
|
24
23
|
extensions: []
|
25
24
|
|
26
25
|
extra_rdoc_files: []
|
@@ -28,14 +27,15 @@ extra_rdoc_files: []
|
|
28
27
|
files:
|
29
28
|
- Rakefile
|
30
29
|
- bin/rspactor
|
31
|
-
- bin/rspactor-system
|
32
30
|
- lib/cucumber_growler.rb
|
33
31
|
- lib/rspactor
|
32
|
+
- lib/rspactor/celerity.rb
|
34
33
|
- lib/rspactor/growl.rb
|
35
34
|
- lib/rspactor/inspector.rb
|
36
35
|
- lib/rspactor/interactor.rb
|
37
36
|
- lib/rspactor/listener.rb
|
38
37
|
- lib/rspactor/runner.rb
|
38
|
+
- lib/rspactor/spork.rb
|
39
39
|
- lib/rspactor.rb
|
40
40
|
- lib/rspec_growler.rb
|
41
41
|
- images/failed.png
|
@@ -46,7 +46,7 @@ files:
|
|
46
46
|
- spec/runner_spec.rb
|
47
47
|
- LICENSE
|
48
48
|
has_rdoc: false
|
49
|
-
homepage: http://github.com/
|
49
|
+
homepage: http://github.com/guillaumegentil/rspactor
|
50
50
|
licenses:
|
51
51
|
post_install_message:
|
52
52
|
rdoc_options: []
|
@@ -71,6 +71,6 @@ rubyforge_project:
|
|
71
71
|
rubygems_version: 1.3.5
|
72
72
|
signing_key:
|
73
73
|
specification_version: 3
|
74
|
-
summary: RSpactor is a command line tool to automatically run your changed specs (much like autotest).
|
74
|
+
summary: RSpactor is a command line tool to automatically run your changed specs & cucumber features (much like autotest).
|
75
75
|
test_files: []
|
76
76
|
|
data/bin/rspactor-system
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'rspactor'
|
3
|
-
Growl = RSpactor::Growl
|
4
|
-
|
5
|
-
root = ENV['HOME']
|
6
|
-
$mappings = []
|
7
|
-
$libs = []
|
8
|
-
|
9
|
-
def map(regex, &block)
|
10
|
-
$mappings << [regex, block]
|
11
|
-
end
|
12
|
-
|
13
|
-
def libs
|
14
|
-
$libs
|
15
|
-
end
|
16
|
-
|
17
|
-
def title
|
18
|
-
$title
|
19
|
-
end
|
20
|
-
|
21
|
-
listener = RSpactor::Listener.new do |changed_files|
|
22
|
-
changed_files.reject! do |file|
|
23
|
-
file.index(root + "/Library/") == 0
|
24
|
-
end
|
25
|
-
|
26
|
-
if changed_files.size == 1
|
27
|
-
changed_file = changed_files.first
|
28
|
-
dir = changed_file
|
29
|
-
hook = nil
|
30
|
-
|
31
|
-
until hook or (dir = File.dirname(dir)) == root
|
32
|
-
candidate = dir + "/.rspactor"
|
33
|
-
hook = candidate if File.exists?(candidate)
|
34
|
-
end
|
35
|
-
|
36
|
-
if hook
|
37
|
-
targets = []
|
38
|
-
$title = "Test results"
|
39
|
-
$mappings.clear
|
40
|
-
$libs.replace ['lib']
|
41
|
-
load hook
|
42
|
-
|
43
|
-
unless $mappings.empty?
|
44
|
-
relative_path = changed_file.sub(dir + '/', '')
|
45
|
-
|
46
|
-
for regex, block in $mappings
|
47
|
-
if match = relative_path.match(regex)
|
48
|
-
targets.concat Array(block.call(relative_path, match))
|
49
|
-
break
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
existing_targets = targets.select { |file| File.exist?(File.join(dir, file)) }
|
54
|
-
else
|
55
|
-
inspector = RSpactor::Inspector.new(dir)
|
56
|
-
existing_targets = inspector.determine_files(changed_file).map do |file|
|
57
|
-
file.sub(dir + '/', '')
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
if not existing_targets.empty?
|
62
|
-
case existing_targets.first
|
63
|
-
when %r{^test/}
|
64
|
-
$libs << 'test'
|
65
|
-
when %r{^spec/}
|
66
|
-
$libs << 'spec'
|
67
|
-
end
|
68
|
-
|
69
|
-
Dir.chdir(dir) do
|
70
|
-
unless 'spec' == $libs.last
|
71
|
-
command = "ruby -I#{$libs.join(':')} -e 'ARGV.each{|f| load f}' "
|
72
|
-
else
|
73
|
-
command = "RUBYOPT='-I#{$libs.join(':')}' spec --color "
|
74
|
-
end
|
75
|
-
command << existing_targets.join(' ')
|
76
|
-
# puts command
|
77
|
-
puts changed_file
|
78
|
-
system command
|
79
|
-
end
|
80
|
-
|
81
|
-
if $?.success?
|
82
|
-
Growl::notify $title, "You rock!", Growl::image_path('success')
|
83
|
-
else
|
84
|
-
Growl::notify $title, "YOU LOSE", Growl::image_path('failed')
|
85
|
-
end
|
86
|
-
elsif $mappings.empty?
|
87
|
-
$stderr.puts "-- don't know how to run #{changed_file}"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
listener.run(root)
|