recap 0.2.0 → 1.0.0
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.
- 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