recap 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/README.md +55 -10
- data/Rakefile +19 -5
- data/bin/recap +2 -2
- data/features/managing-processes.feature +1 -1
- data/features/setting-environment-variables.feature +26 -1
- data/features/steps/capistrano_steps.rb +10 -6
- data/features/support/project.rb +24 -5
- data/features/templates/project/Capfile.erb +1 -1
- data/lib/recap/recipes/rails.rb +6 -0
- data/lib/recap/recipes/ruby.rb +11 -0
- data/lib/recap/recipes/static.rb +3 -0
- data/lib/recap/recipes.rb +18 -0
- data/lib/recap/support/capistrano_extensions.rb +85 -0
- data/lib/recap/support/cli.rb +57 -0
- data/lib/recap/{compatibility.rb → support/compatibility.rb} +2 -2
- data/lib/recap/support/environment.rb +61 -0
- data/lib/recap/support/namespace.rb +47 -0
- data/lib/recap/support/shell_command.rb +35 -0
- data/lib/recap/support/templates/Capfile.erb +6 -0
- data/lib/recap/tasks/bootstrap.rb +77 -0
- data/lib/recap/{bundler.rb → tasks/bundler.rb} +15 -6
- data/lib/recap/{deploy.rb → tasks/deploy.rb} +30 -17
- data/lib/recap/tasks/env.rb +111 -0
- data/lib/recap/{foreman.rb → tasks/foreman.rb} +20 -12
- data/lib/recap/{preflight.rb → tasks/preflight.rb} +13 -11
- data/lib/recap/tasks/rails.rb +42 -0
- data/lib/recap/tasks.rb +16 -0
- data/lib/recap/version.rb +1 -1
- data/lib/recap.rb +119 -10
- data/recap.gemspec +3 -2
- data/spec/models/capistrano_extensions_spec.rb +41 -0
- data/spec/models/cli_spec.rb +25 -0
- data/spec/models/environment_spec.rb +14 -14
- data/spec/models/shell_command_spec.rb +55 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/tasks/bootstrap_spec.rb +9 -13
- data/spec/tasks/bundler_spec.rb +39 -7
- data/spec/tasks/deploy_spec.rb +42 -26
- data/spec/tasks/env_spec.rb +81 -5
- data/spec/tasks/foreman_spec.rb +10 -5
- data/spec/tasks/rails_spec.rb +80 -0
- metadata +65 -57
- data/doc/index.html +0 -235
- data/doc/lib/recap/bootstrap.html +0 -42
- data/doc/lib/recap/bundler.html +0 -168
- data/doc/lib/recap/capistrano_extensions.html +0 -208
- data/doc/lib/recap/cli.html +0 -42
- data/doc/lib/recap/compatibility.html +0 -73
- data/doc/lib/recap/deploy.html +0 -328
- data/doc/lib/recap/env.html +0 -108
- data/doc/lib/recap/foreman.html +0 -42
- data/doc/lib/recap/namespace.html +0 -42
- data/doc/lib/recap/preflight.html +0 -163
- data/doc/lib/recap/rails.html +0 -42
- data/doc/lib/recap/version.html +0 -42
- data/doc/lib/recap.html +0 -42
- data/index.rb +0 -62
- data/lib/recap/bootstrap.rb +0 -47
- data/lib/recap/capistrano_extensions.rb +0 -74
- data/lib/recap/cli.rb +0 -32
- data/lib/recap/deploy/templates/Capfile.erb +0 -6
- data/lib/recap/env.rb +0 -58
- data/lib/recap/environment.rb +0 -54
- data/lib/recap/namespace.rb +0 -37
- data/lib/recap/rails.rb +0 -24
- data/lib/recap/ruby.rb +0 -3
- data/lib/recap/static.rb +0 -1
@@ -0,0 +1,77 @@
|
|
1
|
+
# Recap has a number of requirements on your server before you can deploy applications
|
2
|
+
# with it. These include:
|
3
|
+
#
|
4
|
+
# - Each application needs its own account on the server. The full account environment
|
5
|
+
# is loaded whenever an application command or process is run, so this is the place where
|
6
|
+
# other application specific configuration should happen.
|
7
|
+
# - Each deploying user needs a personal account on the server which they should be able to
|
8
|
+
# ssh into.
|
9
|
+
# - This personal account needs to be able to `sudo`, both to switch to the application user
|
10
|
+
# and to run other administrative commands.
|
11
|
+
|
12
|
+
require 'recap/tasks'
|
13
|
+
|
14
|
+
module Recap::Tasks::Bootstrap
|
15
|
+
extend Recap::Support::Namespace
|
16
|
+
|
17
|
+
# The bootstrap namespace has a couple of task that help configure application and personal accounts
|
18
|
+
# and personal accounts to meet these requirements.
|
19
|
+
namespace :bootstrap do
|
20
|
+
set(:remote_username) { capture('whoami').strip }
|
21
|
+
set(:application_home) { "/home/#{application_user}"}
|
22
|
+
|
23
|
+
# The `bootstrap:application` task sets up the account on the server the application itself uses. This
|
24
|
+
# account should be dedicated to running this application.
|
25
|
+
desc 'Sets up the server account used by the application, including home directory and environment support'
|
26
|
+
task :application do
|
27
|
+
# If the account doesn't already exist on the server, the task creates it.
|
28
|
+
if exit_code("id #{application_user}").strip != "0"
|
29
|
+
sudo "useradd #{application_user} -d #{application_home}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# If the home directory doesn't exist, or isn't both readable and writable by members of the application
|
33
|
+
# group (all the accounts allowed to deploy the app) then the task creates the directory and fixes
|
34
|
+
# file permissions.
|
35
|
+
sudo "mkdir -p #{application_home}"
|
36
|
+
sudo "chown #{application_user}:#{application_group} #{application_home}"
|
37
|
+
sudo "chmod 755 #{application_home}"
|
38
|
+
|
39
|
+
# A script `.recap` is added to set the configuration environment (set with `env:set` and
|
40
|
+
# `env:edit` tasks). The script loads the `.env` file in the users home folder, creates
|
41
|
+
# a new copy with `export ` prefixed to each line, and sources this new copy.
|
42
|
+
put_as_app %{
|
43
|
+
if [ -s "$HOME/.env" ]; then
|
44
|
+
sed -e 's/\\r//g' -e 's/^/export /g' .env > .recap-env-export
|
45
|
+
. $HOME/.recap-env-export
|
46
|
+
fi
|
47
|
+
}, "#{application_home}/.recap"
|
48
|
+
|
49
|
+
# Finally, `.profile` needs to source the `.recap` script, so that the configuration environment is
|
50
|
+
# available whenever the environment is loaded.
|
51
|
+
as_app "touch .profile", "~"
|
52
|
+
|
53
|
+
if exit_code("grep '\\. $HOME/\\.recap' #{application_home}/.profile") != "0"
|
54
|
+
as_app %{echo ". \\$HOME/.recap" >> .profile}, "~"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# The `bootstrap:user` task sets up the personal accounts of user who can deploy applications.
|
59
|
+
# In order to deploy a particular app, the account's git configuration must be set (so
|
60
|
+
# that releases can be tagged), and the account must be a member of the application group.
|
61
|
+
desc 'Sets up the server account used by a deploying user'
|
62
|
+
task :user do
|
63
|
+
git_user_name = Recap::Support::ShellCommand.execute("git config user.name").strip
|
64
|
+
git_user_email = Recap::Support::ShellCommand.execute("git config user.email").strip
|
65
|
+
run "git config --global user.name '#{git_user_name}'"
|
66
|
+
run "git config --global user.email '#{git_user_email}'"
|
67
|
+
sudo "usermod --append -G #{application_group} #{remote_username}"
|
68
|
+
end
|
69
|
+
|
70
|
+
# The `bootstrap` task simply runs both the `bootstrap:application` and `bootstrap:user` tasks
|
71
|
+
# in turn.
|
72
|
+
task :default do
|
73
|
+
application
|
74
|
+
user
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# The bundler recipe ensures that the application bundle is installed whenever the code is updated.
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
require 'recap/tasks'
|
4
|
+
|
5
|
+
module Recap::Tasks::Bundler
|
6
|
+
extend Recap::Support::Namespace
|
5
7
|
|
6
8
|
namespace :bundle do
|
7
|
-
# Each bundle is declared in a `Gemfile`, by default in the root of the application directory
|
9
|
+
# Each bundle is declared in a `Gemfile`, by default in the root of the application directory.
|
8
10
|
set(:bundle_gemfile) { "#{deploy_to}/Gemfile" }
|
9
11
|
|
10
12
|
# As well as a `Gemfile`, application repositories should also contain a `Gemfile.lock`.
|
@@ -16,7 +18,7 @@ module Recap::Bundler
|
|
16
18
|
|
17
19
|
# Not all gems are needed for production environments, so by default the `development`, `test` and
|
18
20
|
# `assets` groups are skipped.
|
19
|
-
set(:bundle_without) { "development test
|
21
|
+
set(:bundle_without) { "development test" }
|
20
22
|
|
21
23
|
# The main bundle install command uses all the settings above, together with the `--deployment`,
|
22
24
|
# `--binstubs` and `--quiet` flags
|
@@ -32,7 +34,7 @@ module Recap::Bundler
|
|
32
34
|
end
|
33
35
|
|
34
36
|
# Occassionally it's useful to force an install (such as if something has gone wrong in
|
35
|
-
# a previous deployment)
|
37
|
+
# a previous deployment).
|
36
38
|
desc "Install the latest gem bundle"
|
37
39
|
task :default do
|
38
40
|
if deployed_file_exists?(bundle_gemfile)
|
@@ -47,9 +49,16 @@ module Recap::Bundler
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
52
|
+
task :check_installed do
|
53
|
+
if exit_code_as_app('bundle --version', '.') != "0"
|
54
|
+
abort "The application user '#{application_user}' cannot execute `bundle`. Please check you have bundler installed."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
after 'preflight:check', 'bundle:check_installed'
|
58
|
+
|
50
59
|
# To install the bundle automatically each time the code is updated or cloned, hooks are added to
|
51
60
|
# the `deploy:clone_code` and `deploy:update_code` tasks.
|
52
61
|
after 'deploy:clone_code', 'bundle:install:if_changed'
|
53
62
|
after 'deploy:update_code', 'bundle:install:if_changed'
|
54
63
|
end
|
55
|
-
end
|
64
|
+
end
|
@@ -1,19 +1,26 @@
|
|
1
|
-
|
2
|
-
require 'recap/capistrano_extensions'
|
1
|
+
# These tasks provide the basic mechanism getting new code onto servers using git.
|
3
2
|
|
4
|
-
require 'recap/
|
5
|
-
require 'recap/
|
6
|
-
require 'recap/env'
|
3
|
+
require 'recap/tasks'
|
4
|
+
require 'recap/support/capistrano_extensions'
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
# These deployment tasks are designed to work alongside the tasks for
|
7
|
+
# [altering environment variables](env.html), as well as the
|
8
|
+
# [preflight checks](preflight.html) and
|
9
|
+
# [bootstrap tasks](bootstrap.html).
|
10
|
+
|
11
|
+
require 'recap/tasks/env'
|
12
|
+
require 'recap/tasks/preflight'
|
13
|
+
require 'recap/tasks/bootstrap'
|
14
|
+
|
15
|
+
module Recap::Tasks::Deploy
|
16
|
+
extend Recap::Support::Namespace
|
10
17
|
|
11
18
|
namespace :deploy do
|
12
19
|
# To use this recipe, both the application's name and its git repository are required.
|
13
20
|
set(:application) { abort "You must set the name of your application in your Capfile, e.g.: set :application, 'tomafro.net'" }
|
14
|
-
set(:repository) { abort "You must set the git respository location in your Capfile, e.g.: set :respository, 'git@github.com/tomafro/tomafro.net'"}
|
21
|
+
set(:repository) { abort "You must set the git respository location in your Capfile, e.g.: set :respository, 'git@github.com/tomafro/tomafro.net'" }
|
15
22
|
|
16
|
-
# The recipe assumes that the application code will be run as a dedicated user. Any
|
23
|
+
# The recipe assumes that the application code will be run as a dedicated user. Any user who
|
17
24
|
# can deploy the application should be added as a member of the application's group. By default,
|
18
25
|
# both the application user and group take the same name as the application.
|
19
26
|
set(:application_user) { application }
|
@@ -23,8 +30,8 @@ module Recap::Deploy
|
|
23
30
|
set(:branch, 'master')
|
24
31
|
|
25
32
|
# Unlike a standard capistrano deployment, all releases are stored directly in the `deploy_to`
|
26
|
-
# directory. The default is `/home/#{application_user}/
|
27
|
-
set(:deploy_to) { "/home/#{application_user}/
|
33
|
+
# directory. The default is `/home/#{application_user}/app`.
|
34
|
+
set(:deploy_to) { "/home/#{application_user}/app" }
|
28
35
|
|
29
36
|
# Each release is marked by a unique tag, generated with the current timestamp. While this can be
|
30
37
|
# changed, it's not recommended, as the sort order of the tag names is important; later tags must
|
@@ -47,16 +54,21 @@ module Recap::Deploy
|
|
47
54
|
# `:pty` is set to `true`.
|
48
55
|
default_run_options[:pty] = true
|
49
56
|
|
50
|
-
# The `deploy:setup` task prepares all the servers for the deployment.
|
57
|
+
# The `deploy:setup` task prepares all the servers for the deployment. It ensures the `env`
|
58
|
+
# has been set, and clones the code.
|
51
59
|
desc "Prepare servers for deployment"
|
52
60
|
task :setup, :except => {:no_release => true} do
|
53
61
|
transaction do
|
62
|
+
top.env.set
|
54
63
|
clone_code
|
55
64
|
end
|
56
65
|
end
|
57
66
|
|
58
|
-
#
|
67
|
+
# The `deploy:clone_code` task clones the project repository into the `deploy_to` location
|
68
|
+
# and ensures it has the correct file permissions. It shouldn't be necessary to call this
|
69
|
+
# task manually as it is run as part of `deploy:setup`.
|
59
70
|
task :clone_code, :except => {:no_release => true} do
|
71
|
+
on_rollback { as_app "rm -fr #{deploy_to}" }
|
60
72
|
# Before cloning, the directory needs to exist and be both readable and writable by the application group
|
61
73
|
as_app "mkdir -p #{deploy_to}", "~"
|
62
74
|
as_app "chmod g+rw #{deploy_to}"
|
@@ -64,11 +76,12 @@ module Recap::Deploy
|
|
64
76
|
git "clone #{repository} ."
|
65
77
|
end
|
66
78
|
|
67
|
-
# The
|
68
|
-
#
|
79
|
+
# The `deploy` task ensures the environment is set, updates the application code,
|
80
|
+
# tags the release and restarts the application.
|
69
81
|
desc "Deploy the latest application code"
|
70
82
|
task :default do
|
71
83
|
transaction do
|
84
|
+
top.env.set
|
72
85
|
update_code
|
73
86
|
tag
|
74
87
|
end
|
@@ -111,8 +124,8 @@ module Recap::Deploy
|
|
111
124
|
end
|
112
125
|
end
|
113
126
|
|
114
|
-
#
|
115
|
-
# previously deployed files
|
127
|
+
# The `destroy` task can be used in an emergency or when manually testing deployment. It removes
|
128
|
+
# all previously deployed files, leaving a blank slate to run `deploy:setup` on.
|
116
129
|
desc "Remove all deployed files"
|
117
130
|
task :destroy do
|
118
131
|
sudo "rm -rf #{deploy_to}"
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# Recap encourages the storage of application configuration (such as database passwords, S3 keys and
|
2
|
+
# other things that change between deploys) in environment variables.
|
3
|
+
# [12factor.net](http://www.12factor.net) has [http://www.12factor.net/config](a good set of reasons
|
4
|
+
# why this is desirable).
|
5
|
+
#
|
6
|
+
# To enable this, [recap](https://github.com/freerange/recap) stores these configuration variables
|
7
|
+
# in `.env`, and adds a script to the user's `.profile` to set these whenever the environment is
|
8
|
+
# loaded (see [bootstrap](bootstrap.html)).
|
9
|
+
#
|
10
|
+
# Variables can be set in two ways. First, using either the `env:set` or `env:edit` tasks,
|
11
|
+
# the `.env` file can be directly manipulated. This is generally the best way to manipulate
|
12
|
+
# these values.
|
13
|
+
#
|
14
|
+
# The other way to set them is using the `set_default_env` method directly in your `Capfile`.
|
15
|
+
# This sets a default value, which will be used if no other value is set. An example where
|
16
|
+
# this might be useful is where you know your app should run using ruby 1.8.7. Using
|
17
|
+
# `set_default_env :RBENV_VERSION, "1.8.7-p352"` in your `Capfile` will use this ruby as the default.
|
18
|
+
# Then, in a different deployment you might want to test using a different version of ruby,
|
19
|
+
# so could use `cap env:set RBENV_VERSION=1.9.3-p0` to override the default.
|
20
|
+
|
21
|
+
require 'recap/tasks'
|
22
|
+
|
23
|
+
module Recap::Tasks::Env
|
24
|
+
extend Recap::Support::Namespace
|
25
|
+
|
26
|
+
namespace :env do
|
27
|
+
set(:environment_file) { "/home/#{application_user}/.env" }
|
28
|
+
|
29
|
+
# The `env` task displays the current configuration environment. Note that this doesn't
|
30
|
+
# include all environment variables, only those stored in the `.env` file.
|
31
|
+
desc 'View the current server environment'
|
32
|
+
task :default do
|
33
|
+
if current_environment.empty?
|
34
|
+
puts "There are no config variables set"
|
35
|
+
else
|
36
|
+
puts "The config variables are:"
|
37
|
+
puts
|
38
|
+
puts current_environment
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# A single variable can be set using the `env:set` task, followed by a variable and value,
|
43
|
+
# for example `cap env:set VARIABLE=VALUE`. Variables can be unset using `cap env:set VARIABLE=`.
|
44
|
+
desc 'Set a variable in the environment, using "cap env:set VARIABLE=VALUE". Unset using "cap env:set VARIABLE="'
|
45
|
+
task :set do
|
46
|
+
env = env_argv.inject(current_environment) do |env, string|
|
47
|
+
env.set_string(string)
|
48
|
+
logger.debug "Setting #{string}"
|
49
|
+
logger.debug "Env is now: #{env}"
|
50
|
+
env
|
51
|
+
end
|
52
|
+
update_remote_environment(env)
|
53
|
+
default
|
54
|
+
end
|
55
|
+
|
56
|
+
# The `env:edit` task uses your EDITOR to load the `.env` file locally, saving any changes
|
57
|
+
# to all servers.
|
58
|
+
desc 'Edit the server environment'
|
59
|
+
task :edit do
|
60
|
+
content = edit_file environment_file
|
61
|
+
env = Recap::Support::Environment.from_string(content)
|
62
|
+
update_remote_environment(env)
|
63
|
+
default
|
64
|
+
end
|
65
|
+
|
66
|
+
# The `env:reset` tasks reverts all variables back to their default values. If there is no default value,
|
67
|
+
# the variable will be removed.
|
68
|
+
desc 'Reset the server environment to its default values'
|
69
|
+
task :reset do
|
70
|
+
as_app "rm -f #{environment_file}", "~"
|
71
|
+
set
|
72
|
+
end
|
73
|
+
|
74
|
+
def current_environment
|
75
|
+
@current_environment ||= begin
|
76
|
+
if deployed_file_exists?(environment_file, '.')
|
77
|
+
Recap::Support::Environment.from_string(capture("cat #{environment_file}"))
|
78
|
+
else
|
79
|
+
Recap::Support::Environment.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_remote_environment(env)
|
85
|
+
logger.debug "Env is now #{env}"
|
86
|
+
|
87
|
+
default_env.each do |name, value|
|
88
|
+
env.set(name, value) unless env.get(name)
|
89
|
+
end
|
90
|
+
|
91
|
+
if env.empty?
|
92
|
+
as_app "rm -f #{environment_file}", "~"
|
93
|
+
else
|
94
|
+
put_as_app env.to_s, environment_file
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Default environment values can be set by a recipe using `set_default_env :NAME, 'VALUE'`.
|
100
|
+
def set_default_env(name, value)
|
101
|
+
default_env[name] = value
|
102
|
+
end
|
103
|
+
|
104
|
+
def default_env
|
105
|
+
@default_env ||= {}
|
106
|
+
end
|
107
|
+
|
108
|
+
def env_argv
|
109
|
+
ARGV[1..-1]
|
110
|
+
end
|
111
|
+
end
|
@@ -1,24 +1,28 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# These tasks configure recap to use Foreman to stop, start and restart your application processes.
|
2
|
+
|
3
|
+
require 'recap/tasks'
|
4
|
+
|
5
|
+
module Recap::Tasks::Foreman
|
6
|
+
extend Recap::Support::Namespace
|
3
7
|
|
4
8
|
namespace :foreman do
|
5
|
-
# Processes are
|
9
|
+
# Processes are declared in a `Procfile`, by default in the root of the application directory.
|
6
10
|
set(:procfile) { "#{deploy_to}/Procfile" }
|
7
11
|
|
8
|
-
# Foreman startup scripts are exported in `upstart` format by default
|
12
|
+
# Foreman startup scripts are exported in `upstart` format by default.
|
9
13
|
set(:foreman_export_format, "upstart")
|
10
14
|
|
11
|
-
# Scripts are exported (as the the application user) to a temporary location first
|
15
|
+
# Scripts are exported (as the the application user) to a temporary location first.
|
12
16
|
set(:foreman_tmp_location) { "#{deploy_to}/tmp/foreman" }
|
13
17
|
|
14
|
-
# After exports, the scripts are moved to their final location, usually `/etc/init
|
18
|
+
# After exports, the scripts are moved to their final location, usually `/etc/init`.
|
15
19
|
set(:foreman_export_location, "/etc/init")
|
16
20
|
|
17
|
-
# The standard foreman export
|
21
|
+
# The standard foreman export.
|
18
22
|
set(:foreman_export_command) { "./bin/foreman export #{foreman_export_format} #{foreman_tmp_location} --procfile #{procfile} --app #{application} --user #{application_user} --log #{deploy_to}/log" }
|
19
23
|
|
20
24
|
namespace :export do
|
21
|
-
# After each deployment, the startup scripts are exported if the `Procfile` has changed
|
25
|
+
# After each deployment, the startup scripts are exported if the `Procfile` has changed.
|
22
26
|
task :if_changed do
|
23
27
|
if deployed_file_changed?(procfile)
|
24
28
|
top.foreman.export.default
|
@@ -28,6 +32,7 @@ module Recap::Foreman
|
|
28
32
|
# To export the scripts, they are first generated in a temporary location, then copied to their final
|
29
33
|
# destination. This is done because the foreman export command needs to be run as the application user,
|
30
34
|
# while sudo is required to write to `/etc/init`.
|
35
|
+
desc 'Export foreman configuration'
|
31
36
|
task :default do
|
32
37
|
if deployed_file_exists?(procfile)
|
33
38
|
as_app foreman_export_command
|
@@ -37,21 +42,24 @@ module Recap::Foreman
|
|
37
42
|
end
|
38
43
|
end
|
39
44
|
|
40
|
-
# Starts all processes that form the application
|
45
|
+
# Starts all processes that form the application.
|
46
|
+
desc 'Start all application processes'
|
41
47
|
task :start do
|
42
48
|
if deployed_file_exists?(procfile)
|
43
49
|
sudo "start #{application}"
|
44
50
|
end
|
45
51
|
end
|
46
52
|
|
47
|
-
# Restarts all processes that form the application
|
53
|
+
# Restarts all processes that form the application.
|
54
|
+
desc 'Restart all application processes'
|
48
55
|
task :restart do
|
49
56
|
if deployed_file_exists?(procfile)
|
50
57
|
sudo "restart #{application} || sudo start #{application}"
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
54
|
-
# Stops all processes that form the application
|
61
|
+
# Stops all processes that form the application.
|
62
|
+
desc 'Stop all application processes'
|
55
63
|
task :stop do
|
56
64
|
if deployed_file_exists?(procfile)
|
57
65
|
sudo "stop #{application}"
|
@@ -61,4 +69,4 @@ module Recap::Foreman
|
|
61
69
|
after 'deploy:update_code', 'foreman:export:if_changed'
|
62
70
|
after 'deploy:restart', 'foreman:restart'
|
63
71
|
end
|
64
|
-
end
|
72
|
+
end
|
@@ -17,50 +17,52 @@
|
|
17
17
|
# This preflight recipe checks each of these things in turn, and attempts to give helpful advice
|
18
18
|
# should a check fail.
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
require 'recap/tasks'
|
21
|
+
|
22
|
+
module Recap::Tasks::Preflight
|
23
|
+
extend Recap::Support::Namespace
|
22
24
|
|
23
25
|
namespace :preflight do
|
24
|
-
# The preflight check is pretty quick, so run it before every `deploy:setup` and `deploy
|
26
|
+
# The preflight check is pretty quick, so run it before every `deploy:setup` and `deploy`.
|
25
27
|
before 'deploy:setup', 'preflight:check'
|
26
28
|
before 'deploy', 'preflight:check'
|
27
29
|
|
28
30
|
set(:remote_username) { capture('whoami').strip }
|
29
31
|
|
30
32
|
task :check do
|
31
|
-
# First check the `application_user` exists
|
33
|
+
# First check the `application_user` exists.
|
32
34
|
if exit_code("id #{application_user}").strip != "0"
|
33
35
|
abort %{
|
34
|
-
The application user '#{application_user}' doesn't exist. You can create this user by logging into the server and running:
|
36
|
+
The application user '#{application_user}' doesn't exist. Did you run the `bootstrap` task? You can also create this user by logging into the server and running:
|
35
37
|
|
36
38
|
sudo useradd #{application_user}
|
37
39
|
\n}
|
38
40
|
end
|
39
41
|
|
40
|
-
# Then the `application_group
|
42
|
+
# Then the `application_group`.
|
41
43
|
if exit_code("id -g #{application_group}") != "0"
|
42
44
|
abort %{
|
43
|
-
The application group '#{application_group}' doesn't exist. You can create this group by logging into the server and running:
|
45
|
+
The application group '#{application_group}' doesn't exist. Did you run the `bootstrap` task? You can also create this group by logging into the server and running:
|
44
46
|
|
45
47
|
sudo groupadd #{application_group}
|
46
48
|
sudo usermod --append -G #{application_group} #{application_user}
|
47
49
|
\n}
|
48
50
|
end
|
49
51
|
|
50
|
-
# Check the git configuration exists
|
52
|
+
# Check the git configuration exists.
|
51
53
|
if capture('git config user.name || true').strip.empty? || capture('git config user.email || true').strip.empty?
|
52
54
|
abort %{
|
53
|
-
Your remote user must have a git user.name and user.email set. You can set these by logging into the server as #{remote_username} and running:
|
55
|
+
Your remote user must have a git user.name and user.email set. Did you run the `bootstrap` task? You can also set these by logging into the server as #{remote_username} and running:
|
54
56
|
|
55
57
|
git config --global user.email "you@example.com"
|
56
58
|
git config --global user.name "Your Name"
|
57
59
|
\n}
|
58
60
|
end
|
59
61
|
|
60
|
-
# And finally check the remote user is a member of the `application_group
|
62
|
+
# And finally check the remote user is a member of the `application_group`.
|
61
63
|
unless capture('groups').split(" ").include?(application_group)
|
62
64
|
abort %{
|
63
|
-
Your remote user must be a member of the '#{application_group}' group in order to perform deployments. You can add yourself to this group by logging into the server and running:
|
65
|
+
Your remote user must be a member of the '#{application_group}' group in order to perform deployments. Did you run the `bootstrap` task? You can also add yourself to this group by logging into the server and running:
|
64
66
|
|
65
67
|
sudo usermod --append -G #{application_group} #{remote_username}
|
66
68
|
\n}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# The rails tasks add to the standard deployment with tasks to support running
|
2
|
+
# database migrations and precompiling assets.
|
3
|
+
|
4
|
+
require 'recap/tasks'
|
5
|
+
|
6
|
+
module Recap::Tasks::Rails
|
7
|
+
extend Recap::Support::Namespace
|
8
|
+
|
9
|
+
namespace :rails do
|
10
|
+
namespace :db do
|
11
|
+
task :load_schema do
|
12
|
+
if deployed_file_exists?("db/schema.rb")
|
13
|
+
as_app './bin/rake db:create db:schema:load'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task :migrate do
|
18
|
+
if deployed_file_changed?("db/schema.rb")
|
19
|
+
as_app './bin/rake db:migrate'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# The `rails:assets:precompile` runs rails' asset precompilation rake task on
|
25
|
+
# the server. As assets come from so many sources (app/assets, vendor/assets
|
26
|
+
# and from individual gems) it's not easy to determine whether compilation is
|
27
|
+
# required, so it is done on every deploy.
|
28
|
+
namespace :assets do
|
29
|
+
task :precompile do
|
30
|
+
as_app "./bin/rake RAILS_GROUPS=assets assets:precompile"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# After the code is first cloned (during `deploy:setup`) load the schema into
|
35
|
+
# the database.
|
36
|
+
after "deploy:clone_code", "rails:db:load_schema"
|
37
|
+
|
38
|
+
# On every deploy, after the code is updated, run the database migrations
|
39
|
+
# and precompile the assets.
|
40
|
+
after "deploy:update_code", "rails:db:migrate", "rails:assets:precompile"
|
41
|
+
end
|
42
|
+
end
|
data/lib/recap/tasks.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Recap provides a number of capistrano tasks to aid with deployment. The core functionality
|
2
|
+
# is found in the [tasks for deployment](tasks/deploy.html) and those for
|
3
|
+
# [altering environment variables](tasks/env.html).
|
4
|
+
#
|
5
|
+
# Supporting these are [preflight checks](tasks/preflight.html) to ensure servers and
|
6
|
+
# users are correctly setup, and the [bootstrap tasks](tasks/bootstrap.html) that help
|
7
|
+
# do this setting up.
|
8
|
+
#
|
9
|
+
# In addition, there are extensions for [bundler](tasks/bundler.html),
|
10
|
+
# [foreman](tasks/foreman.html), and [rails](tasks/rails.html) that add extra
|
11
|
+
# functionality to the standard deploy.
|
12
|
+
|
13
|
+
require 'recap'
|
14
|
+
|
15
|
+
module Recap::Tasks
|
16
|
+
end
|
data/lib/recap/version.rb
CHANGED