Tuesday, November 18, 2008

Extending Capistrano (1.x) task

You can extend the default behavior of Capistrano by different ways. Here I am mentioning the ways that I used to extend the default Capistrano behavior.

Writing Custom Task

We used Capistrano for the first time in a project [www.scrumpad.com] to deploy our application. We used Rails 1.2.5 and the default support from Capistrano was fine for us. But in next project when we were trying to use Capistrano to deploy our Rails application we felt the necessity of extending the default behavior of Capistrano.

In the second case we had different servers (6 servers) to deploy the application in development (2 servers), testing (2 servers) and production (2 servers) environment. We were planning to use the same capfile for deployment in all the servers. There were different configurations for different types of environments and we needed something that will do the configuration based on the user command.

Capistrano has nice support to extend its default behavior to write custom tasks. For our purpose we made three tasks (development, testing, production) and each task set the environment of each environment.

desc "this task sets the development environment"

task :development do

role :app, "my.dev1.server.ip"

role :app, "my.dev2.server.ip"

set :environment, "development"

end

Now as we want to set the environment before any standard Capistrano task start running we run the capfile in this way:

cap [environment] [standard_capistrano_task]
i.e. cap development setup

Using the Event Framework

In Capistrano 1.x we can extend a default task my creating new tasks whose names are prefixed with 'before_' and 'after_'. For example depending on the environment we need to change the value of 'deploy_to' in our application. In that case we can write another task 'before_deploy':

desc "this task set the value for deploy_to based on the value of 'environment'"

task :before_deploy do

if environment == 'development'

set :deploy_to = "deploy_folder_path_in_development_server"

elsif environment == 'testing'

set :deploy_to = "deploy_folder_path_in_testing_server"

elsif environment == 'production'

set :deploy_to = "deploy_folder_path_in_production_server"

end

end

So this task will be called before the calling of 'deploy' task. Similarly if you want to do some extra work after 'deploy' task is called in that case you could write a new task 'after_deploy'

Overriding default task

As I have already said, I was using Capistrano for Rails application. Later for a Ruby application I need to use Capistrano to deploy the application in server and here I found a problem. In Rails application there is a folder 'Public' and the default 'update_code' task makes a link to that folder. But as I was trying with Ruby application where there is no 'Public' folder I was getting an error. To solve the problem I override the standard implementation by creating the same task with custom implementation. Here is the code:

desc <<-DESC
Update all servers with the latest release of the source code. All this does is do a checkout (as defined by the selected scm module). This task is modified for Ruby application
DESC

task :update_code, :except => { :no_release => true } do

on_rollback { delete release_path, :recursive => true }

source.checkout(self)

set_permissions

run <<-CMD rm -rf #{release_path}/log #{release_path}/public/system &&

ln -nfs #{shared_path}/log #{release_path}/log

CMD

@releases = nil

end

In future I will post more on how to extend the default Capistrano tasks with other ways.

No comments: