autospec.rb
require "open3"
require "date"
@mappings = { /^app\/views\/(.*)\/(.*)\.html\.haml$/ =>
lambda { |m| ["spec/views/big_fucking_view_spec.rb", "spec/views/#{m[1]}/#{m[2]}.html.haml_spec.rb"] },
/^app\/(.*)\/(.*)\.rb$/ =>
lambda { |m| "spec/#{m[1]}/#{m[2]}_spec.rb" },
/^spec\/(.*)_spec\.rb$/ =>
lambda { |m| "spec/#{m[1]}_spec.rb" },
/^(lib\/launch_accounting_entries|spec\/models\/shared_examples_for_accounting_entries)\.rb$/ =>
lambda { |m| ["spec/models/flight_spec.rb", "spec/models/tow_flight_spec.rb", "spec/models/wire_launch_spec.rb"] },
/^app\/models\/((.*)_cost_category(.*)|plane|wire_launcher|flight|wire_launch|tow_flight|(.*)_cost_rule)\.rb$/ =>
lambda { |m| ["spec/models/accounting_entry_invalidation_integration_spec.rb"] } }
def build_mtimes_hash(globs, first)
files = @files || {}
globs.each { |g|
Dir[g].each { |file| files[file] = first ? File.mtime(file) : (files[file] || (Time.now - 86400)) }
}
files
end
def uncached_specs_for(file)
@mappings.map { |k, v|
m = k.match(file)
if m
v.call(m)
else
[]
end
}.flatten.select { |f| File.exists?(f) }
end
def specs_for(file)
if ((DateTime.now - @file_time) * 1440) > 1 #search for new files every minute
search_files
@sf[file] = uncached_specs_for(file)
end
@sf[file] ||= uncached_specs_for(file)
end
def search_files(first = false)
@specs = @spec_dirs.map { |d| Dir[d] }.flatten
@files = build_mtimes_hash(["app/**/*.rb", "app/views/**/*.html.haml", "lib/**/*.rb", @spec_dirs].flatten, first)
@file_time = DateTime.now
end
def specs
if ((DateTime.now - @file_time) * 1440) > 1 #search for new files every minute
search_files
end
@specs
end
def files
if ((DateTime.now - @file_time) * 1440) > 1 #search for new files every minute
search_files
end
@files
end
@spec_dirs = ["spec/**/*_spec.rb"]
search_files(true)
@sf = {}
@run_all = false
@last_time_all = DateTime.now
@run_all_when_green = false
trap('INT') do
exit
end
loop do
changed_files = files.find_all { |file, last_changed|
begin
m = File.mtime(file)
r = m > last_changed
@files[file] = m
r
rescue Errno::ENOENT => e # file may have been moved, deleted etc.
warn e
@files.delete file
end
}.map { |e| e[0] }
if !changed_files.empty? || @run_all
notified = false
err = ""
if @run_all && changed_files.empty? #do not run all, if there are changed files
c = "bundle exec rspec --tty spec/"
@run_all = false
@last_time_all = DateTime.now
else
c = "bundle exec rspec --tty #{changed_files.map { |f| specs_for(f) }.flatten.uniq.join(' ')}"
end
15.times { puts }
puts "\e[34m##{'#'*45}\e[0m"
Open3.popen3(c) do |_, stdout, stderr|
n = 0
puts "running #{c}"
l = ""
while(ch = stdout.getc) do
putc ch
if ch == "\n"
if l =~ /([0-9]*) examples, 0 failures, ([0-9]*) pending/
`notify-send --hint=int:transient:1 '#{$1} example#{$1 == "1" ? "" : "s"}, #{$2} pending' -i ~/code/foxtrot_mike/.notify-img/pending.png &> /dev/null`
notified = true
if @run_all_when_green
#@run_all = true
@run_all_when_green = false
end
elsif l =~ /([0-9]*) examples*, 0 failures/
`notify-send --hint=int:transient:1 '#{$1} example#{$1 == "1" ? "" : "s"} passed' -i ~/code/foxtrot_mike/.notify-img/passed.png &> /dev/null`
notified = true
if @run_all_when_green && ((DateTime.now - @last_time_all) * 1440) > 5 #only run all after green every 5 minutes
#@run_all = true
@run_all_when_green = false
end
elsif l =~ /([0-9]*) examples*, ([0-9]*) failures*/
`notify-send --hint=int:transient:1 '#{$1} example#{$1 == "1" ? "" : "s"}, #{$2} failed' -i ~/code/foxtrot_mike/.notify-img/failed.png &> /dev/null`
notified = true
@run_all_when_green = true
end
l = ""
else
l += ch
end
end
err = stderr.readlines
end
unless notified
#`notify-send 'Specs could not be run' -i ~/traffic-light-red.jpg &> /dev/null`
puts err
end
else
sleep 5
end
end