34

I'm looking into the possibility of using Capistrano as a generic deploy solution. By "generic", I mean not-rails. I'm not happy with the quality of the documentation I'm finding, though, granted, I'm not looking at the ones that presume you are deploying rails. So I'll just try to hack up something based on a few examples, but there are a couple of problems I'm facing right from the start.

My problem is that cap deploy doesn't have enough information to do anything. Importantly, it is missing the tag for the version I want to deploy, and this has to be passed on the command line.

The other problem is how I specify my git repository. Our git server is accessed by SSH on the user's account, but I don't know how to change deploy.rb to use the user's id as part of the scm URL.

So, how do I accomplish these things?

Example

I want to deploy the result of the first sprint of the second release. That's tagged in the git repository as r2s1. Also, let's say user "johndoe" gets the task of deploying the system. To access the repository, he has to use the URL johndoe@gitsrv.domain:app. So the remote URL for the repository depends on the user id.

The command lines to get the desired files would be these:

git clone johndoe@gitsrv.domain:app
cd app
git checkout r2s1
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681

5 Answers5

49

Update: For Capistrano 3, see scieslak's answer.


As jarrad has said, capistrano-ash is a good basic set of helper modules to deploy other project types, though it's not required as at the end of the day it's just a scripting language and most tasks are done with the system commands and end up becoming almost shell script like.

To pass in parameters, you can set the -s flag when running cap to give you a key value pair. First create a task like this:

desc "Parameter Testing"
task :parameter do
  puts "Parameter test #{branch} #{tag}"
end

Then start your task like so:

cap test:parameter -s branch=master -s tag=1.0.0

For the last part, I would recommend setting up passwordless access using ssh keys to your server, but if you want to take it from the current logged in user, you can do something like this:

desc "Parameter Testing"
task :parameter do
  system("whoami", user)
  puts "Parameter test #{user} #{branch} #{tag}"
end

UPDATE: Edited to work with the latest versions of Capistrano. The configuration array is no longer available.

Global Parameters: See comments Use set :branch, fetch(:branch, 'a-default-value') to use parameters globally. (And pass them with -S instead.)

Gareth Jones
  • 1,241
  • 4
  • 17
  • 38
Jamie Sutherland
  • 2,760
  • 18
  • 19
  • That's fine as far as it goes, but how do I tell Capistrano what tag it should check out? – Daniel C. Sobral Apr 27 '12 at 12:53
  • 1
    Using the -s parameter. So I'd have a commandline like this for deploying a specific tag. cap production deploy -s tag=2.1.3 If you are making use of capistano-ash, you just have to do set :branch, #{configuration[:tag]} That should checkout the tag set at the commandline – Jamie Sutherland Apr 27 '12 at 13:14
  • 2
    This doesn't work anymore. According to https://groups.google.com/forum/?fromgroups=#!topic/capistrano/1nFQPWf9EIo and other places, `configuration` has been deprecated: `undefined local variable or method 'configuration' for # (NameError)`. Now you can just use the variable names. How did this work only a few months ago?? – jordanpg Oct 16 '12 at 17:33
  • The example has been updated. The configuration array is no longer required. – Jamie Sutherland Oct 21 '12 at 17:50
  • 3
    If you're using the multistage extension for Capistrano, the stage.rb files seem to be evaluated after the code in the Capfile, and variables that are set there will override variables set via the -s parameter. I had to do something like the following in my multistage files: `set :p, "default" if ! :p` This kept the parameter from being obliterated. –  Apr 02 '13 at 21:48
  • 2
    I've found that parameters passed in with -s param are only scoped to the tasks, so if you need to access a param globally (eg to meta-program some task creation) then this doesnt work... – johnmartirano Aug 28 '13 at 21:34
  • 4
    Yes, exactly - use `set :branch, fetch(:branch, 'a-default-value')` to use parameters globally. (And pass them with `-S` instead.) – cbmanica Sep 14 '13 at 23:43
  • 1
    Please add on your answer the comment done by @cbmanica. It is important to know how to set a variable out of a task! – fotanus Oct 10 '13 at 17:18
  • Currently you should use env vars instead of `-S`: https://github.com/capistrano/capistrano/issues/807 – Nakilon Dec 27 '14 at 11:08
20

Update. Regarding passing parameters to Capistrano 3 task only.

I know this question is quite old but still pops up first on Google when searching for passing parameters to Capistrano task. Unfortunately, the fantastic answer provided by Jamie Sutherland is no longer valid with Capistrano 3. Before you waste your time trying it out except the results to be like below:

cap test:parameter -s branch=master 

outputs :

cap aborted!
OptionParser::AmbiguousOption: ambiguous option: -s
OptionParser::InvalidOption: invalid option: s

and

cap test:parameter -S branch=master 

outputs:

invalid option: -S

The valid answers for Capistrano 3 provided by @senz and Brad Dwyer you can find by clicking this gold link: Capistrano 3 pulling command line arguments

For completeness see the code below to find out about two option you have.

1st option:

You can iterate tasks with the key and value as you do with regular hashes:

desc "This task accepts optional parameters"

task :task_with_params, :first_param, :second_param do |task_name, parameter|
  run_locally do
    puts "Task name: #{task_name}"
    puts "First parameter: #{parameter[:first_param]}"
    puts "Second parameter: #{parameter[:second_param]}"
  end
end

Make sure there is no space between parameters when you call cap:

cap production task_with_params[one,two]

2nd option:

While you call any task, you can assign environmental variables and then call them from the code:

set :first_param, ENV['first_env'] || 'first default'
set :second_param, ENV['second_env'] || 'second default'

desc "This task accepts optional parameters"
task :task_with_env_params do
  run_locally do
    puts "First parameter: #{fetch(:first_param)}"
    puts "Second parameter: #{fetch(:second_param)}"
  end
end

To assign environmental variables, call cap like bellow:

cap production task_with_env_params first_env=one second_env=two

Hope that will save you some time.

Community
  • 1
  • 1
scieslak
  • 584
  • 6
  • 8
10

I'd suggest to use ENV variables.

Somethings like this (command):

$ GIT_REPO="johndoe@gitsrv.domain:app" GIT_BRANCH="r2s1" cap testing

Cap config:

#deploy.rb:
task :testing, :roles => :app do
  puts ENV['GIT_REPO']
  puts ENV['GIT_BRANCH']
end

And take a look at the https://github.com/capistrano/capistrano/wiki/2.x-Multistage-Extension, may be this approach will be useful for you as well.

deadrunk
  • 13,861
  • 4
  • 29
  • 29
  • 1
    I've noticed that using environment variables are "in" with Ruby stuff, but I think they are very inconvenient. For instance, I'd require three separate commands on Windows with the suggestion you present, each one subject to small typo errors, and lousy feedback if you do make a typo. – Daniel C. Sobral Apr 27 '12 at 12:48
  • I agree with the last comment, I prefer a command line with -s or -S var=value and then something like `if variables.include?(:var) ... else ... end` – Federico Jun 20 '12 at 15:32
3

As Jamie already showed, you can pass parameters to tasks with the -s flag. I want to show you how you additionally can use a default value.

If you want to work with default values, you have to use fetch instead of ||= or checking for nil:

namespace :logs do
  task :tail do
    file = fetch(:file, 'production') # sets 'production' as default value
    puts "I would use #{file}.log now"
  end
end

You can either run this task by (uses the default value production for file)

$ cap logs:tail

or (uses the value cron for file

$ cap logs:tail -s file=cron
tbuehl
  • 178
  • 1
  • 6
0

Check out capistrano-ash for a library that helps with non-rails deployment. I use it to deploy a PyroCMS app and it works great.

Here is a snippet from my Capfile for that project:

# deploy from git repo
set :repository, "git@git.mygitserver.com:mygitrepo.git"
# tells cap to use git
set :scm, :git

I'm not sure I understand the last two parts of the question. Provide some more detail and I'd be happy to help.

EDIT after example given:

set :repository, "#{scm_user}@gitsrv.domain:app"

Then each person with deploy priveledges can add the following to their local ~/.caprc file:

set :scm_user, 'someuser'
jarrad
  • 3,292
  • 1
  • 23
  • 15