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

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

Related

Limit scope of rule defined inside namespace

I have the following Rakefile (this is a simplified example):
namespace :green do
rule(/^build:/) do |t|
puts "[green] #{t}"
end
task :start do
puts '[green] start'
end
task run: ['build:app', :start]
end
namespace :blue do
rule(/^build:/) do |t|
puts "[blue] #{t}"
end
task :start do
puts '[blue] start'
end
task run: ['build:app', :start]
end
I would like each "build" rule to apply only within the namespace where it's defined. In other words, this is what I want to happen:
$ rake blue:run
[blue] build:app
[blue] start
But what actually happens is this (with Rake 12.3.1):
$ rake blue:run
[green] build:app
[blue] start
Is there a way to limit the scope of the "build" rules so that the rule defined in the "green" namespace isn't accessible from the "blue" namespace?
It appears that Rake doesn't support this natively. Tasks are scoped to the namespace they are defined in (by adding the scope path as a prefix), but rules get no such prefix.
I was able to get this to work by monkey-patching Rake, which is not ideal:
# Monkey-patch rake
module Rake
module TaskManager
# Copied from rake 12.3.1 and enhanced for scoped rules
def lookup_in_scope(name, scope)
loop do
tn = scope.path_with_task_name(name)
task = #tasks[tn]
return task if task
break if scope.empty?
# BEGIN ADDED LINES
task = enhance_with_matching_rule(tn)
return task if task
# END ADDED LINES
scope = scope.tail
end
nil
end
end
module DSL
# Create a rule inside a namespace scope
def scoped_rule(name, &block)
pattern = "^#{Rake.application.current_scope.path}:#{name}:"
Rake.application.create_rule(Regexp.new(pattern), &block)
end
end
end
namespace :green do
scoped_rule :build do |t|
puts t
end
task :start do |t|
puts t
end
task run: ['build:app', :start]
end
namespace :blue do
scoped_rule :build do |t|
puts t
end
task :start do |t|
puts t
end
task run: ['build:app', :start]
end
Output:
$ rake green:run
green:build:app
green:start
$ rake blue:run
blue:build:app
blue:start
I know that it's not the best solution, but I think it maybe can help you.
rule(/^build*/) do |t|
Rake::Task["green:build"].invoke if ARGV[0].start_with? "green"
Rake::Task["blue:build"].invoke if ARGV[0].start_with? "blue"
end
namespace :green do
task :build do
puts '[green] build'
end
task :start do
puts '[green] start'
end
task run: ['build.app', :start]
end
namespace :blue do
task :build do
puts '[blue] build'
end
task :start do
puts '[blue] start'
end
task run: ['build.app', :start]
end
Testing it we have:
rake green:run # [green] build
# [green] start
rake blue:run # [blue] build
# [blue] start

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 to know which task is being executed with rake

I'd like to know from within a rake ask what is the name of the task that is being executed? How to do this? For example, in the code bellow, when I run rake my_incredible_task, it should print "my_incredible_task":
task :boot do
task_name = <what comes here?>
puts task_name
end
task :my_incredible_task => [:boot] do
#do some stuff
end
I'm not sure there is a way out of the box, however you can do something like this:
require 'rake'
module Rake
class Application
attr_accessor :current_task_name
end
class Task
alias :old_execute :execute
def execute(args=nil)
Rake.application.current_task_name = #name
old_execute(args)
end
end
end
namespace :so do
task :my_task do
puts Rake.application.current_task_name
end
end
Not sure how this will work out with tasks that run in parallel...
You can use a parameter in the block :
task :my_incredible_task do |t|
puts t.name
end
EDIT
You could use methods instead :
task :boot do |t|
boot(t.name)
end
task :my_incredible_task do |t|
boot(t.name)
#do some stuff
end
def boot task_name
# do stuff
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

Resources