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
@@ -1,163 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
5
|
-
<title>preflight.rb</title>
|
6
|
-
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<div id='container'>
|
10
|
-
<div id="background"></div>
|
11
|
-
<div id="jump_to">
|
12
|
-
Jump To …
|
13
|
-
<div id="jump_wrapper">
|
14
|
-
<div id="jump_page">
|
15
|
-
<a class="source" href="../../index.html">index.rb</a>
|
16
|
-
<a class="source" href="../recap.html">recap.rb</a>
|
17
|
-
<a class="source" href="bootstrap.html">bootstrap.rb</a>
|
18
|
-
<a class="source" href="bundler.html">bundler.rb</a>
|
19
|
-
<a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
|
20
|
-
<a class="source" href="cli.html">cli.rb</a>
|
21
|
-
<a class="source" href="compatibility.html">compatibility.rb</a>
|
22
|
-
<a class="source" href="deploy.html">deploy.rb</a>
|
23
|
-
<a class="source" href="env.html">env.rb</a>
|
24
|
-
<a class="source" href="foreman.html">foreman.rb</a>
|
25
|
-
<a class="source" href="namespace.html">namespace.rb</a>
|
26
|
-
<a class="source" href="preflight.html">preflight.rb</a>
|
27
|
-
<a class="source" href="rails.html">rails.rb</a>
|
28
|
-
<a class="source" href="version.html">version.rb</a>
|
29
|
-
</div>
|
30
|
-
</div>
|
31
|
-
</div>
|
32
|
-
<table cellspacing=0 cellpadding=0>
|
33
|
-
<thead>
|
34
|
-
<tr>
|
35
|
-
<th class=docs><h1>preflight.rb</h1></th>
|
36
|
-
<th class=code></th>
|
37
|
-
</tr>
|
38
|
-
</thead>
|
39
|
-
<tbody>
|
40
|
-
<tr id='section-1'>
|
41
|
-
<td class=docs>
|
42
|
-
<div class="pilwrap">
|
43
|
-
<a class="pilcrow" href="#section-1">¶</a>
|
44
|
-
</div>
|
45
|
-
<p>Before <code>recap</code> will work correctly, a small amount of setup work needs to be performed on
|
46
|
-
all target servers.</p>
|
47
|
-
|
48
|
-
<p>First, each user who can deploy the app needs to have an account on each server, and must be able
|
49
|
-
to ssh into the box. They’ll also each need to be sudoers.</p>
|
50
|
-
|
51
|
-
<p>Secondly, each deploying user should set their git <code>user.name</code> and <code>user.email</code>. This can easily
|
52
|
-
be done by running:</p>
|
53
|
-
|
54
|
-
<p><code>git config —global user.email “you@example.com”</code>
|
55
|
-
<code>git config —global user.name “Your Name”</code></p>
|
56
|
-
|
57
|
-
<p>Finally, a user and group representing the application (and usually with the same name) should be
|
58
|
-
created. Where possible, the application user will run application code, while the group will own
|
59
|
-
application specific files. Each deploying user should be added to the application group.</p>
|
60
|
-
|
61
|
-
<p>This preflight recipe checks each of these things in turn, and attempts to give helpful advice
|
62
|
-
should a check fail.</p>
|
63
|
-
</td>
|
64
|
-
<td class=code>
|
65
|
-
<div class='highlight'><pre><span class="k">module</span> <span class="nn">Recap::Preflight</span>
|
66
|
-
<span class="kp">extend</span> <span class="no">Recap</span><span class="o">::</span><span class="no">Namespace</span>
|
67
|
-
|
68
|
-
<span class="n">namespace</span> <span class="ss">:preflight</span> <span class="k">do</span></pre></div>
|
69
|
-
</td>
|
70
|
-
</tr>
|
71
|
-
<tr id='section-2'>
|
72
|
-
<td class=docs>
|
73
|
-
<div class="pilwrap">
|
74
|
-
<a class="pilcrow" href="#section-2">¶</a>
|
75
|
-
</div>
|
76
|
-
<p>The preflight check is pretty quick, so run it before every <code>deploy:setup</code> and <code>deploy</code></p>
|
77
|
-
</td>
|
78
|
-
<td class=code>
|
79
|
-
<div class='highlight'><pre> <span class="n">before</span> <span class="s1">'deploy:setup'</span><span class="p">,</span> <span class="s1">'preflight:check'</span>
|
80
|
-
<span class="n">before</span> <span class="s1">'deploy'</span><span class="p">,</span> <span class="s1">'preflight:check'</span>
|
81
|
-
|
82
|
-
<span class="n">set</span><span class="p">(</span><span class="ss">:remote_username</span><span class="p">)</span> <span class="p">{</span> <span class="n">capture</span><span class="p">(</span><span class="s1">'whoami'</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="p">}</span>
|
83
|
-
|
84
|
-
<span class="n">task</span> <span class="ss">:check</span> <span class="k">do</span></pre></div>
|
85
|
-
</td>
|
86
|
-
</tr>
|
87
|
-
<tr id='section-3'>
|
88
|
-
<td class=docs>
|
89
|
-
<div class="pilwrap">
|
90
|
-
<a class="pilcrow" href="#section-3">¶</a>
|
91
|
-
</div>
|
92
|
-
<p>First check the <code>application_user</code> exists</p>
|
93
|
-
</td>
|
94
|
-
<td class=code>
|
95
|
-
<div class='highlight'><pre> <span class="k">if</span> <span class="n">exit_code</span><span class="p">(</span><span class="s2">"id </span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span> <span class="o">!=</span> <span class="s2">"0"</span>
|
96
|
-
<span class="nb">abort</span> <span class="sx">%{</span>
|
97
|
-
<span class="sx">The application user '</span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="sx">' doesn't exist. You can create this user by logging into the server and running:</span>
|
98
|
-
|
99
|
-
<span class="sx"> sudo useradd </span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="sx"></span>
|
100
|
-
<span class="se">\n</span><span class="sx">}</span>
|
101
|
-
<span class="k">end</span></pre></div>
|
102
|
-
</td>
|
103
|
-
</tr>
|
104
|
-
<tr id='section-4'>
|
105
|
-
<td class=docs>
|
106
|
-
<div class="pilwrap">
|
107
|
-
<a class="pilcrow" href="#section-4">¶</a>
|
108
|
-
</div>
|
109
|
-
<p>Then the <code>application_group</code></p>
|
110
|
-
</td>
|
111
|
-
<td class=code>
|
112
|
-
<div class='highlight'><pre> <span class="k">if</span> <span class="n">exit_code</span><span class="p">(</span><span class="s2">"id -g </span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="o">!=</span> <span class="s2">"0"</span>
|
113
|
-
<span class="nb">abort</span> <span class="sx">%{</span>
|
114
|
-
<span class="sx">The application group '</span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="sx">' doesn't exist. You can create this group by logging into the server and running:</span>
|
115
|
-
|
116
|
-
<span class="sx"> sudo groupadd </span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="sx"></span>
|
117
|
-
<span class="sx"> sudo usermod --append -G </span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="sx"> </span><span class="si">#{</span><span class="n">application_user</span><span class="si">}</span><span class="sx"></span>
|
118
|
-
<span class="se">\n</span><span class="sx">}</span>
|
119
|
-
<span class="k">end</span></pre></div>
|
120
|
-
</td>
|
121
|
-
</tr>
|
122
|
-
<tr id='section-5'>
|
123
|
-
<td class=docs>
|
124
|
-
<div class="pilwrap">
|
125
|
-
<a class="pilcrow" href="#section-5">¶</a>
|
126
|
-
</div>
|
127
|
-
<p>Check the git configuration exists</p>
|
128
|
-
</td>
|
129
|
-
<td class=code>
|
130
|
-
<div class='highlight'><pre> <span class="k">if</span> <span class="n">capture</span><span class="p">(</span><span class="s1">'git config user.name || true'</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="o">.</span><span class="n">empty?</span> <span class="o">||</span> <span class="n">capture</span><span class="p">(</span><span class="s1">'git config user.email || true'</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="o">.</span><span class="n">empty?</span>
|
131
|
-
<span class="nb">abort</span> <span class="sx">%{</span>
|
132
|
-
<span class="sx">Your remote user must have a git user.name and user.email set. You can set these by logging into the server as </span><span class="si">#{</span><span class="n">remote_username</span><span class="si">}</span><span class="sx"> and running:</span>
|
133
|
-
|
134
|
-
<span class="sx"> git config --global user.email "you@example.com"</span>
|
135
|
-
<span class="sx"> git config --global user.name "Your Name"</span>
|
136
|
-
<span class="se">\n</span><span class="sx">}</span>
|
137
|
-
<span class="k">end</span></pre></div>
|
138
|
-
</td>
|
139
|
-
</tr>
|
140
|
-
<tr id='section-6'>
|
141
|
-
<td class=docs>
|
142
|
-
<div class="pilwrap">
|
143
|
-
<a class="pilcrow" href="#section-6">¶</a>
|
144
|
-
</div>
|
145
|
-
<p>And finally check the remote user is a member of the <code>application_group</code></p>
|
146
|
-
|
147
|
-
</td>
|
148
|
-
<td class=code>
|
149
|
-
<div class='highlight'><pre> <span class="k">unless</span> <span class="n">capture</span><span class="p">(</span><span class="s1">'groups'</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" "</span><span class="p">)</span><span class="o">.</span><span class="n">include?</span><span class="p">(</span><span class="n">application_group</span><span class="p">)</span>
|
150
|
-
<span class="nb">abort</span> <span class="sx">%{</span>
|
151
|
-
<span class="sx">Your remote user must be a member of the '</span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="sx">' group in order to perform deployments. You can add yourself to this group by logging into the server and running:</span>
|
152
|
-
|
153
|
-
<span class="sx"> sudo usermod --append -G </span><span class="si">#{</span><span class="n">application_group</span><span class="si">}</span><span class="sx"> </span><span class="si">#{</span><span class="n">remote_username</span><span class="si">}</span><span class="sx"></span>
|
154
|
-
<span class="se">\n</span><span class="sx">}</span>
|
155
|
-
<span class="k">end</span>
|
156
|
-
<span class="k">end</span>
|
157
|
-
<span class="k">end</span>
|
158
|
-
<span class="k">end</span></pre></div>
|
159
|
-
</td>
|
160
|
-
</tr>
|
161
|
-
</table>
|
162
|
-
</div>
|
163
|
-
</body>
|
data/doc/lib/recap/rails.html
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
5
|
-
<title>rails.rb</title>
|
6
|
-
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<div id='container'>
|
10
|
-
<div id="background"></div>
|
11
|
-
<div id="jump_to">
|
12
|
-
Jump To …
|
13
|
-
<div id="jump_wrapper">
|
14
|
-
<div id="jump_page">
|
15
|
-
<a class="source" href="../../index.html">index.rb</a>
|
16
|
-
<a class="source" href="../recap.html">recap.rb</a>
|
17
|
-
<a class="source" href="bootstrap.html">bootstrap.rb</a>
|
18
|
-
<a class="source" href="bundler.html">bundler.rb</a>
|
19
|
-
<a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
|
20
|
-
<a class="source" href="cli.html">cli.rb</a>
|
21
|
-
<a class="source" href="compatibility.html">compatibility.rb</a>
|
22
|
-
<a class="source" href="deploy.html">deploy.rb</a>
|
23
|
-
<a class="source" href="env.html">env.rb</a>
|
24
|
-
<a class="source" href="foreman.html">foreman.rb</a>
|
25
|
-
<a class="source" href="namespace.html">namespace.rb</a>
|
26
|
-
<a class="source" href="preflight.html">preflight.rb</a>
|
27
|
-
<a class="source" href="rails.html">rails.rb</a>
|
28
|
-
<a class="source" href="version.html">version.rb</a>
|
29
|
-
</div>
|
30
|
-
</div>
|
31
|
-
</div>
|
32
|
-
<table cellspacing=0 cellpadding=0>
|
33
|
-
<thead>
|
34
|
-
<tr>
|
35
|
-
<th class=docs><h1>rails.rb</h1></th>
|
36
|
-
<th class=code></th>
|
37
|
-
</tr>
|
38
|
-
</thead>
|
39
|
-
<tbody>
|
40
|
-
</table>
|
41
|
-
</div>
|
42
|
-
</body>
|
data/doc/lib/recap/version.html
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
5
|
-
<title>version.rb</title>
|
6
|
-
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<div id='container'>
|
10
|
-
<div id="background"></div>
|
11
|
-
<div id="jump_to">
|
12
|
-
Jump To …
|
13
|
-
<div id="jump_wrapper">
|
14
|
-
<div id="jump_page">
|
15
|
-
<a class="source" href="../../index.html">index.rb</a>
|
16
|
-
<a class="source" href="../recap.html">recap.rb</a>
|
17
|
-
<a class="source" href="bootstrap.html">bootstrap.rb</a>
|
18
|
-
<a class="source" href="bundler.html">bundler.rb</a>
|
19
|
-
<a class="source" href="capistrano_extensions.html">capistrano_extensions.rb</a>
|
20
|
-
<a class="source" href="cli.html">cli.rb</a>
|
21
|
-
<a class="source" href="compatibility.html">compatibility.rb</a>
|
22
|
-
<a class="source" href="deploy.html">deploy.rb</a>
|
23
|
-
<a class="source" href="env.html">env.rb</a>
|
24
|
-
<a class="source" href="foreman.html">foreman.rb</a>
|
25
|
-
<a class="source" href="namespace.html">namespace.rb</a>
|
26
|
-
<a class="source" href="preflight.html">preflight.rb</a>
|
27
|
-
<a class="source" href="rails.html">rails.rb</a>
|
28
|
-
<a class="source" href="version.html">version.rb</a>
|
29
|
-
</div>
|
30
|
-
</div>
|
31
|
-
</div>
|
32
|
-
<table cellspacing=0 cellpadding=0>
|
33
|
-
<thead>
|
34
|
-
<tr>
|
35
|
-
<th class=docs><h1>version.rb</h1></th>
|
36
|
-
<th class=code></th>
|
37
|
-
</tr>
|
38
|
-
</thead>
|
39
|
-
<tbody>
|
40
|
-
</table>
|
41
|
-
</div>
|
42
|
-
</body>
|
data/doc/lib/recap.html
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
5
|
-
<title>recap.rb</title>
|
6
|
-
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
7
|
-
</head>
|
8
|
-
<body>
|
9
|
-
<div id='container'>
|
10
|
-
<div id="background"></div>
|
11
|
-
<div id="jump_to">
|
12
|
-
Jump To …
|
13
|
-
<div id="jump_wrapper">
|
14
|
-
<div id="jump_page">
|
15
|
-
<a class="source" href="../index.html">index.rb</a>
|
16
|
-
<a class="source" href="recap.html">recap.rb</a>
|
17
|
-
<a class="source" href="recap/bootstrap.html">bootstrap.rb</a>
|
18
|
-
<a class="source" href="recap/bundler.html">bundler.rb</a>
|
19
|
-
<a class="source" href="recap/capistrano_extensions.html">capistrano_extensions.rb</a>
|
20
|
-
<a class="source" href="recap/cli.html">cli.rb</a>
|
21
|
-
<a class="source" href="recap/compatibility.html">compatibility.rb</a>
|
22
|
-
<a class="source" href="recap/deploy.html">deploy.rb</a>
|
23
|
-
<a class="source" href="recap/env.html">env.rb</a>
|
24
|
-
<a class="source" href="recap/foreman.html">foreman.rb</a>
|
25
|
-
<a class="source" href="recap/namespace.html">namespace.rb</a>
|
26
|
-
<a class="source" href="recap/preflight.html">preflight.rb</a>
|
27
|
-
<a class="source" href="recap/rails.html">rails.rb</a>
|
28
|
-
<a class="source" href="recap/version.html">version.rb</a>
|
29
|
-
</div>
|
30
|
-
</div>
|
31
|
-
</div>
|
32
|
-
<table cellspacing=0 cellpadding=0>
|
33
|
-
<thead>
|
34
|
-
<tr>
|
35
|
-
<th class=docs><h1>recap.rb</h1></th>
|
36
|
-
<th class=code></th>
|
37
|
-
</tr>
|
38
|
-
</thead>
|
39
|
-
<tbody>
|
40
|
-
</table>
|
41
|
-
</div>
|
42
|
-
</body>
|
data/index.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
# This is the annotated source code and documentation for
|
2
|
-
# [recap](http://github.com/freerange/recap), a simple, opinionated set of capistrano
|
3
|
-
# deployment recipes.
|
4
|
-
|
5
|
-
# Inspired in part by
|
6
|
-
# [this blog post](https://github.com/blog/470-deployment-script-spring-cleaning), these recipes use
|
7
|
-
# git's strengths to deploy applications in a faster, simpler manner than a standard capistrano
|
8
|
-
# deployment. Using git to manage release versions means apps can be deployed to a single directory.
|
9
|
-
# There's no need for `releases`, `shared` or `current` folders, and no symlinking.
|
10
|
-
|
11
|
-
# ### Goals ###
|
12
|
-
|
13
|
-
# These deployment recipes try to do the following:
|
14
|
-
|
15
|
-
# Where possible run commands as the `application_user`, loading the full user environment. The only
|
16
|
-
# exceptions are `git` commands (which often rely on SSH agent forwarding for authentication), and
|
17
|
-
# anything that requires `sudo`.
|
18
|
-
#
|
19
|
-
|
20
|
-
# Use `git` to avoid unecessary work. If the `Gemfile.lock` hasn't changed, there's no need to run
|
21
|
-
# `bundle install`. Similarly if there are no new migrations, why do `rake db:migrate`? Faster
|
22
|
-
# deploys mean more frequent deploys.
|
23
|
-
#
|
24
|
-
|
25
|
-
# Avoid the use of `sudo` (other than to change to the `application_user`). As much as possible,
|
26
|
-
# `sudo` is only used to `su` to the `application_user` before running a command. To avoid having to
|
27
|
-
# type a password to perform the majority of deployment tasks, these lines can be added to
|
28
|
-
# `/etc/sudoers.d/application` (change `application` to the name of your app).
|
29
|
-
|
30
|
-
%application ALL=NOPASSWD: /sbin/start application*
|
31
|
-
%application ALL=NOPASSWD: /sbin/stop application*
|
32
|
-
%application ALL=NOPASSWD: /sbin/restart application*
|
33
|
-
%application ALL=NOPASSWD: /bin/su - application*
|
34
|
-
%application ALL=NOPASSWD: /bin/su application*
|
35
|
-
|
36
|
-
# Use environment variables for configuration. Rather than setting `rails_env` in the `Capfile`,
|
37
|
-
# `RAILS_ENV` (or `RACK_ENV`) variables should be set for the `application_user`. The `env:set` and
|
38
|
-
# `env:edit` tasks help do this.
|
39
|
-
|
40
|
-
# ### Code layout ###
|
41
|
-
|
42
|
-
# The main deployment tasks are defined in [recap/deploy.rb](lib/recap/deploy.html). Automatic
|
43
|
-
# checks to ensure servers are correctly setup are in
|
44
|
-
# [recap/preflight.rb](lib/recap/preflight.html), while tasks for environment variables are in
|
45
|
-
# [recap/env.rb](lib/recap/env.html)
|
46
|
-
|
47
|
-
# In addition, there are extensions for [bundler](lib/recap/bundler.html),
|
48
|
-
# [foreman](lib/recap/foreman.html) and [rails](lib/recap/rails.html)
|
49
|
-
|
50
|
-
# For limited compatability with other existing recipes, see
|
51
|
-
# [compatibility](lib/recap/compatibility.html).
|
52
|
-
|
53
|
-
# ### Deployment target ###
|
54
|
-
|
55
|
-
# These recipes have been developed and tested using Ubuntu 11.04, though they may work well with
|
56
|
-
# other flavours of unix.
|
57
|
-
|
58
|
-
# The application should be run as the application user; if using Apache and Passenger, you should
|
59
|
-
# set the `PassengerDefaultUser` directive to be the same as the `application_user`.
|
60
|
-
|
61
|
-
# The code is available [on github](http://github.com/freerange/recap) and released under the
|
62
|
-
# [MIT License](https://github.com/freerange/recap/blob/master/LICENSE)
|
data/lib/recap/bootstrap.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module Recap::Bootstrap
|
2
|
-
extend Recap::Namespace
|
3
|
-
|
4
|
-
namespace :bootstrap do
|
5
|
-
set(:remote_username) { capture('whoami').strip }
|
6
|
-
set(:application_home) { "/home/#{application_user}"}
|
7
|
-
|
8
|
-
task :default do
|
9
|
-
application
|
10
|
-
user
|
11
|
-
end
|
12
|
-
|
13
|
-
task :application do
|
14
|
-
if exit_code("id #{application_user}").strip != "0"
|
15
|
-
sudo "useradd #{application_user} -d #{application_home}"
|
16
|
-
end
|
17
|
-
sudo "mkdir -p #{application_home}"
|
18
|
-
sudo "chown #{application_user}:#{application_group} #{application_home}"
|
19
|
-
sudo "chmod 755 #{application_home}"
|
20
|
-
|
21
|
-
put_as_app %{
|
22
|
-
if [ -s "$HOME/.env" ]; then
|
23
|
-
rm -rf $HOME/.recap-env-export
|
24
|
-
touch $HOME/.recap-env-export
|
25
|
-
while read line
|
26
|
-
do echo "export $line" >> $HOME/.recap-env-export;
|
27
|
-
done < $HOME/.env
|
28
|
-
. $HOME/.recap-env-export
|
29
|
-
fi
|
30
|
-
}, "#{application_home}/.recap"
|
31
|
-
|
32
|
-
as_app "touch .profile", "~"
|
33
|
-
|
34
|
-
if exit_code(%{grep '\\. \\$HOME\\/.recap' .profile}) != "0"
|
35
|
-
as_app %{echo >> .profile && echo ". \\$HOME/.recap" >> .profile}, "~"
|
36
|
-
end
|
37
|
-
|
38
|
-
as_app "mkdir -p #{deploy_to}", "~"
|
39
|
-
end
|
40
|
-
|
41
|
-
task :user do
|
42
|
-
run "git config --global user.name '#{`git config user.name`.strip}'"
|
43
|
-
run "git config --global user.email '#{`git config user.email`.strip}'"
|
44
|
-
sudo "usermod --append -G #{application_group} #{remote_username}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'tempfile'
|
2
|
-
|
3
|
-
module Recap
|
4
|
-
module CapistranoExtensions
|
5
|
-
# Run a command as the given user
|
6
|
-
def as_user(user, command, pwd = deploy_to)
|
7
|
-
sudo "su - #{user} -c 'cd #{pwd} && #{command}'"
|
8
|
-
end
|
9
|
-
|
10
|
-
# Run a command as root
|
11
|
-
def as_root(command, pwd = deploy_to)
|
12
|
-
as_user 'root', command, pwd
|
13
|
-
end
|
14
|
-
|
15
|
-
# Run a command as the application user
|
16
|
-
def as_app(command, pwd = deploy_to)
|
17
|
-
as_user application_user, command, pwd
|
18
|
-
end
|
19
|
-
|
20
|
-
# Put a string into a file as the application user
|
21
|
-
def put_as_app(string, path)
|
22
|
-
put string, "/tmp/recap-put-as-app"
|
23
|
-
as_app "cp /tmp/recap-put-as-app #{path} && chmod g+rw #{path}", "/"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Edit a file on the remote server, using a local editor
|
27
|
-
def edit_file(path)
|
28
|
-
if editor = ENV['DEPLOY_EDITOR'] || ENV['EDITOR']
|
29
|
-
as_app "touch #{path} && chmod g+rw #{path}"
|
30
|
-
local_path = Tempfile.new('deploy-edit').path
|
31
|
-
get(path, local_path)
|
32
|
-
`#{editor} #{local_path}`
|
33
|
-
upload(local_path, path)
|
34
|
-
else
|
35
|
-
abort "To edit a remote file, either the EDITOR or DEPLOY_EDITOR environment variables must be set"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# Run a git command in the `deploy_to` directory
|
40
|
-
def git(command)
|
41
|
-
run "cd #{deploy_to} && umask 002 && sg #{application_group} -c \"git #{command}\""
|
42
|
-
end
|
43
|
-
|
44
|
-
# Capture the result of a git command run within the `deploy_to` directory
|
45
|
-
def capture_git(command)
|
46
|
-
capture "cd #{deploy_to} && umask 002 && sg #{application_group} -c 'git #{command}'"
|
47
|
-
end
|
48
|
-
|
49
|
-
def exit_code(command)
|
50
|
-
capture("#{command} > /dev/null 2>&1; echo $?").strip
|
51
|
-
end
|
52
|
-
|
53
|
-
# Find the latest tag from the repository. As `git tag` returns tags in order, and our release
|
54
|
-
# tags are timestamps, the latest tag will always be the last in the list.
|
55
|
-
def latest_tag_from_repository
|
56
|
-
result = capture_git("tag | tail -n1").strip
|
57
|
-
result.empty? ? nil : result
|
58
|
-
end
|
59
|
-
|
60
|
-
# Does the given file exist within the deployment directory?
|
61
|
-
def deployed_file_exists?(path)
|
62
|
-
exit_code("cd #{deploy_to} && [ -f #{path} ]") == "0"
|
63
|
-
end
|
64
|
-
|
65
|
-
# Has the given path been created or changed since the previous deployment? During the first
|
66
|
-
# successful deployment this will always return true.
|
67
|
-
def deployed_file_changed?(path)
|
68
|
-
return true unless latest_tag
|
69
|
-
exit_code("cd #{deploy_to} && git diff --exit-code #{latest_tag} origin/#{branch} #{path}") == "1"
|
70
|
-
end
|
71
|
-
|
72
|
-
Capistrano::Configuration.send :include, self
|
73
|
-
end
|
74
|
-
end
|
data/lib/recap/cli.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require 'thor'
|
2
|
-
|
3
|
-
module Recap
|
4
|
-
class CLI < Thor
|
5
|
-
include Thor::Actions
|
6
|
-
|
7
|
-
attr_accessor :name, :repository
|
8
|
-
|
9
|
-
def self.source_root
|
10
|
-
File.expand_path("../deploy/templates", __FILE__)
|
11
|
-
end
|
12
|
-
|
13
|
-
desc 'setup', 'Setup basic capistrano recipes, e.g: recap setup'
|
14
|
-
method_option :name, :aliases => "-n"
|
15
|
-
method_option :repository, :aliases => "-r"
|
16
|
-
def setup
|
17
|
-
self.name = options["name"] || guess_name
|
18
|
-
self.repository = options["repo"] || guess_repository
|
19
|
-
template 'Capfile.erb', 'Capfile'
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def guess_name
|
25
|
-
Dir.pwd.split(File::SEPARATOR).last
|
26
|
-
end
|
27
|
-
|
28
|
-
def guess_repository
|
29
|
-
`git remote -v`.split[1]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
data/lib/recap/env.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
# Environment variables are a useful way to set application configuration, such as database passwords
|
2
|
-
# or S3 keys and secrets. [recap](http://github.com/freerange/recap) stores these extra variables in
|
3
|
-
# a special file, usually stored at `$HOME/.env`. This file is loaded each time the shell starts by
|
4
|
-
# adding the following to the user's `.profile`:
|
5
|
-
#
|
6
|
-
# . $HOME/.recap
|
7
|
-
#
|
8
|
-
# The `.recap` script is automatically generated in the bootstrap process.
|
9
|
-
|
10
|
-
module Recap::Env
|
11
|
-
extend Recap::Namespace
|
12
|
-
|
13
|
-
namespace :env do
|
14
|
-
# Environment
|
15
|
-
set(:environment_file) { "/home/#{application_user}/.env" }
|
16
|
-
|
17
|
-
def current_environment
|
18
|
-
@current_environment ||= begin
|
19
|
-
if deployed_file_exists?(environment_file)
|
20
|
-
Recap::Environment.from_string(capture("cat #{environment_file}"))
|
21
|
-
else
|
22
|
-
Recap::Environment.new
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
task :default do
|
28
|
-
if current_environment.empty?
|
29
|
-
puts "There are no config variables set"
|
30
|
-
else
|
31
|
-
puts "The config variables are:"
|
32
|
-
puts
|
33
|
-
puts current_environment
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
task :set do
|
38
|
-
env = ARGV[1..-1].inject(current_environment) do |env, string|
|
39
|
-
env.set_string(string)
|
40
|
-
logger.debug "Setting #{string}"
|
41
|
-
logger.debug "Env is now: #{env}"
|
42
|
-
env
|
43
|
-
end
|
44
|
-
|
45
|
-
if env.empty?
|
46
|
-
as_app "rm -f #{environment_file}", "~"
|
47
|
-
else
|
48
|
-
put_as_app env.to_s, environment_file
|
49
|
-
end
|
50
|
-
default
|
51
|
-
end
|
52
|
-
|
53
|
-
task :edit do
|
54
|
-
edit_file environment_file
|
55
|
-
default
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
data/lib/recap/environment.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
class Recap::Environment
|
2
|
-
def initialize(variables = {})
|
3
|
-
@variables = variables
|
4
|
-
end
|
5
|
-
|
6
|
-
def get(name)
|
7
|
-
@variables[name]
|
8
|
-
end
|
9
|
-
|
10
|
-
def set(name, value)
|
11
|
-
if value.nil? || value.empty?
|
12
|
-
@variables.delete(name)
|
13
|
-
else
|
14
|
-
@variables[name] = value
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def set_string(string)
|
19
|
-
if string =~ /\A([A-Za-z0-9_]+)=(.*)\z/
|
20
|
-
set $1, $2
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def empty?
|
25
|
-
@variables.empty?
|
26
|
-
end
|
27
|
-
|
28
|
-
def merge(hash)
|
29
|
-
hash.each {|k, v| set(k, v)}
|
30
|
-
end
|
31
|
-
|
32
|
-
def each(&block)
|
33
|
-
@variables.sort.each(&block)
|
34
|
-
end
|
35
|
-
|
36
|
-
def include?(key)
|
37
|
-
@variables.include?(key)
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_s
|
41
|
-
@variables.keys.sort.map do |key|
|
42
|
-
key + "=" + @variables[key] + "\n" if @variables[key]
|
43
|
-
end.compact.join
|
44
|
-
end
|
45
|
-
|
46
|
-
class << self
|
47
|
-
def from_string(string)
|
48
|
-
string.split("\n").inject(new) do |env, line|
|
49
|
-
env.set_string(line)
|
50
|
-
env
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|