Add task dependencies to Rake::TestTask - ruby

How can I declare task dependencies to a TestTask ?
In this example, 'clean_database' task should be run before integration task
Rake::TestTask.new(:integration) do |t|
t.libs << "test"
t.test_files = FileList['test/**/integration/**/test*.rb']
t.verbose = true
end
task :clean_database => [:init] do
#...
end

Rake enables redefining existing tasks, so this should be possible (add it to your existing code):
task :integration => :clean_database

You can pass in the dependency to the TestTask initializer:
Rake::TestTask.new(:integration => :clean_database) do |t|
t.libs << "test"
t.test_files = FileList['test/**/integration/**/test*.rb']
t.verbose = true
end

Related

Continue multi-host tests even on failure

I've built some serverspec code to run a group of tests on multiple hosts. The trouble is that the testing stops at the current host when any test fails. I want it to continue to all hosts even if a test fails.
The Rakefile:
namespace :spec do
task :all => hosts.map {|h| 'spec:' + h.split('.')[0] }
hosts.each do |host|
begin
desc "Run serverspec to #{host}"
RSpec::Core::RakeTask.new(host) do |t|
ENV['TARGET_HOST'] = host
t.pattern = "spec/cfengine3/*_spec.rb"
end
rescue
end
end
end
Complete code:
https://gist.github.com/neilhwatson/1d41c696102c01bbb87a
This behaviour is controlled by RSpec::Core::RakeTask#fail_on_error so in order to have it continue on all hosts you need to add t.fail_on_error = false. I also think that you don't need to rescue.
namespace :spec do
task :all => hosts.map {|h| 'spec:' + h.split('.')[0] }
hosts.each do |host|
desc "Run serverspec to #{host}"
RSpec::Core::RakeTask.new(host) do |t|
ENV['TARGET_HOST'] = host
t.pattern = "spec/cfengine3/*_spec.rb"
t.fail_on_error = false
end
end
end

How do you use multiple tasks using Rake::TestTask?

I am running Minitest with Rake and would like to have two separate Rake tasks.
I have added the following:
require 'rake/testtask'
task :default => [:test]
task :quick => [:unit]
Rake::TestTask.new do |t|
puts 'within test task'
t.libs.push 'specs'
t.pattern = 'specs/*_spec.rb'
ENV['STACK'] = 'stack1'
puts "test stack #{ENV['STACK']}"
end
Rake::TestTask.new('unit') do |t|
puts 'within unit task'
t.libs.push 'specs'
t.pattern = 'specs/*_unit.rb'
ENV['STACK'] = 'stack2'
puts "test stack #{ENV['STACK']}"
end
When I run bundle exec rake quick then I get this output:
within test task
test stack stack1
within unit task
test stack stack2
I did not expect both the tasks to run. How do I create and run two separate rake tasks? As it is now, the second one always overwrites the environment variable.
Thanks
You solve this issue by using Rake::Task["task_name"].clear like this:
task :test_task do
Rake::TestTask.new do |t|
puts 'within test task'
t.libs.push 'specs'
t.pattern = 'specs/*_spec.rb'
ENV['STACK'] = 'stack1'
puts "test stack #{ENV['STACK']}"
end
end
task :unit_task do
Rake::TestTask.new('unit') do |t|
puts 'within unit task'
t.libs.push 'specs'
t.pattern = 'specs/*_unit.rb'
ENV['STACK'] = 'stack2'
puts "test stack #{ENV['STACK']}"
end
end
task :test do
Rake::Task["unit_task"].clear
Rake::Task["test_task"].invoke
end
task :unit do
Rake::Task["test_task"].clear
Rake::Task["unit_task"].invoke
end

A rake task by .rake file

I have the following Rakefile in a Ruby 1.9.3 project:
require 'rake/testtask'
require 'json'
Rake::TestTask.new do |t|
t.pattern = "spec/**/*_spec.rb"
t.verbose = true
end
task :default => :test
namespace :omglol do
namespace :file_a do
task :foo do
# do some stuff
end
end
namespace :file_b do
task :bar do
# do some stuff
end
end
end
As you can see, the first part of this file allow to run tests, just using rake command. And the second part contains some tasks.
Actually, I have a lot of tasks inside omglol:file_a and omglol:file_b namespaces. That's why I would like to move each of them inside a file, for instance tasks/omglol/file_a.rake and tasks/omglol/file_b.rake.
Is there a best way to do so? Thanks.
Yes. Simply move the logic into the appropriate files and then require them.
Example Rakefile:
require 'rake/testtask'
require 'json'
require 'lib/tasks/omglol/file_a.rake' # <= contains your subtasks
Rake::TestTask.new do |t|
t.pattern = "spec/**/*_spec.rb"
t.verbose = true
end
task :default => :test
Then in lib/tasks/omglol/file_a.rake simply define your tasks as normal:
namespace :omglol do
namespace :file_a do
task :foo do
# do some stuff
end
end
end
The pattern would be the same for file_b.rake.

How do I run multiple Rake tasks programmatically at once?

At the command line I can run multiple tasks like this
rake environment task1 task2 task3
How can I do this programmatically? I know that I can run one task like this
Rake::Task['task1'].invoke
You can call two tasks:
require 'rake'
task :task1 do |t|
p t
end
task :task2 do |t|
p t
end
Rake::Task["task1"].invoke
Rake::Task["task2"].invoke
I would prefer a new tast with prerequisites:
require 'rake'
task :task1 do |t|
p t
end
task :task2 do |t|
p t
end
desc "Common task"
task :all => [ :task1, :task2 ]
Rake::Task["all"].invoke
If I misunderstood your question and you want to execute the same task twice: You can reenable tasks:
require 'rake'
task :task1 do |t|
p t
end
Rake::Task["task1"].invoke
Rake::Task["task1"].reenable
Rake::Task["task1"].invoke
Make a rake task for it :P
# in /lib/tasks/some_file.rake
namespace :myjobs do
desc "Doing work, son"
task :do_work => :environment do
Rake::Task['resque:work'].invoke
start_some_other_task
end
def start_some_other_task
# custom code here
end
end
Then just call it:
rake myjobs:do_work

Flexible Rake task

I would like to use the following Rake task for multiple directories. And each directory would need slightly different constants defined. How can I handle this and stay DRY?
namespace :assets do
EXT = 'js'
OBJDIR = 'public/javascripts'
LIBFILE = "#{OBJDIR}/packaged.#{EXT}"
SRC = FileList["#{OBJDIR}/*.#{EXT}"].select {|file| !file.match(/\.min\.#{EXT}|packaged\.#{EXT}/)}
OBJ = SRC.collect {|fn| File.join(OBJDIR, File.basename(fn).ext("min.#{EXT}"))}
MINE = %w(4sq app fb mbp).collect {|x| x + ".#{EXT}"}
desc "Build #{LIBFILE}"
task :build => LIBFILE
desc "Remove minified files"
task :clean do
rm_f OBJ
end
desc "Remove #{LIBFILE}"
task :clobber do
rm_f LIBFILE
end
file LIBFILE => OBJ do
sh "cat #{OBJ} >> #{LIBFILE}"
end
rule ".min.#{EXT}" => lambda{ |objfile| find_source(objfile) } do |t|
if EXT == 'js'
if MINE.include?(File.basename(t.source))
sh "closure --js #{t.source} --js_output_file #{t.name}"
else
sh "closure --warning_level QUIET --third_party --js #{t.source} --js_output_file #{t.name}"
end
elsif EXT == 'css'
sh "yuicompressor #{t.source} -o #{t.name}"
end
end
def find_source(objfile)
base = File.basename(objfile, ".min.#{EXT}")
SRC.find {|s| File.basename(s, ".#{EXT}") == base}
end
end
First you must replace the constants by variables.
The next problem is to set the variables.
Task can get variables.
Example:
namespace :assets do |x1,x2|
task :doit, :ext, :objdir do |tsk, args|
puts tsk
p args
end
end
You can call it with:
rake assets:doit[js,objdir]
Result:
assets:doit called with {:ext=>"js", :objdir=>"objdir"}
If you want to avoid to set the variables for each of your task, you may add a 'set' task:
namespace :assets2 do |x1,x2|
task :set, :ext, :objdir do |tsk, args|
#args = args
puts "#{tsk} set: #{#args.inspect}"
end
task :doit do |tsk|
puts "#{tsk} called with #{#args.inspect}"
end
end
Call:
rake assets2:set[js,objdir] assets2:doit
Result:
assets2:set set: {:ext=>"js", :objdir=>"objdir"}
assets2:doit called with {:ext=>"js", :objdir=>"objdir"}
Instead of setting all parameters, you may define a configuration file.
There is one disadvantage. The following task would not work:
rake assets:doit[js,objdir] assets:doit[c,objdir2]
assets:doit would be called once. the second call is ignored, the task is already executed. there is no check for different parameters (One solution for this: perhaps you could reset the task)
Edit: I found and tested a 'reset'-method: You just need to add tsk.reenable
namespace :assets do |x1,x2|
task :doit, :ext, :objdir do |tsk, args|
puts "#{tsk} called with #{args.inspect}"
tsk.reenable
end
end
Another problem: If your parameters contains spaces. you may get trouble.
==============
Code for generic generation of rule: (see comments)
namespace :assets3 do |x1,x2|
task :set, :ext, :objdir do |tsk, args|
#args = args
#src = FileList["*.rb"]
puts "#{tsk} set: #{#args.inspect}"
#Define rule, when extension is set.
rule ".min.#{#args[:ext]}" => lambda{ |objfile| find_source(objfile) } do |t|
puts "#{t} called with #{#args.inspect}"
end
end
task :doit do |tsk|
puts "#{tsk} called with #{#args.inspect}"
end
def find_source(objfile)
base = File.basename(objfile, ".min.#{#args[:ext]}")
#If nothing is found, rake will abort with 'can't convert nil into String (TypeError)'
#If I return '' in this case, I get 'Don't know how to build task 'test.min.js' (RuntimeError)'
#src.find {|s| File.basename(s, ".#{#args[:ext]}") == base} || ''
end
end
With your help I finally figured it out. Here's what's working for me so far:
namespace :assets do
task :set, [:ext, :objdir] do |t, args|
#ext = args.ext
#objdir = args.objdir
#bundle = "#{#objdir}/bundle.#{#ext}"
#src = FileList["#{#objdir}/*.#{#ext}"].select {|file| !file.match(/\.min\.#{#ext}|#{Regexp.escape(#bundle)}/)}
#min = #src.collect {|fn| File.join(#objdir, File.basename(fn).ext("min.#{#ext}"))}
Rake::Task.define_task 'assets:build' => #bundle
Rake::FileTask.define_task #bundle => #min do
sh "cat #{#min} > #{#bundle}"
end
Rake::Task.create_rule ".min.#{#ext}" => lambda{ |objfile| find_source(objfile) } do |t|
if #ext == 'js'
if #mine.include?(File.basename(t.source))
sh "closure --js #{t.source} --js_output_file #{t.name}"
else
sh "closure --warning_level QUIET --third_party --js #{t.source} --js_output_file #{t.name}"
end
elsif #ext == 'css'
sh "yuicompressor #{t.source} -o #{t.name}"
end
end
end
desc "Remove minified files"
task :clean do
rm_f #min
end
desc "Remove bundle"
task :clobber do
rm_f #bundle
end
def find_source(objfile)
base = File.basename(objfile, ".min.#{#ext}")
#src.find {|s| File.basename(s, ".#{#ext}") == base}
end
end

Resources