1
0
Fork 0
mirror of https://github.com/capistrano/capistrano synced 2023-03-27 23:21:18 -04:00

Commit this stuff before I lose it all

This commit is contained in:
Lee Hambley 2013-06-12 22:44:00 +02:00
commit 61aec364b2
26 changed files with 1094 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
_site

6
Gemfile Normal file
View file

@ -0,0 +1,6 @@
source "https://rubygems.org"
gem "debugger"
gem "jekyll"
gem "redcarpet"
gem "git"

50
Gemfile.lock Normal file
View file

@ -0,0 +1,50 @@
GEM
remote: https://rubygems.org/
specs:
classifier (1.3.3)
fast-stemmer (>= 1.0.0)
colorator (0.1)
columnize (0.3.6)
commander (4.1.3)
highline (~> 1.6.11)
debugger (1.6.0)
columnize (>= 0.3.1)
debugger-linecache (~> 1.2.0)
debugger-ruby_core_source (~> 1.2.1)
debugger-linecache (1.2.0)
debugger-ruby_core_source (1.2.2)
directory_watcher (1.4.1)
fast-stemmer (1.0.2)
git (1.2.5)
highline (1.6.19)
jekyll (1.0.2)
classifier (~> 1.3)
colorator (~> 0.1)
commander (~> 4.1.3)
directory_watcher (~> 1.4.1)
kramdown (~> 1.0.2)
liquid (~> 2.3)
maruku (~> 0.5)
pygments.rb (~> 0.5.0)
safe_yaml (~> 0.7.0)
kramdown (1.0.2)
liquid (2.5.0)
maruku (0.6.1)
syntax (>= 1.0.0)
posix-spawn (0.3.6)
pygments.rb (0.5.0)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
redcarpet (2.2.2)
safe_yaml (0.7.1)
syntax (1.0.0)
yajl-ruby (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
debugger
git
jekyll
redcarpet

7
_config.yml Normal file
View file

@ -0,0 +1,7 @@
name: Capistrano
pygments: true
markdown: redcarpet
redcarpet:
extensions: ["no_intra_emphasis", "fenced_code_blocks", "autolink", "tables", "with_toc_data"]
table_of_contents:
dirs: [documentation]

28
_includes/footer.html Normal file
View file

@ -0,0 +1,28 @@
<div class="bottom-menu">
<div class="container">
<div class="row">
<div class="span2 brand">
<a href="http://capistranorb.com/" class="capistrano-logo"></a>
</div>
<div class="span8">
<ul class="bottom-links">
<li><a href="#fakelink">About Capistrano</a></li>
<li><a href="#fakelink">Contributing</a></li>
<li><a href="#fakelink">Releases</a></li>
<li><a href="#fakelink">Upgrading</a></li>
<li><a href="#fakelink">StackOverflow</a></li>
<li><a href="#fakelink">Mailing List</a></li>
<li><a href="#fakelink">Support</a></li>
<li><a href="#fakelink">Links</a></li>
</ul>
</div>
<div class="span2">
<ul class="bottom-icons">
<li><a href="#fakelink" class="fui-twitter"></a></li>
</ul>
</div>
</div>
</div>
</div>

5
_includes/header.html Normal file
View file

@ -0,0 +1,5 @@
<div class="header pure-u-1-1">
<a href="/" class="brand">
<img src="/images/CapistranoLogo.png" />
</a>
</div>

31
_includes/navigation.html Normal file
View file

@ -0,0 +1,31 @@
<div class="pure-menu pure-menu-open">
<ul class="nav nav-list">
<li><a href="http://www.harrow.io/" class="advertisment"><span class="label label-important">New</span> Hosted Capistrano for Teams</a></li>
<li class="pure-menu-heading">Overview</li>
<li><a href="/documentation/overview/what-is-capistrano/">What is Capistrano?</a></li>
<li><a href="/documentation/overview/introductory-demo-video/">Introductory Demo Video</a></li>
<li class="pure-menu-heading">Getting Started</li>
<li><a href="/documentation/getting-started/installation/">Installation</a></li>
<li><a href="/documentation/getting-started/preparing-your-application/">Preparing Your Application</a></li>
<li><a href="/documentation/getting-started/authentication-and-authorisation/">Authentication & Authorisation</a></li>
<li><a href="/documentation/getting-started/cold-start/">Cold Start</a></li>
<li><a href="/documentation/getting-started/rollbacks/">Rollbacks</a></li>
<li class="pure-menu-heading">Troubleshooting</li>
<li><a href="/documentation/troubleshooting/authentication/">SCM (Git, SVN, etc) Authentication</a></li>
<li><a href="/documentation/troubleshooting/connectivity/">Connectivity</a></li>
<li><a href="/documentation/troubleshooting/gateway-servers/">Gateway Servers</a></li>
<li><a href="/documentation/troubleshooting/agent-forwarding/">Agent Forwarding</a></li>
<li><a href="/documentation/troubleshooting/sudo-password/">`sudo` Password</a></li>
<li><a href="/documentation/troubleshooting/rvm-rbenv-nvm/">RVM, `rbenv` And `nvm`</a></li>
<li class="pure-menu-heading">FAQ</li>
<li><a href="/documentation/faq/why-does-something-work-in-my-ssh-session-but-not-in-capistrano/">Why Does Something Work In An SSH Session, But Not In Capistrano</a></li>
<li><a href="/documentation/faq/should-i-use-capistrano-to-provision-my-servers/">Should I Use Capistrano To Provision My Servers?</a></li>
<li class="pure-menu-heading">Power Use-Cases</li>
<li><a href="/documentation/power-use-cases/integration-with-rake/">Integration With Rake</a></li>
<li><a href="/documentation/power-use-cases/driving-tools-such-as-chef-solo/">Driving Tools Such As <em>Chef Solo</em></a></li>
<li class="pure-menu-heading">Recent Announcements</li>
{% for post in site.posts %}
<li><a href="{{ post.url }}"><span class="post-date">{{ post.date | date_to_string }}</span> {{ post.title }}</a></li>
{% endfor %}
</ul>
</div>

47
_layouts/default.html Normal file
View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ page.title }}</title>
<script type="text/javascript" src="//use.typekit.net/itm5ubu.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Enriqueta' rel='stylesheet' type='text/css'>
<link href="http://vjs.zencdn.net/4.0.2/video-js.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/4.0.2/video.js"></script>
<link rel="stylesheet" href="http://yui.yahooapis.com/pure/0.1.0/pure-min.css">
<link rel="stylesheet" href="/css/syntax.css">
<link rel="stylesheet" href="/css/capistrano.css">
</head>
<body>
{% include header.html %}
<div class="pure-g-r">
<div class="pure-u-1-3">
{% include navigation.html %}
</div>
<div class="pure-u-2-3">
<div class="content">
<h2>{{ page.title }}</h2>
{{ content }}
</div>
</div>
</div>
<!--<div class="container"> -->
<!-- <h1 class="title"><a href="/">{{ site.name }}</a></h1>-->
<!-- <a class="extra" href="/">home</a> -->
<!-- </div> -->
<!-- {{ content }} -->
<!--</div> [> /container <] -->
{% include footer.html %}
</body>
</html>

8
_layouts/post.html Normal file
View file

@ -0,0 +1,8 @@
---
layout: default
---
<p class="meta">{{ page.date | date_to_string }}</p>
<div id="post">
{{ content }}
</div>

View file

@ -0,0 +1 @@
Why is this here?

32
_plugins/gitactivity.rb Normal file
View file

@ -0,0 +1,32 @@
require 'git'
module Jekyll
class GitActivityTag < Liquid::Tag
def initialize(tag_name, text, tokens)
super
end
def render(context)
result = ""
g = Git.open(File.join(Dir.getwd, ".."))
index = 0
g.log.each do |log|
if(index < 10)
result << "<li>"
result << log.date.strftime("%d %b")
result << " - <a href='https://github.com/capistrano/capistrano-documentation/commit/"
result << log.sha
result << "/'>"
result << log.message
result << "</a></li>"
index += 1
end
end
"<ul>#{result}</ul>"
end
end
end
Liquid::Template.register_tag('gitactivity', Jekyll::GitActivityTag)

View file

@ -0,0 +1,30 @@
require 'git'
module Jekyll
class TableOfContentsTag < Liquid::Tag
def initialize(tag_name, text, tokens)
super
end
def render(context)
result = ""
g = Git.open(File.join(Dir.getwd, ".."))
index = 0
g.log.each do |log|
if(index < 10)
result << "<li>"
result << log.date.strftime("%d %b")
result << " - <a href='https://github.com/capistrano/capistrano-documentation/commit/"
result << log.sha
result << "/'>"
result << log.message
result << "</a></li>"
index += 1
end
end
"<ul>#{result}</ul>"
end
end
end
Liquid::Template.register_tag('table_of_contents', Jekyll::TableOfContentsTag)

View file

@ -0,0 +1,24 @@
---
layout: post
title: "Welcome to Jekyll!"
date: 2013-05-18 15:09:49
categories: jekyll update
---
You'll find this post in your `_posts` directory - edit this post and re-build (or run with the `-w` switch) to see your changes!
To add new posts, simply add a file in the `_posts` directory that follows the convention: YYYY-MM-DD-name-of-post.ext.
Jekyll also offers powerful support for code snippets:
{% highlight ruby %}
def print_hi(name)
puts "Hi, #{name}"
end
print_hi('Tom')
#=> prints 'Hi, Tom' to STDOUT.
{% endhighlight %}
Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll's GitHub repo][jekyll-gh].
[jekyll-gh]: https://github.com/mojombo/jekyll
[jekyll]: http://jekyllrb.com

View file

@ -0,0 +1,529 @@
---
layout: post
title: "Capistrano Version 3 Release Announcement"
date: 2013-06-01 00:00:00
---
After what seems like years of work, the Capistrano team (that's Tom and I)
are pleased to announce the first *major* release of Capistrano in almost 5
years.
The reasons behind the length of time between the last architectural overhaul
and this one are numerous, but it can be summrised to say that Capistrano is a
widely used tool, and when working around software deployment it's really a
question of downtime. If we had changed something significant in Capistrano we
could have taken a lot of sites offline, and made a lot of people very
unhappy. Until this point we haven't felt that the time has been ripe where
the benefits of a slightly rocky upgrade path are worth the risks of downtime.
It also hasn't helped historically that we've only just gotten to grips with
Ruby 1.9, and that Bundler's near ubuquity means that now it's trivial to lock
a Gem at a specific version. With other tools in the Ruby eco system it's
become easier for us to make significant changes to a tool upon which many
hundreds of thousands of people rely.
### Design Goals
We had a few goals for this release, in no particular order they were:
* **Get away from our own DSL solution.** Great DSL alternatives (Rake, Sake, Thor,
etc) are already widely used.
* **Better modularisation.** to enable people outside the Rails community to
benefit from Capistrano's *best-practice* workflow, and to enable people in
the Rails community to pick and choose support for components they use
(Database Migrations, Asset Pipeline, etc)
* **Easier Debugging.** A lot of problems with Capistrano come from weirdness
surrounding environmental issues around PTY vs non-TTY environments, login
and non-login shells not to mention *environment managers* such as rvm,
rbenv and nvm.
* **Speed.** We know that in a lot of environments speed of deploment is a
huge factor, since Rails introduced the *Asset Pipeline* it's not uncommon
for a deploy that formerly took 5 seconds now takes 5 minutes. This really
is mostly out of our control, but with improved support for parallelism,
rolling restarts we feel confident that things are bettwe not.
* **Applicability.** We've always maintained that Capistrano is a terrible
tool for system provisioning, and that more often than not servers are
better being setup with Chef, Puppet or similar, whilst we still agree with
that, the new features in Capistrano really lend themselves to integrating
with these kinds of tools.
### What's missing?
Before we get too carried away it's worth shortlisting the things that don't
exist in version three, *yet*.
* *Run Locally.* `run_locally` was always a bit of the poor relation in the
family, it didn't quite work the same way as other things, and I never liked
the idea that you were binding a tool that in principle should be cross
platform (Ruby, and Capistrano) to locally executing shell commands which
probably only work on POSIX-like operating systems. I hope that
`run_locally` will stay gone, and that as a community we can find better
ways of doing things that always relied on locally creating tarballs, or
writing configuration files, or similar.
* *SSH Gateway Support.* SSH Gateway support hasn't been implemented in
version three yet, I hope that this will be done soon. As I have no direct
need for it, I haven't the means to test it with a view to implementing it,
yet.
* *Mecurial, Subversion, and CVS Support.* These have been removed as we've
been able to implement the Git SCM in an incredibly neat way that isn't
compatible with the others. We wanted to break the cycle of always sticking
with the lowest common denominator, so we are **actively** looking for
people who are interested in contributing, or sharing expertise on the
*best-practice* way of speedily deploying from your respective choice of
source control.
* *`HOSTFILTER` ,`ROLEFILTER` and friends.* These have gone away because I
always felt they were indemic of a bad design desision about using
Environmental Variables. These will be coming back as flags passed to `cap`
on the CLI, and options that can be set on the Capistrano::Application Ruby
class.
* *Shell.* The shell has been removed temporarily pending a neater
implementation, we've got something that we are playing with internally, but
it needs better readline support, and some more controls around what to do
when things go badly on some servers, but not others.
* *Cold Deploy.* The `cap deploy:cold` is a really old legacy component,
orignally from the days of the `script/spinner` where deploying cold
(starting workers that weren't running), and deploying a *warm* system were
different (restarting existing worker pools, which wasn't fun!) By and large
these things have gone away, and it's time `deploy:cold` went away. It's
safe in every case we could find to call setup, and seed and other Rake
tasks without things blowing up, and that should be the approach we take.
Tasks on the server should be idempotent, and if something is called twice,
let it be.
* *Coloured Output.*✝ The capistrano-colours Gem was (fairly) recently merged
into Capistrano v2, this has gone away in favour of a IO streaming model
inspired by MiniTest/Pride. Read more below in new features.
### What's new?
Each section here really deserves it's own sub-heading as some of the new
features are awesome.
#### Rake Integration
We have moved away from our own DSL implemenation to implement Capistrano as a
Rake application.
Rake has always supported being sub-classed, so to speak as a
*sub-application*; it is however poorly documented. By subclassing
Rake::Application one can specify what the *Rakefile* should look like, where
to search for it, and how to load other *Rakefiles*.
The *Rake* DSL is widely used, well known and very powerful. As Rake is
essentially a dependency resolution system, it offers a lot of nice ways to,
for example build a tarball as a dependency of uploading it and deploying it.
This has allowed us to do away with the *copy* strategy all together, as it
can now be implemented from scratch in fewer than ten lines of code. You can
check out the [replicating the copy strategy][] screencast and acompanying
documentation if you want to explore that any further.
The guiding principle is dependency resolution, and interoperability with
other tools, for example:
{% highlight ruby %}
# No description, this is an internal method
task :notify do
this_release_tag = sh("git describe --abbrev=0 --tags")
last_ten_commits = sh("git log #{this_release_tag}~10..#{this_release_tag}")
Mail.deliver do
to "team@example.com"
subject "Releasing #{this_release_tag} Now!"
body last_ten_commits
end
end
namespace :deploy
task default: :notify
end
{% endhighlight %}
The last three lines rely on Rake's additive task declaration, by redefining the
`deploy:default` task by adding another dependency. Rake will automatically
resolve this dependency at Runtime, mailing the recent changelog to your team,
assuming everything is setup correctly.
#### Built In Stage Support
#### Parallelism
In former versions of Capistrano there was a *parallel* option to run
different tasks differently on groups of servers, it looked something like
this:
{% highlight ruby %}
task :restart do
parallel do |session|
session.when "in?(:app)", "/u/apps/social/script/restart-mongrel"
session.when "in?(:web)", "/u/apps/social/script/restart-apache"
session.else "echo nothing to do"
end
end
{% endhighlight %}
This always felt a little unclean, and indeed it's a hack that was originally
implemeted to facilitate rolling deployments at a large German firm by a
couple of freelancers who were consulting with them. (Hint, one of those guys
went on to found Travis-CI!)
The equivilent code in under Capistrano v3 would look like this:
{% highlight ruby %}
task :restart do
on :all, in: :parallel do |host|
if host.roles.include?(:app)
execute "/u/apps/social/script/restart-mongrel"
elsif host.roles.include?(:web)
execute "/u/apps/social/script/restart-web"
else
info "Nothing to do for #{host} with roles #{host.properties.roles}."
end
end
end
{% endhighlight %}
The second block of code, that representing the new Rake derived DSL and
demonstrating how to use the parallel execution mode is a little longer, but I
think it's clearer, more idiomatic Ruby code which relies less on an intimate
knowledge of how the Capistrano DSL happens to work. It also hints at the
built-in logging subsystem, keep reading to learn more.
Other modes for parallelism include:
{% highlight ruby %}
on :all, in: :groups, max: 3, wait: 5 do
# Take all servers, in groups of three which execute in parallel
# wait five seconds between groups of servers.
# This is perfect for rolling restarts
end
on :all, in: :sequence, wait: 15 do
# This takes all servers, in sequence and waits 15 seconds between
# each server, this might be perfect if you are afraid about
# overloading a shared resource, or want to defer the asset compilation
# over your cluster owing to worries about load
end
on :all, in: :parallel do
# This will simply try and execute the commands contained within
# the block in parallel on all servers. This might be perfect for kicking
# off something like a Git checkout or similar.
end
{% endhighlight %}
The internal tasks, for standard deploy recipes make use of all of these as is
appropriate for the normal case, no need to be afraid of scary slow deploys
again!
#### Streaming IO
This IO streaming model means that results from commands, the commands
themselves and any other arbitrary output are sent as objects to a class with
an `IO`ish interface, the class knows what to do with these things. There's a
*progress* formatter which prints dots for each command that is called, as
well as a *pretty* formatter which prints the full command, it's output on
standard out and standard error, as well as the final return status. It would
be trivial to implement HTML formatters, or formatters that reported to your
IRC room, or to email. I look forward to seeing more of these cropping up in
the community.
#### Host Definition Access
If you didn't skim over the *Parallism* section above, you might have noticed we
did something clever that wasn't possible in Capistrano v2; we accessed the
`host` inside the execution block.
For a lot of reasons in Capistrano v2 is wasn't possible to do this, the block
was essentially evaluated once and called verbatim on each host. This lead to
disappointing missing features such as not being able to pull the host list
out of Capistrano and examine the roles to do something like controlling chef
solo, or similar.
In Capistrano v3 the `host` object is the same object that is created when a
server is defined, and is internally used, for example to pass to an ERB
template for rendering a last-deploy message that is dumped onto each server
after a successful deployment. The last deploy log includes everything
Capistrano knew about that server during the deployment.
> Users of Capistrano v2 may be familiar with the perenial `cap deploy:cleanup`
problem which came to light when servers differed in their old releases list,
imagine a scenario with two servers, one has been your bread-and-butter since
you launched, it has hundreds of old releases from all your wonderful deploys
over the months or years. The second server has been in the cluster for about
a month, it didn't quite slot-in cleanly, so the list of old releases looks a
bit weird, you deleted a few by hand, and anyway there might only be ten-or-so
releases there.
> Now imagine that you call `cap deploy:cleanup`, old `capture()`
implementations silently only ran on the first server that matched the
properties defined, so server one returned a list of ~95 old timestamped
release directories. Next Capistrano v2 would call `rm -rf
release1..release95` on **both** servers, causing server two to err our, and
leaving an undefined state on server one, as Capistrano would simply hang up
both connections.
This cleanup routine can now be better implemented as follows (which is
actually more or less the actual implenetation in the the new Gem):
{% highlight ruby %}
desc "Cleanup all old releases (keeps #{fetch(:releases_to_keeo_on_cleanup)}
old releases"
task :cleanup do
keep_releases = fetch(:releases_to_keeo_on_cleanup)
releases = capture(:ls, fetch(:releases_directory))
release_to_delete = releases.sort_by { |r| rn.to_i }.slice(1..-(keep_releases + 1))
releases_to_delete.each do |r|
execute :rm, fetch(:releases_directory).join(r)
end
end
{% endhighlight %}
Some handy things to note here are that both server one and server two in our
contrived example will both evaluate that independently, and when both servers
are finished removing old releases the `task :cleanup` block will have
finished.
Also in Capistrano v3 most path varaibles are [`Pathname`] objects, so they natively
respond to things like `#basename`, `#expand_path`, `#join` and similar.
**Warning:** `#expand_path` probably won't do what you expect, it will execute
on your *workstation* machine, and not on the remote host, so it's possible
that it will return an error in the case of paths which exist remotely but not
locally.
#### Host Properties
As the `host` object is now available to the task blocks, it made sense to make
it possible to store arbitrarty values against them.
Enter `host.properties`. This is a simple [*OpenStruct*][] which can be used to
store any additional properties which are important for your application.
An example of it's usage might be:
{% highlight ruby %}
h = SSHKit::Host.new 'example.com'
h.properties.roles ||= %i{wep app}
{% endhighlight %}
#### More Expressive Command Language
In Capistrano v2, it wasn't uncommon to find commands such as:
{% highlight ruby %}
task :precompile, :roles => lambda { assets_role }, :except => { :no_release => true } do
run <<-CMD.compact
cd -- #{latest_release} &&
RAILS_ENV=#{rails_env.to_s.shellescape} #{asset_env} #{rake} assets:precompile
CMD
end
{% endhighlight %}
In Capistrano v3 this looks more like this:
{% highlight ruby %}
task :precompile do
on :sprockets_asset_host, reject: lambda { |h| h.properties.no_release } do
within fetch(:latest_release_directory)
with rails_env: fetch(:rails_env) do
execute :rake, 'assets:precompile'
end
end
end
end
{% endhighlight %}
Again, with other examples this format is a little longer, but much more
expressive, and all the nightmare of shell escaping is handled interally for
you, environmental variables are capitalised and applied at the correct point
(i.e between the `cd` and `rake` calls in this case).
Other options here include `as :a_user` and
#### Better *magic* Variable Support
In Capistrano v2 there were certain bits of magic where if calling a variable
and NoMethodError would have been raised (for example the
`latest_release_directory` varaible). This variable never existed on the
global namespace, as a fall-back the list of `set()` variables would be
consulted.
This magic lead to times when people were not recognising that magic variables
were even being used. The magic variable system of Capistrano v2 did also
include a way to `fetch(:some_variable, 'with a default value')` incase the
variable might not be set already, but it wasn't widely used, and more often
than not people just used things like `latest_release_directory` never knowing
that behind the scenes an exception was raised, then rescued, and that
`:latest_release_directory` in the variable map was actually a continuation
that was evaluated the first time it was used, and the value then cached until
the end of the script.
The system has now 100% less magic. If you set a variable using `set()`, it
can be fetched with `fetch()`, if the value you set into the variable responds
to `#call` then it will be executed in the current context whenever it is
used, the values will not be cached, unless your continuation does some
explicit caching. *Again, we are favoring clarity over micro optimisation*.
#### SSHKit
Many of the new features in Capistrano whch relate to logging, formatting,
SSH, connection management and pooling, parallism, batch execution and more
are from a library that fell out of the Capistrano v3 development process.
[*SSHKit*][] is a lower level toolkit, a level higher than *Net::SSH*, still
but lacking the roles, environments, rollbacks and other higher level features
from Capistrano.
SSHkit is ideal for use if you need to just connect to a machine and run some
arbitrary command, for example:
{% highlight ruby %}
# Rakefile
require 'sshkit'
desc "Check the uptime of example.com"
task :uptime do |h|
execute :uptime
end
{% endhighlight %}
There is much more than can be done with SSHKit, and we have quite an
extensive [list of examples][]. For the most part with Capistrano v3, anything
that happens inside of an `on()` block is happening in SSHkit, and the
documentation from that library is the place to go to find more information.
#### Command Mapping
This is another feature from SSHKit, designed to remove a little ambiguity
from preceedings, there is a so-called command map for commands.
When executing something like:
{% highlight ruby %}
execute "git clone ........ ......."
{% endhighlight %}
The command is passed through to the remote server *completely unchanged*.
This includes the options which might be set, such as user, directory, and
environmental variables. **This is by design.** This feature is designed to
allow people to write non-trivial commands in [heredocs][] when the need
arises.
The idiomatic way to write that command in Capistrano v3 is to use the
separated variadaric method to specify the command:
{% highlight ruby %}
execute :git, :clone, "........", "......."
{% endhighlight %}
In this way the *command map* is consulted, the command map maps all unknown
commands (which in this case is `git`, the rest of the line are *arguments* to
`git` ) are mapped to `/usr/bin/env ...`. Meaning that this command would be
expanded to `/usr/bin/env git clone ...... ......` which is what happens when
`git` is called without a full path, the `env` program is consulted (perhaps
indirectly) to determine which `git` to run.
Commands such as `rake` and `rails` are often better prefixed by `bundle
exec`, and in this case could be mapped to:
{% highlight ruby %}
SSHKit.config.command_map[:rake] = "bundle exec rake"
SSHKit.config.command_map[:rails] = "bundle exec rails"
{% endhighlight %}
There can also be a lamda or Proc applied in place of the mapping like so:
{% highlight ruby %}
SSHKit.config.command_map = Hash.new do |hash, key|
if %i{rails rake bundle clockwork heroku}.include?(key.to_sym)
hash[key] = "/usr/bin/env bundle exec #{key}"
else
hash[key] = "/usr/bin/env #{key}"
end
end
{% endhighlight %}
Between these two options there should be quite powerful options to map
commands in your environment without having to override internal tasks from
Capistrano just because a path is different, or a binary has a different name.
This can also be *slightly* abused in environments where *shim* executables
are used, for example `rbenv` *wrappers*:
{% highlight ruby %}
SSHKit.config.command_map = Hash.new do |hash, key|
if %i{rails rake bundle clockwork heroku}.include?(key.to_sym)
hash[key] = "/usr/bin/env myproject_bundle exec myproject_#{key}"
else
hash[key] = "/usr/bin/env #{key}"
end
end
{% endhighlight %}
The above assumes that you have done something like `rbenv wrapper default
myproject` which creates wrapper binaries which correctly set up the Ruby
environment without requiring an interactive login shell.
#### Testing
The old test suite for Capistrano was purely unit tests, and didn't cover a
wide varity of problem cases, specifically nothing in the `deploy.rb` (that is
the actual *deployment* code) was tested at all; because of having our own DSL
implementation, and other slightly odd design points, it was painful to test
the actual *recipes*.
Testing has been a focus of Capistrano v3. The *integration* test suite uses
Vagrant to boot a machine, configures certain scenarios using portable shell
script, and then executes commands against them, deploying common
configurations to typical Linux systems. This is slow to execute, but offers
stronger guarantees that nothing is broken that we've ever been able to give
before.
Capistrano v3 also offers a possibility to swap out backend implementations.
This is interesting because for the purpose of testing your *own* recipes you
can use a *printer* backend, and verify that the output matched what you
expected, or use a stubbed backend upon which you can verify that calls were
made, or not made as expected.
#### Arbitrary Logging
Capistrano exposes the methods `debug()`, `info()`, `warn()`, `error()` and
`fatal()` inside of `on()` blocks which can be used to log using the existing
logging infrastructure and streaming IO formatters:
{% highlight ruby %}
on hosts do |host|
f = '/some/file'
if test("[ -d #{f} ]")
execute :touch, f
else
info "#{f} already exists on #{host}!"
end
end
{% endhighlight %}
### Upgrading
The best place to go here is the [upgrading documentation][] to get deeper
into the specifics.
The simple version is to say that there is *no **direct** upgrade path*,
versions two and three are incompatible.
This is partly by design, the old DSL was imprecise in places that would have
made doing the right thing in most cases tricky, we opted to invest in more
features and better reliability than investing in keeping a backwards
compatible API.
There are a number of *gotchas* listed below, but the main points are the new
names of the built-in roles, as well as that by default Capistrano v3 is
platform agnostic, if you need Rails support, for migrations, asset pipeline
and such like, then it's required to `require` the support files.
### Gotchas
#### Rake DSL Is Additive
In Capistrano v2 if you re-define a task then it replaces the original
implemetation, this has been used by people to replace internal tasks
piecemeal with their own implementations
#### `sudo` Behaviour

4
changes.html Normal file
View file

@ -0,0 +1,4 @@
---
layout: default
title: "Recent Site Changes"
---

66
css/capistrano.css Normal file
View file

@ -0,0 +1,66 @@
a {
text-decoration: none;
color: #52C1DB;
}
body, p, a {
font-family: 'Open-Sans', sans-serif;
-webkit-font-smoothing: antialiased;
}
p, h1, h2, h3, h4, h5, h6 {
color: #1C1B39;
}
.header {
height: 195px;
background-color: #1C1B39;
background-image: url('/images/CapistranoGraphicWireframe.png');
background-repeat: no-repeat;
background-size: 275px;
position: relative;
}
.header a {
color: #52C1DB;
}
pre {
margin: 1.3em 0 1em;
padding: 1.3em;
}
code, kbd, pre, samp {
font-family: 'droid-sans-mono', monospace, serif;
background-color: rgb(250, 250, 250);
}
.header a.brand img {
margin: 6.5em auto auto 7em;
width: 300px;
}
h1, h2, h3, h4, h5 h6 {
font-family: 'Enriqueta', serif;
}
.post-date {
font-weight: bold;
}
h1 {
font-size: 36pt;
}
h2 {
font-size: 18pt;
}
.nav.nav-list {
border-top: none;
}
.content {
margin: 1.3em 0 1em;
padding: 1.3em;
}

60
css/syntax.css Normal file
View file

@ -0,0 +1,60 @@
.highlight { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #d14 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #0086B3 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #d14 } /* Literal.String.Backtick */
.highlight .sc { color: #d14 } /* Literal.String.Char */
.highlight .sd { color: #d14 } /* Literal.String.Doc */
.highlight .s2 { color: #d14 } /* Literal.String.Double */
.highlight .se { color: #d14 } /* Literal.String.Escape */
.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
.highlight .si { color: #d14 } /* Literal.String.Interpol */
.highlight .sx { color: #d14 } /* Literal.String.Other */
.highlight .sr { color: #009926 } /* Literal.String.Regex */
.highlight .s1 { color: #d14 } /* Literal.String.Single */
.highlight .ss { color: #990073 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */

View file

@ -0,0 +1,86 @@
---
title: Installation
layout: default
---
Capistrano is bundled as a Ruby Gem. **It requires Ruby 1.9 or newer.**
Capistrano can be installed as a standalone Gem, or bundled into your
application.
<div class="alert">
It is recommended to fix the version number when using Capistrano, and is
therefore recommended to use an appropriate bundler.
</div>
### General Usage
The following commands will clone Capistrano at the latest `v3` revision, and
will build the gem and install it locally. **The Gem is not yet availalble via
Rubygems.org.**
{% highlight bash %}
$ git clone -b v3 https://github.com/capistrano/capistrano.git
$ cd capistrano
$ gem build *.gemspec
$ gem install *.gem
{% endhighlight %}
### Usage in a Rails project
Add the following lines to the Gemfile, to the group `:development` ideally.
{% highlight ruby %}
group :development do
gem 'capistrano-rails', github: 'capistrano/capistrano-rails', branch: 'v3'
end
{% endhighlight %}
There will be a Gem released via [rubygems.org][rubygems], but as most people
are still using Capistrano v2.x, the v3 release will not be pushed to
[rubygems.org][rubygems] just yet give people a chance to lock their version
in their `Gemfile`.
The *Capistrano-Rails* Gem includes extras specifically designed for Ruby on
Rails, specifically:
* Asset Pipeline Support
* Gem Bundler Support
* Database Migration Support
The documentation for these components can be found in
[their][capistrano-rails-asset-pipeline-readme],
[respective][capistrano-rails-gem-bundler-readme],
[READMEs][capistrano-rails-database-migrations-readme]. However for the most
part, to get the best, and most sensible results, simply `require` these
files:
{% highlight ruby %}
require 'capistrano/rails/assets'
require 'capistrano/rails/gem-bundler'
require 'capistrano/rails/database-migrations'
{% endhighlight %}
<div class="alert alert-info">
<h5>Help! I was using Capistrano `v2.x` and I didn't want to upgrade!</h5>
If you are using Capistrano `v2.x.x` and have also installed Capistrano `v3`
by mistake, then you can lock your Gem version for Capistrano at something
like:
{% highlight ruby %}
gem 'capistrano', '~> 2.15' # Or whatever patch release you are using
{% endhighlight %}
This is the [pessimistic operator][rubygems-pessimistic-operator] which
installs the closest matching version, at the time of writing this would
install `2.15.4`, and any other point-release in the `2.15.x` family without
the risk of accidentally upgrading to `v3`.
</div>
--
[rubygems]: http://rubygems.org/
[rubygems-pessimistic-operator]: http://docs.rubygems.org/read/chapter/16#page74
[capistrano-rails-asset-pipeline-readme]: https://www.github.com/capistrano/asset-pipeline/bundler/README.md
[capistrano-rails-database-migrations-readme]: https://www.github.com/capistrano/migrations/bundler/README.md
[capistrano-rails-gem-bundler-readme]: https://www.github.com/capistrano/capistrano-rails/bundler/README.md

1
documentation/index.html Normal file
View file

@ -0,0 +1 @@
FUCK YOU JEKYLL

View file

@ -0,0 +1,38 @@
---
title: Introductory Demo Video
layout: default
---
The video below was filmed on Mac OSX 10.8 using a more-or-less standard shell
without much previous setup.
It covers using Capistrano to install an example Rails project on a previously
unprepared server, covering all aspects of Github access, as well as
privisioning the server using *Chef Solo* and Capistrano with *Rake*.
#### Show Notes
The *Chef Solo* recipes can be reached at [this repository at
Github][capistrano-chef-solo-example-recipes], they rely on a fairly new
version of *Chef Solo*, spefically any including the results of [this
ticket][chef-issue-3365]. The aforementioned *Chef* issue adds environment
support to *Chef Solo*.
The provisioning can also be done using any other mechanism, it's generally
accepted however that there's not much point in automising your deploys,
unless you are also automating provisioning of your servers for a known,
consistent state.
Using `sudo` with any deployment can be tricky, so it's better to avoid it.
Rebooting services without `sudo` is typically the first place people run into
trouble using Capistrano. The [trouble shooting page for `sudo`
problems][troubleshooting-sudo-password] may help.
**Note:** Some long sequences have been shortened (nobody needs to sit and watch me
sitting and watching Ruby compile, for example!)
--
[chef-issue-3365]: https://github.com/opscode/chef/pull/359
[troubleshooting-sudo-password]: /troubleshooting/sudo-password/

View file

@ -0,0 +1,5 @@
---
title: "Upgrading from v2.x.x"
---
Lorem Ipsum

BIN
images/CapistranoAvatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
images/CapistranoLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

35
index.markdown Normal file
View file

@ -0,0 +1,35 @@
---
layout: default
title: A remote server automation and deployment tool written in Ruby.
---
### A Simple Task
{% highlight ruby %}
role :demo, %{example.com example.org, example.net}
task :uptime do |host|
on :demo, in: :parallel do
uptime = capture(:uptime)
puts "#{host.hostname} reports: #{uptime}"
end
end
{% endhighlight %}
Capistrano extends the *Rake* DSL with methods specific to running commands
`on()` servers.
### For Any Language
Capistrano is written in Ruby, but it can easily be used to deploy any
language. Popular extensions add support for *Wordpress* blogs as well as
*Symfony* and *Node.js* applications.
If your language has special deployment requirements, Capistrano can easily be
extended to support them.
### Demo Video
<video id="demo" class="video-js vjs-default-skin" controls preload="auto" width="640" height="400" data-setup="{}">
<source src="http://capistrano-screencasts.s3.amazonaws.com/Capistrano%20Introduction%20Video.mp4" type='video/mp4'>
</video>