capistrano-fanfare 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,87 @@
1
+ require 'capistrano'
2
+ require 'capistrano/recipes/deploy/strategy/git_style'
3
+
4
+ module Capistrano::Fanfare::GitStyle
5
+ def self.load_into(configuration)
6
+ configuration.load do
7
+ set :scm, :git
8
+ set :deploy_via, :git_style
9
+ set(:release_name) { %{#{Time.now.utc.strftime("%Y%m%d%H%M%S")}-#{real_revision}} }
10
+ set(:release_path) { current_path }
11
+ set(:current_release) { current_path }
12
+ set(:latest_release) { current_path }
13
+
14
+ set(:current_revision) {
15
+ capture("cd #{current_path} && git rev-parse HEAD",
16
+ :except => { :no_release => true }).chomp }
17
+ set(:latest_revision) {
18
+ last_release_dir = releases.length > 0 ? File.join(releases_path, releases.last) : nil
19
+ capture("basename #{last_release_dir} | cut -d - -f 2",
20
+ :except => { :no_release => true }).chomp }
21
+ set(:previous_revision) {
22
+ capture("basename #{previous_release} | cut -d - -f 2",
23
+ :except => { :no_release => true }).chomp if previous_release }
24
+
25
+ namespace :deploy do
26
+ desc <<-DESC
27
+ Copies your project to the remote servers. This is the first stage \
28
+ of any deployment; moving your updated code and assets to the deployment \
29
+ servers. You will rarely call this task directly, however; instead, you \
30
+ should call the `deploy' task (to do a complete deploy) or the `update' \
31
+ task (if you want to perform the `restart' task separately).
32
+
33
+ You will need to make sure you set the :scm variable to the source \
34
+ control software you are using (it defaults to :subversion), and the \
35
+ :deploy_via variable to the strategy you want to use to deploy (it \
36
+ defaults to :checkout).
37
+
38
+ [NOTE] This overrides the capistrano default by removing the \
39
+ on_rollback logic since previous release checkouts don't exist.
40
+ DESC
41
+ task :update_code, :except => { :no_release => true } do
42
+ strategy.deploy!
43
+ finalize_update
44
+ end
45
+
46
+ desc <<-DESC
47
+ [internal] No-op for git-based deployments.
48
+
49
+ [NOTE] This overides the capistrano default since there is no need for a
50
+ symlink farm.
51
+ DESC
52
+ task :create_symlink, :except => { :no_release => true } do
53
+ end
54
+
55
+ namespace :rollback do
56
+ desc <<-DESC
57
+ [internal] Updates git HEAD to the last deployed commit.
58
+ This is called by the rollback sequence, and should rarely (if
59
+ ever) need to be called directly.
60
+ DESC
61
+ task :revision, :except => { :no_release => true } do
62
+ if previous_release
63
+ set :branch, previous_revision
64
+ update_code
65
+ else
66
+ raise "could not rollback the code because there is no prior release"
67
+ end
68
+ end
69
+
70
+ desc <<-DESC
71
+ [internal] No-op for git-based deployments.
72
+ This is called by the rollback sequence, and should rarely
73
+ (if ever) need to be called directly.
74
+ DESC
75
+ task :cleanup, :roles => [:app, :web, :db], :except => { :no_release => true } do
76
+ run %{if [ `(cd #{current_path} && git rev-parse HEAD)` != `#{latest_revision}` ]; then rm -rf #{current_release}; fi}
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ if Capistrano::Configuration.instance
86
+ Capistrano::Fanfare::GitStyle.load_into(Capistrano::Configuration.instance)
87
+ end
@@ -0,0 +1,36 @@
1
+ require 'capistrano'
2
+
3
+ module Capistrano::Fanfare::Multistage
4
+ def self.load_into(configuration)
5
+ configuration.load do
6
+ def _cset(name, *args, &block)
7
+ unless exists?(name)
8
+ set(name, *args, &block)
9
+ end
10
+ end
11
+
12
+ _cset :stages, %w{staging production}
13
+ _cset :default_stage, "staging"
14
+
15
+ require 'capistrano/ext/multistage'
16
+
17
+ # =========================================================================
18
+ # These are the tasks that are available to help with deploying web apps,
19
+ # and specifically, Rails applications. You can have cap give you a summary
20
+ # of them with `cap -T'.
21
+ # =========================================================================
22
+
23
+ desc <<-DESC
24
+ Lists all valid deployment environments.
25
+ DESC
26
+ task :all_stages, :roles => :app, :except => { :no_release => true } do
27
+ logger.important "Valid stages are:\n\n"
28
+ fetch(:stages, []).each { |s| logger.important "* #{s}" }
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ if Capistrano::Configuration.instance
35
+ Capistrano::Fanfare::Multistage.load_into(Capistrano::Configuration.instance)
36
+ end
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module Fanfare
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ require "capistrano"
2
+ require "capistrano/fanfare/version"
3
+
4
+ if Capistrano::Configuration.instance
5
+ Capistrano::Configuration.instance.load_paths << File.dirname(__FILE__)
6
+ end
7
+
8
+ module Capistrano
9
+ module Fanfare
10
+ module Configuration
11
+ def fanfare_recipe(recipe)
12
+ require "capistrano/fanfare/#{recipe}"
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ module Capistrano
19
+ class Configuration
20
+ include Capistrano::Fanfare::Configuration
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'capistrano/recipes/deploy/strategy/remote'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module Strategy
6
+
7
+ class GitStyle < Remote
8
+ protected
9
+
10
+ def command
11
+ @command ||= "if [ -d #{configuration[:current_path]}/.git ]; then " +
12
+ "#{source.sync(revision, configuration[:current_path])}; " +
13
+ "else #{source.checkout(revision, configuration[:current_path])}; fi"
14
+ end
15
+
16
+ def mark
17
+ "(mkdir -p #{File.join(configuration[:releases_path], configuration[:release_name])})"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,162 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/capistrano'
3
+ require 'capistrano/fanfare'
4
+ require 'capistrano/fanfare/bundler'
5
+
6
+ #
7
+ # Rake mixes in FileUtils methods into Capistrano::Configuration::Namespace as
8
+ # private methods which will cause a method/task namespace collision when the
9
+ # `bundle:install' task is created.
10
+ #
11
+ # So, if we are in a Rake context, nuke :install in the Namespace class--we
12
+ # won't be using it directly in this codebase but this feels so very, very
13
+ # wrong (here be dragons).
14
+ #
15
+ if defined?(Rake::DSL)
16
+ Capistrano::Configuration::Namespaces::Namespace.class_eval { undef :install }
17
+ end
18
+
19
+ describe Capistrano::Fanfare::Bundler do
20
+ before do
21
+ @config = Capistrano::Configuration.new
22
+ Capistrano::Fanfare::Bundler.load_into(@config)
23
+ @config.extend(MiniTest::Capistrano::ConfigurationExtension)
24
+ @orig_config = Capistrano::Configuration.instance
25
+ Capistrano::Configuration.instance = @config
26
+
27
+ @config.set :current_release, "/srv/gemmy/releases/thisone"
28
+ end
29
+
30
+ after do
31
+ Capistrano::Configuration.instance = @orig_config
32
+ end
33
+
34
+ describe "for variables" do
35
+ it "sets :bundle_cmd to 'bundle'" do
36
+ @config.fetch(:bundle_cmd).must_equal "bundle"
37
+ end
38
+
39
+ it "sets :bundle_shebang to 'ruby-local-exec'" do
40
+ @config.fetch(:bundle_shebang).must_equal "ruby-local-exec"
41
+ end
42
+
43
+ it "add :current_path/bin to the default_environment PATH" do
44
+ @config.set :current_path, "/tmp/app/current"
45
+
46
+ @config.fetch(:default_environment)['PATH'].must_equal "/tmp/app/current/bin:$PATH"
47
+ end
48
+
49
+ it "sets :bundle_binstub_template to the binstub script" do
50
+ @config.set :bundle_shebang, "jruby"
51
+
52
+ @config.fetch(:bundle_binstub_template).must_equal <<-BINSTUB
53
+ #!/usr/bin/env jruby
54
+ #
55
+ # This file was generated by capistrano.
56
+ #
57
+
58
+ require 'pathname'
59
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
60
+ Pathname.new(__FILE__).realpath)
61
+
62
+ require 'rubygems'
63
+
64
+ load Gem.bin_path('bundler', 'bundle')
65
+ BINSTUB
66
+ end
67
+
68
+ it "sets :rake to 'rake'" do
69
+ @config.fetch(:rake).must_equal "rake"
70
+ end
71
+
72
+ describe ":bundle_flags" do
73
+ after do
74
+ ENV.delete('VERBOSE')
75
+ end
76
+
77
+ it "contains --deployment" do
78
+ @config.fetch(:bundle_flags).must_match /--deployment/
79
+ end
80
+
81
+ it "contains --binstubs" do
82
+ @config.fetch(:bundle_flags).must_match /--binstubs/
83
+ end
84
+
85
+ it "contains --shebang <shebang_bin>" do
86
+ @config.set :bundle_shebang, "bangbang"
87
+
88
+ @config.fetch(:bundle_flags).must_match /--shebang bangbang/
89
+ end
90
+
91
+ it "contains --quiet by default" do
92
+ @config.fetch(:bundle_flags).must_match /--quiet/
93
+ end
94
+
95
+ it "does not contain --quiet if ENV['VERSBOSE'] is set" do
96
+ ENV['VERBOSE'] = "yes"
97
+
98
+ @config.fetch(:bundle_flags).wont_match /--quiet/
99
+ end
100
+ end
101
+
102
+ describe ":bundle_without" do
103
+ it "contains :development and :test groups" do
104
+ @config.fetch(:bundle_without).must_include :development
105
+ @config.fetch(:bundle_without).must_include :test
106
+ end
107
+
108
+ it "contains all other values from :os_types if the :os_type variable exists" do
109
+ @config.set :os_types, [:fizz, :buzz, :rocketships]
110
+ @config.set :os_type, :rocketshipos
111
+
112
+ @config.fetch(:bundle_without).must_include :fizz
113
+ @config.fetch(:bundle_without).must_include :buzz
114
+ @config.fetch(:bundle_without).must_include :development
115
+ @config.fetch(:bundle_without).must_include :test
116
+ end
117
+ end
118
+ end
119
+
120
+ describe "for namespace :bundle" do
121
+ it "creates a bundle:install task" do
122
+ @config.must_have_task "bundle:install"
123
+ end
124
+
125
+ it "calls bundle:install task after deploy:finalize_update" do
126
+ @config.must_have_callback_after "deploy:finalize_update", "bundle:install"
127
+ end
128
+
129
+ describe "task :create_binstub_script" do
130
+ it "creates bin/bundle binstub script" do
131
+ @config.set :shared_path, "/tmp/app/shared"
132
+ @config.set :bundle_binstub_template, "thescript"
133
+ @config.find_and_execute_task("bundle:create_binstub_script")
134
+
135
+ @config.must_have_run "mkdir -p /tmp/app/shared/bin"
136
+ @config.must_have_put "/tmp/app/shared/bin/bundle", "thescript"
137
+ end
138
+
139
+ it "gets called after deploy:setup task" do
140
+ @config.must_have_callback_after "deploy:setup", "bundle:create_binstub_script"
141
+ end
142
+ end
143
+
144
+ describe "task :cp_bundle_binstub" do
145
+ it "copies bin/bundle into current_path" do
146
+ @config.set :shared_path, "/tmp/app/shared"
147
+ @config.set :current_path, "/tmp/app/current"
148
+ @config.find_and_execute_task("bundle:cp_bundle_binstub")
149
+
150
+ @config.must_have_run [
151
+ "mkdir -p /tmp/app/current/bin",
152
+ "cp /tmp/app/shared/bin/bundle /tmp/app/current/bin/bundle",
153
+ "chmod 0755 /tmp/app/current/bin/bundle"
154
+ ].join(" && ")
155
+ end
156
+
157
+ it "gets called after deploy:update_code task" do
158
+ @config.must_have_callback_before "deploy:finalize_update", "bundle:cp_bundle_binstub"
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,177 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/capistrano'
3
+ require 'capistrano/fanfare'
4
+ require 'capistrano/fanfare/defaults'
5
+
6
+ describe Capistrano::Fanfare::Defaults do
7
+ before do
8
+ @config = Capistrano::Configuration.new
9
+ Capistrano::Fanfare::Defaults.load_into(@config)
10
+ @config.extend(MiniTest::Capistrano::ConfigurationExtension)
11
+ ENV['BRANCH'] = nil
12
+ end
13
+
14
+ it "sets :scm to :git" do
15
+ @config.fetch(:scm).must_equal :git
16
+ end
17
+
18
+ it "sets :use_sudo to false" do
19
+ @config.fetch(:use_sudo).must_equal false
20
+ end
21
+
22
+ it "sets :user to 'deploy'" do
23
+ @config.fetch(:user).must_equal "deploy"
24
+ end
25
+
26
+ it "sets :rake to 'bundle exec rake'" do
27
+ @config.fetch(:rake).must_equal "bundle exec rake"
28
+ end
29
+
30
+ it "sets :ssh_options to include :forward_agent => true" do
31
+ @config.fetch(:ssh_options)[:forward_agent].must_equal true
32
+ end
33
+
34
+ it "sets :deploy_to to a directory containing :application and :deploy_env" do
35
+ @config.set :application, "fizzy"
36
+ @config.set :deploy_env, "staging"
37
+
38
+ @config.fetch(:deploy_to).must_equal "/srv/fizzy_staging"
39
+ end
40
+
41
+ describe ":branch" do
42
+ it "sets to master by default" do
43
+ @config.fetch(:branch).must_equal "master"
44
+ end
45
+
46
+ it "sets to ENV['BRANCH'] if set" do
47
+ ENV['BRANCH'] = "tree-branch"
48
+
49
+ @config.fetch(:branch).must_equal "tree-branch"
50
+ end
51
+ end
52
+
53
+ describe ":deploy_env" do
54
+ before do
55
+ @config.set :stage, "stage_env"
56
+ @config.set :rails_env, "railsy_baby"
57
+ @config.set :rack_env, "rackish_dude"
58
+
59
+ ENV['RAILS_ENV'] = "rails_env_hash"
60
+ ENV['RACK_ENV'] = "rack_env_hash"
61
+ end
62
+
63
+ after do
64
+ ENV.delete 'RAILS_ENV'
65
+ ENV.delete 'RACK_ENV'
66
+ end
67
+
68
+ it "sets to :stage if it exists" do
69
+ @config.fetch(:deploy_env).must_equal "stage_env"
70
+ end
71
+
72
+ it "set to :rails_env if :stage isn't present" do
73
+ @config.unset :stage
74
+
75
+ @config.fetch(:deploy_env).must_equal "railsy_baby"
76
+ end
77
+
78
+ it "set to ENV['RAILS_ENV'] if :stage and :rails_env arent't present" do
79
+ @config.unset :stage
80
+ @config.unset :rails_env
81
+
82
+ @config.fetch(:deploy_env).must_equal "rails_env_hash"
83
+ end
84
+
85
+ it "set to :rack_env if :stage, :rails_env, and ENV['RAILS_ENV'] arent't present" do
86
+ @config.unset :stage
87
+ @config.unset :rails_env
88
+ ENV.delete 'RAILS_ENV'
89
+
90
+ @config.fetch(:deploy_env).must_equal "rackish_dude"
91
+ end
92
+
93
+ it "set to ENV['RACK_ENV'] if :stage, :rails_env, ENV['RAILS_ENV'], and :rack_env arent't present" do
94
+ @config.unset :stage
95
+ @config.unset :rails_env
96
+ @config.unset :rack_env
97
+ ENV.delete 'RAILS_ENV'
98
+
99
+ @config.fetch(:deploy_env).must_equal "rack_env_hash"
100
+ end
101
+
102
+ it "set to 'production' as a fallback" do
103
+ @config.unset :stage
104
+ @config.unset :rails_env
105
+ @config.unset :rack_env
106
+ ENV.delete 'RAILS_ENV'
107
+ ENV.delete 'RACK_ENV'
108
+
109
+ @config.fetch(:deploy_env).must_equal "production"
110
+ end
111
+ end
112
+
113
+ it "sets :pty = true for default_run_options" do
114
+ @config.default_run_options[:pty].must_equal true
115
+ end
116
+
117
+ it "sets :os_types to a list of OSes" do
118
+ @config.fetch(:os_types).must_equal [:darwin, :linux, :sunos]
119
+ end
120
+
121
+ describe ":os_type" do
122
+ it "set to :darwin for Mac OS" do
123
+ @config.captures_responses["uname -s"] = "Darwin\n"
124
+
125
+ @config.fetch(:os_type).must_equal :darwin
126
+ end
127
+
128
+ it "set to :linunx for Linux-based OSes" do
129
+ @config.captures_responses["uname -s"] = "Linux\n"
130
+
131
+ @config.fetch(:os_type).must_equal :linux
132
+ end
133
+
134
+ it "set to :sunos for Solaris-based OSes" do
135
+ @config.captures_responses["uname -s"] = "SunOS\n"
136
+
137
+ @config.fetch(:os_type).must_equal :sunos
138
+ end
139
+ end
140
+
141
+ it "sets :shared_children to include tmp/sockets and tmp/sessions" do
142
+ @config.fetch(:shared_children).
143
+ must_equal %w{public/system log tmp/pids tmp/sockets tmp/sessions}
144
+ end
145
+
146
+ describe "for :deploy namespace" do
147
+ describe "task :cold" do
148
+ before do
149
+ @config.load do
150
+ def methods_called ; @methods_called ||= [] ; end
151
+
152
+ namespace :deploy do
153
+ task(:update) { methods_called << "deploy:update" }
154
+ task(:migrate) { methods_called << "deploy:migrate" }
155
+ task(:start) { methods_called << "deploy:start" }
156
+ end
157
+ end
158
+ end
159
+
160
+ it "calls same tasks as delivered gem code" do
161
+ @config.find_and_execute_task("deploy:cold")
162
+
163
+ @config.methods_called.must_equal(
164
+ ["deploy:update", "deploy:migrate", "deploy:start"])
165
+ end
166
+
167
+ it "calls db:seed if the task exists" do
168
+ @config.namespace :db do
169
+ task(:seed) { methods_called << "db:seed" }
170
+ end
171
+ @config.find_and_execute_task("deploy:cold")
172
+
173
+ @config.methods_called.must_include "db:seed"
174
+ end
175
+ end
176
+ end
177
+ end