Command Line Arguments in v3

2,156 views
Skip to first unread message

Clinton Blackburn

unread,
Oct 16, 2013, 3:38:38 PM10/16/13
to capis...@googlegroups.com
I am trying to convert a v2 deployment to v3 and have run into issues with command line parameters (e.g. -S variable=value). It seems the -S option is no longer valid. Does v3 support this functionality? If not, what is the recommended workaround? Environment variables?

Vassilis Rizopoulos

unread,
Oct 16, 2013, 4:22:27 PM10/16/13
to capis...@googlegroups.com
Well, the new Capistrano is based on rake so you have a few options.
One is the use of environment variables. You can set the before hand or you can specify them on the command line:

cap stage task VAR=foo

Access in the code is through the ENV Hash:

ENV['VAR']

This is actually what I do and I do it the following way: I put accessor methods for environment variables in a module. This allows me to add code to check for definitions and make sure I warn the user if the parameter is really needed:

module EnvironmentOptions
  def var
    return ENV['VAR']
  end


end


Vassilis Rizopoulos

unread,
Oct 16, 2013, 4:28:24 PM10/16/13
to capis...@googlegroups.com
OK, sent it by mistake so here's the rest of the code

module EnvironmentOptions
 def var!
    mandatory('VAR')
 end
  def mandatory option
    ENV[option] || raise("Environment variable #{option} no set. required for this task")  
  end
end

Rake also has a way to define task arguments. You call the task with 

cap stage task[arg1,arg2]

and then you define the task as

task :task :arg1 :arg2 do |t,args|
 p args
end

TBH I only use the environment variable passing option because it keeps my task definitions cleaner and my parameters neatly documented and tucked away in a module.

Cheers,
V.-

Jonathan Rochkind

unread,
Oct 16, 2013, 4:32:52 PM10/16/13
to capis...@googlegroups.com
Huh. I'm going to miss the capistrano settings feature a lot.

But I had a lot of code that is parameterized with regard to settings,
such that there's a default value, but it can be overridden on the
command line -- and I'm going to miss that feature from the
default/standard recipes too.

I guess it can probably be substituted for with ENV, I'm gonna have to
think about it and experiment a bit.

But, hmm, some of the standard recipes are indeed using capistrano
'settings'. For instance, from: https://github.com/capistrano/rails

Some rails specific options.

set :rails_env, 'staging' # If the environment differs from
the stage

So there are still Capistrano 'settings'--they just can't be set or
overridden on the command line anymore? This seems unfortunate, it
makes Capistrano settings a lot less useful. Perhaps some recipes will
start using ENV instead of capistrano settings, so that they can still
be set/overridden on the command line -- but then what's the point of
capistrano settings?

I wonder if there's a clever way someone can figure out to reintroduce
the possibility of setting capistrano settings on the command line, even
within the Rake wrapper. It might be a good idea.
> --
> --
> * You received this message because you are subscribed to the Google
> Groups "Capistrano" group.
> * To post to this group, send email to capis...@googlegroups.com
> * To unsubscribe from this group, send email to
> capistrano+...@googlegroups.com For more options, visit this
> group at http://groups.google.com/group/capistrano?hl=en
> ---
> You received this message because you are subscribed to the Google
> Groups "Capistrano" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to capistrano+...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Clinton Blackburn

unread,
Oct 16, 2013, 4:45:32 PM10/16/13
to capis...@googlegroups.com
I'm going to go with environment variables. I went so far as to code up an argument parser using OptionParser (http://ruby-doc.org/stdlib-2.0.0/libdoc/optparse/rdoc/OptionParser.html) but ultimately decided environment variables would be cleaner and simpler (since I only have two values I care about).

Thanks,
Clinton

Vassilis Rizopoulos

unread,
Oct 16, 2013, 4:47:01 PM10/16/13
to capis...@googlegroups.com
There are settings.

There's the set, fetch pair which works nice

set :setting, "value"
fetch(:setting,"default value")

I'd put that stuff in the deploy.rb and use environment variables to override. 

A neat way to override would be 

set :setting,ENV['VAR']

fetch (:setting,"Default value")

Unfortunately fetch will return nil as :setting is defined, even though it is nil. Grrr, I'm so hooked on the NullObject pattern that I don't like to see nils anymore.
@Lee do you think it would be a good idea to have a fetch!() that returns the default value if key exists or value==nil? 

Also, because I'm quite new to cap3 as well I might be missing the option switch that allows you to define a setting on the command line. --help though does not give any indication to it's existence.
Cheers,
V.-

Lee Hambley

unread,
Oct 17, 2013, 5:31:48 AM10/17/13
to capistrano
Also, because I'm quite new to cap3 as well I might be missing the option switch that allows you to define a setting on the command line. --help though does not give any indication to it's existence.

No, you're not missing anything. Rather than a broad discussion about settings on the command line, I'd rather see us solve the underlying problem, which appears to be "I need different settings when I run Cap" which implies that maybe more than one stage is in order, or a setup task which prepares the environment, i.e:

    cap production mysetup_a deploy

Where mysetup_a is a version controlled task definition which sets up what you need (in exactly the same way that `production` is a task which sets up what deploy needs.)

Issues to discuss problems, and solutions welcome at GH.

--

Vassilis Rizopoulos

unread,
Oct 17, 2013, 7:01:18 AM10/17/13
to capis...@googlegroups.com
I don't think this is a cap issue.

We have several ways to pass parameters into tasks.
Let's take the obvious two offered by rake: task arguments and environment variables.
Then we have the cap's settings system which works quite well and has a clear override sequence (global to stage to task, or am I mistaken?)

With rake I have very often used the simple trick of creating my own configuration class that reads from a config file and is initialised at the top of my rakefile.
Exactly the same code works with cap, no problems (one of the reasons I loved the change to rake-based cap)

Actually all of my rakefiles nowdays look like this:

require 'helpers'
setup_environment(__FILE__) <---- configuration is read in here
require 'tasks'

and all my code is nicely gemified somewhere else.

Which configuration file to read is then passed via an environment variable. This works intuitively on the command line  (adding CONFIG=foo is very obvious) but it also has the added advantage of allowing us an easy way to set a default.

I think we might have more luck talking about how to think in terms of deploy/stage/task and what belongs where and how we can leverage Ruby to make it more flexible without adding more concepts and/or abstractions to core cap. We then can talk about extensions to core cap in the form of gems.

I must say I like the 

set :foo,ENV['FOO']

fetch(:foo,"bar")

construct but it will get tiresome quick if we have to sprinkle the default value around with every fetch. How about having a set version with 3 params

set(setting,calculator,default)

That way we can write set :foo,ENV['FOO'],"foo"

Which would work the same with a block version of set

set(setting,&block) --> set :foo { ENV['FOO'] || "foo" }

I'll stop thinking out loud now
Cheers,
V.-

Lee Hambley

unread,
Oct 17, 2013, 7:04:57 AM10/17/13
to capistrano
Great ideas Vassilis, I like the 3rd argument to set, and how the block syntax would work, and I agree on not needing a way to replicate `-s`, although I don't think env variables are the solution (my general rule of thumb, is that if you HAVE to set the env var, you are doing something wrong, they should be for easy tweaks to otherwise functioning software config)

Regarding the order of lookup for variables, I agree that it's sane and clean now, and I don't really want to make it messier, but I'd like to better understand Clinton's usecase before dismissing the idea all together.

--

Clinton Blackburn

unread,
Oct 17, 2013, 8:46:09 AM10/17/13
to capis...@googlegroups.com
I have three use cases:
  • Git revision: When my build server finishes running tests, it deploys code. Since commits can occur during testing, HEAD may not necessarily be the revision that was tested and needs to be deployed. Previously I passed -S revision=<git-sha> to ensure only tested code was deployed. We used -S tag when deploying to production.
  • API Versioning: My API versions live on different branches of the same repository and are deployed to different locations. For example, v1 lives in the api/v1 branch and is deployed to /var/www/api-v1. In Capv2, I passed -S version=1 to set the version.
  • Elasticsearch Index Naming: My deployment of ES indices relies on knowing the index name. Since we have indices named based on our customers' names as well as a build number (e.g. acme_186), I need to be able to pass in -S customer=acme -S build_number=186.

Thanks,
Clinton

Lee Hambley

unread,
Oct 18, 2013, 7:23:40 AM10/18/13
to capistrano
Alright Clinton,

Sounds like those don't have a sane default, that is, if they're not set you're deploying in the wind, and that's not a solution.

In this case environmental variables are probably the way to go, or to make a *very* simple wrapper script that loads capistrano, parses your special options with `OptParser` or something, and then defers to the Capistrano application, it would be exactly like https://github.com/capistrano/capistrano/blob/master/bin/cap except you'd be able to drop it into your own app.

In this case, especially as they are required, I'd be tempted to do something like this:

#!/usr/bin/env ruby

require 'optparse'
require 'capistrano/all'

OptionParser.new do |opts|
  opts.banner = "Usage: clintcap [options] [commands as accepted by cap itself]"
  opts.on("-r", "--ref", "Git Reference") do |r|
    $git_reference = r
  end
  opts.on("-e", "--es-index", "ElasticSearch Index Name") do |esi|
    $elasticsearch_index = esi
  end
end.parse!

Capistrano::Application.new.run

--

Konstantin Senz

unread,
Feb 21, 2014, 3:12:47 AM2/21/14
to capis...@googlegroups.com
Hello. Have a look at this http://stackoverflow.com/a/21875603/121048

среда, 16 октября 2013 г., 23:38:38 UTC+4 пользователь Clinton Blackburn написал:
Reply all
Reply to author
Forward
0 new messages