Adding Growl notifications after Rake tasks are finished - ruby

Is there a way to add Growl notifications to the end of all Rake tasks?
I initially thought of creating a task that Growls, and adding it as a dependency to tasks I want alerts from, but realized the dependencies get run before the task begins. Is there a way to add tasks to be run after certain Rake tasks are finished?
It'd be really useful so I don't have to sit there waiting for long tasks.
** update 8/17/2010 **
Here is the solution for doing it with growlnotify...put this in your Rakefile:
def growl(message)
growlnotify = `which growlnotify`.chomp
system %(#{growlnotify} -sm #{message})
end
task_names = Rake.application.top_level_tasks
task_names.each do |name|
Rake.application[name].enhance { growl "'Task #{name} completed (#{Time.now})'" }
end
-- Credit to Alkaline - see his solution for using ruby-growl below --

Here's how you can implicitly invoke a growl action for the calling (top level) tasks
require 'rake'
require 'ruby-growl'
task :task1 do puts "Doing task 1"; sleep 1; end
task :task2 do puts "Doing task 2"; sleep 1; end
task :default => [:task1, :task2]
# Add a growl action to all top level tasks
task_names = Rake.application.top_level_tasks
task_names.each do |name|
Rake.application[name].enhance {growl(name)}
end
def growl(name)
g = Growl.new "localhost", "ruby-growl", ["ruby-growl Notification"]
g.notify "ruby-growl Notification", "My Project", "Task #{name} completed"
end

The gem rakegrowl does this very simply. All you have to do is install the rakegrowl gem and alias rake to rake -rubygems -r rakegrowl in your .bashrc.

Related

How to test rake task callbacks

I create test code with rspec. I want to test callback is executed or not.
task main: [:callback] means run callback before main, doesn't it?
But my test failed. I looks like callback is not executed. Why?
require 'rails_helper'
require 'rake'
RSpec.describe 'Rake::Task' do
before(:all) do
#rake = Rake::Application.new
Rake.application = #rake
Rake.application.rake_require('rspec_before', ["#{Rails.root}/lib/tasks"])
end
subject { #rake['rspec_before:main'].execute }
it "expects run callback before main task" do
expect{ subject }.to output(/Hello, world/).to_stdout
end
end
My Rake task is below.
namespace :rspec_before do
task :callback do
#greeting = "Hello, world"
end
# case 1
# In this case, `callback` is NOT executed in rspec
# In console, `callback` is executed !!!!
desc "main task"
task main: [:callback] do
puts #greeting
end
# case 2
# In this case, `callback` is executed in rspec
# task :main do
# Rake::Task['rspec_before:callback'].execute
# puts #greeting
# end
end
So, I'm not sure I would call :callback a callback, it's more of a dependency. A callback implies it happens after the main task is done, whereas when you do
task main: [:callback]
what you're really saying is that you depend on the other task having run first. So I would end up changing the name of that, though that's probably just a sample/throwaway name for this question. But, I digress and I'll continue calling the task :callback as written for this answer.
The main issue here is that when you call execute on a rake task, only that task gets executed. This is because there may be situations where you don't want or need to call the entire dependency chain. Let's say we add another task to your file:
desc "secondary task"
task :secondary do
#greeting = 'Goodbye, Cruel World'
Rake::Task['rspec_before:main'].execute
end
If we run this, we very likely want the main task to output Goodbye, Cruel World, instead of Hello, World and if we call all the dependencies, main would end up calling :callback which would override our #greeting and end up outputting Hello, World.
There is, however, another task that does call the entire dependency chain: invoke:
desc "secondary task"
task :secondary do
#greeting = 'Goodbye, Cruel World'
Rake::Task['rspec_before:main'].invoke
end
if we run this task, now we'll see Hello, World instead of Goodbye, Cruel World. So, having said all of this, what does that mean for your RSpec test? You simply need to change your subject to:
subject { #rake['rspec_before:main'].invoke }
because you are wanting to run the dependencies.

Rake before task hook

Is there a straight forward way to modify a Rake task to run some bit of code before running the existing task? I'm looking for something equivalent to enhance, that runs at the beginning rather than the end of the task.
Rake::Task['lame'].enhance(['i_run_afterwards_ha_ha'])
You can use the dependency of Rake task to do that, and the fact that Rake allows you to redefine existing task.
Rakefile
task :your_task do
puts 'your_task'
end
task :before do
puts "before"
end
task :your_task => :before
As result
$ rake your_task
before
your_task
Or you could use the rake-hooks gem to do before and after hooks:
https://github.com/guillermo/rake-hooks
namespace :greetings do
task :hola do puts "Hola!" end ;
task :bonjour do puts "Bonjour!" end ;
task :gday do puts "G'day!" end ;
end
before "greetings:hola", "greetings:bonjour", "greetings:gday" do
puts "Hello!"
end
rake greetings:hola # => "Hello! Hola!"

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

Alias of task name in Rake

When I need to alias some task's name, how should I do it?
For example, how do I turn the task name:
rake db:table
rake db:create
rake db:schema
rake db:migration
to:
rake db:t
rake db:c
rake db:s
rake db:m
Editing after getting the answer:
def alias_task(tasks)
tasks.each do |new_name, old_name|
task new_name, [*Rake.application[old_name].arg_names] => [old_name]
end
end
alias_task [
[:ds, :db_schema],
[:dc, :db_create],
[:dr, :db_remove]
]
Why do you need an alias? You may introduce a new task without any code, but with a prerequisite to the original task.
namespace :db do
task :table do
puts "table"
end
#kind of alias
task :t => :table
end
This can be combined with parameters:
require 'rake'
desc 'My original task'
task :original_task, [:par1, :par2] do |t, args|
puts "#{t}: #{args.inspect}"
end
#Alias task.
#Parameters are send to prerequisites, if the keys are identic.
task :alias_task, [:par1, :par2] => :original_task
To avoid to search for the parameters names you may read the parameters with arg_names:
#You can get the parameters of the original
task :alias_task2, *Rake.application[:original_task].arg_names, :needs => :original_task
Combine it to a define_alias_task-method:
def define_alias_task(alias_task, original)
desc "Alias #{original}"
task alias_task, *Rake.application[original].arg_names, :needs => original
end
define_alias_task(:alias_task3, :original_task)
Tested with ruby 1.9.1 and rake-0.8.7.
Hmmm, well, I see that's more or less exactly the same solution RyanTM already posted some hours ago.
Here is some code someone wrote to do it: https://gist.github.com/232966
def alias_task(name, old_name)
t = Rake::Task[old_name]
desc t.full_comment if t.full_comment
task name, *t.arg_names do |_, args|
# values_at is broken on Rake::TaskArguments
args = t.arg_names.map { |a| args[a] }
t.invoke(args)
end
end

Using a rake task that accepts parameters as a prerequisite

According to http://rake.rubyforge.org/files/doc/rakefile_rdoc.html, you can create a task that accepts parameters and also has prerequisites:
task :name, [:first_name, :last_name] => [:pre_name] do |t, args|
But what if :pre_name is a task that also accepts parameters? What is the syntax for passing parameters to :pre_name when it is used as a prerequisite?
It's actually pretty simple - the :pre task will receive the same parameters as the original task. All you need to do is make sure that the signature is similar - for instance if the first task receives :a,:b the :pre task needs to receive them as well.
See more here: rake with params
I know I'm late to the party, but I had the same problem and figured something out that didn't use environment variables. You can use Rake::Task.invoke to do this. Here's an example for a database backup rake task:
namespace :db do
task :dump_db, [:dump_file, :rails_env] do |t, args|
puts "dumping to #{args[:dump_file]} with rails env = #{args[:rails_env]}"
end
task :stop_slave do
puts "stopping slave"
end
task :start_slave do
puts "starting slave"
end
task :upload_dump, [:dump_file] do |t, args|
puts "uploading #{args[:dump_file]}"
end
task :backup_to_s3, [:dump_file, :rails_env] do |t, args|
Rake::Task["db:stop_slave"].invoke()
Rake::Task["db:dump_db"].invoke(args[:dump_file], args[:rails_env])
Rake::Task["db:start_slave"].invoke()
Rake::Task["db:upload_dump"].invoke(args[:dump_file])
end
end
I don't have a direct answer, but I do have an alternative solution that might work for you. None of my rake tasks use parameters. (I think I tried to use parameters and had trouble getting them to work.) Instead, I rely on the ENV array. So, for example, I would write that example task as:
task :name =>:pre_name do
do_something_with_name(ENV['first_name'], ENV['last_name'])
end
which would be invoked as:
$ rake name first_name=John last_name=Smith
The ENV array data would be available to the pre_name task as well.
namespace :shell do
desc "Local hostname"
task :hostname do
puts "Local hostname"
sh "hostname"
end
desc "Local uptime"
task :uptime do
puts "Local uptime"
sh "uptime"
end
desc "Echo something"
task :echo,[:someword] do |t,args|
puts "--- #{args[:someword]} ---"
end
end
desc "Run all tasks"
task :all , [:someword] => ["shell:hostname","shell:uptime","shell:echo"] do
puts "Done."
end

Resources