capistrano 2.8.0 → 3.19.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.
Files changed (239) hide show
  1. checksums.yaml +7 -0
  2. data/.docker/Dockerfile +7 -0
  3. data/.docker/ssh_key_rsa +49 -0
  4. data/.docker/ssh_key_rsa.pub +1 -0
  5. data/.docker/ubuntu_setup.sh +23 -0
  6. data/.github/issue_template.md +19 -0
  7. data/.github/pull_request_template.md +22 -0
  8. data/.github/release-drafter.yml +25 -0
  9. data/.github/workflows/ci.yml +80 -0
  10. data/.github/workflows/release-drafter.yml +18 -0
  11. data/.gitignore +23 -8
  12. data/.rubocop.yml +62 -0
  13. data/CHANGELOG.md +1 -0
  14. data/CONTRIBUTING.md +63 -0
  15. data/DEVELOPMENT.md +112 -0
  16. data/Gemfile +42 -9
  17. data/LICENSE.txt +21 -0
  18. data/README.md +221 -0
  19. data/RELEASING.md +17 -0
  20. data/Rakefile +17 -8
  21. data/UPGRADING-3.7.md +86 -0
  22. data/bin/cap +2 -3
  23. data/bin/capify +7 -89
  24. data/capistrano.gemspec +29 -43
  25. data/docker-compose.yml +8 -0
  26. data/features/configuration.feature +28 -0
  27. data/features/deploy.feature +92 -0
  28. data/features/deploy_failure.feature +17 -0
  29. data/features/doctor.feature +11 -0
  30. data/features/installation.feature +21 -0
  31. data/features/sshconnect.feature +11 -0
  32. data/features/stage_failure.feature +9 -0
  33. data/features/step_definitions/assertions.rb +162 -0
  34. data/features/step_definitions/cap_commands.rb +21 -0
  35. data/features/step_definitions/setup.rb +91 -0
  36. data/features/subdirectory.feature +9 -0
  37. data/features/support/docker_gateway.rb +53 -0
  38. data/features/support/env.rb +1 -0
  39. data/features/support/remote_command_helpers.rb +29 -0
  40. data/features/support/remote_ssh_helpers.rb +33 -0
  41. data/lib/Capfile +3 -0
  42. data/lib/capistrano/all.rb +17 -0
  43. data/lib/capistrano/application.rb +153 -0
  44. data/lib/capistrano/configuration/empty_filter.rb +9 -0
  45. data/lib/capistrano/configuration/filter.rb +26 -0
  46. data/lib/capistrano/configuration/host_filter.rb +29 -0
  47. data/lib/capistrano/configuration/null_filter.rb +9 -0
  48. data/lib/capistrano/configuration/plugin_installer.rb +51 -0
  49. data/lib/capistrano/configuration/question.rb +76 -0
  50. data/lib/capistrano/configuration/role_filter.rb +29 -0
  51. data/lib/capistrano/configuration/scm_resolver.rb +149 -0
  52. data/lib/capistrano/configuration/server.rb +137 -0
  53. data/lib/capistrano/configuration/servers.rb +56 -96
  54. data/lib/capistrano/configuration/validated_variables.rb +110 -0
  55. data/lib/capistrano/configuration/variables.rb +79 -94
  56. data/lib/capistrano/configuration.rb +178 -33
  57. data/lib/capistrano/console.rb +1 -0
  58. data/lib/capistrano/defaults.rb +36 -0
  59. data/lib/capistrano/deploy.rb +3 -0
  60. data/lib/capistrano/doctor/environment_doctor.rb +19 -0
  61. data/lib/capistrano/doctor/gems_doctor.rb +45 -0
  62. data/lib/capistrano/doctor/output_helpers.rb +79 -0
  63. data/lib/capistrano/doctor/servers_doctor.rb +105 -0
  64. data/lib/capistrano/doctor/variables_doctor.rb +74 -0
  65. data/lib/capistrano/doctor.rb +6 -0
  66. data/lib/capistrano/dotfile.rb +2 -0
  67. data/lib/capistrano/dsl/env.rb +43 -0
  68. data/lib/capistrano/dsl/paths.rb +89 -0
  69. data/lib/capistrano/dsl/stages.rb +31 -0
  70. data/lib/capistrano/dsl/task_enhancements.rb +61 -0
  71. data/lib/capistrano/dsl.rb +95 -0
  72. data/lib/capistrano/framework.rb +2 -0
  73. data/lib/capistrano/i18n.rb +46 -0
  74. data/lib/capistrano/immutable_task.rb +30 -0
  75. data/lib/capistrano/install.rb +1 -0
  76. data/lib/capistrano/plugin.rb +95 -0
  77. data/lib/capistrano/proc_helpers.rb +13 -0
  78. data/lib/capistrano/scm/git.rb +105 -0
  79. data/lib/capistrano/scm/hg.rb +55 -0
  80. data/lib/capistrano/scm/plugin.rb +13 -0
  81. data/lib/capistrano/scm/svn.rb +56 -0
  82. data/lib/capistrano/scm/tasks/git.rake +84 -0
  83. data/lib/capistrano/scm/tasks/hg.rake +53 -0
  84. data/lib/capistrano/scm/tasks/svn.rake +53 -0
  85. data/lib/capistrano/scm.rb +115 -0
  86. data/lib/capistrano/setup.rb +36 -0
  87. data/lib/capistrano/tasks/console.rake +25 -0
  88. data/lib/capistrano/tasks/deploy.rake +280 -0
  89. data/lib/capistrano/tasks/doctor.rake +24 -0
  90. data/lib/capistrano/tasks/framework.rake +67 -0
  91. data/lib/capistrano/tasks/install.rake +41 -0
  92. data/lib/capistrano/templates/Capfile +38 -0
  93. data/lib/capistrano/templates/deploy.rb.erb +39 -0
  94. data/lib/capistrano/templates/stage.rb.erb +61 -0
  95. data/lib/capistrano/upload_task.rb +9 -0
  96. data/lib/capistrano/version.rb +1 -14
  97. data/lib/capistrano/version_validator.rb +32 -0
  98. data/lib/capistrano.rb +0 -3
  99. data/spec/integration/dsl_spec.rb +632 -0
  100. data/spec/integration_spec_helper.rb +5 -0
  101. data/spec/lib/capistrano/application_spec.rb +60 -0
  102. data/spec/lib/capistrano/configuration/empty_filter_spec.rb +17 -0
  103. data/spec/lib/capistrano/configuration/filter_spec.rb +109 -0
  104. data/spec/lib/capistrano/configuration/host_filter_spec.rb +71 -0
  105. data/spec/lib/capistrano/configuration/null_filter_spec.rb +17 -0
  106. data/spec/lib/capistrano/configuration/plugin_installer_spec.rb +98 -0
  107. data/spec/lib/capistrano/configuration/question_spec.rb +92 -0
  108. data/spec/lib/capistrano/configuration/role_filter_spec.rb +80 -0
  109. data/spec/lib/capistrano/configuration/scm_resolver_spec.rb +56 -0
  110. data/spec/lib/capistrano/configuration/server_spec.rb +309 -0
  111. data/spec/lib/capistrano/configuration/servers_spec.rb +331 -0
  112. data/spec/lib/capistrano/configuration_spec.rb +357 -0
  113. data/spec/lib/capistrano/doctor/environment_doctor_spec.rb +44 -0
  114. data/spec/lib/capistrano/doctor/gems_doctor_spec.rb +67 -0
  115. data/spec/lib/capistrano/doctor/output_helpers_spec.rb +47 -0
  116. data/spec/lib/capistrano/doctor/servers_doctor_spec.rb +86 -0
  117. data/spec/lib/capistrano/doctor/variables_doctor_spec.rb +89 -0
  118. data/spec/lib/capistrano/dsl/paths_spec.rb +228 -0
  119. data/spec/lib/capistrano/dsl/task_enhancements_spec.rb +108 -0
  120. data/spec/lib/capistrano/dsl_spec.rb +125 -0
  121. data/spec/lib/capistrano/immutable_task_spec.rb +31 -0
  122. data/spec/lib/capistrano/plugin_spec.rb +84 -0
  123. data/spec/lib/capistrano/scm/git_spec.rb +194 -0
  124. data/spec/lib/capistrano/scm/hg_spec.rb +109 -0
  125. data/spec/lib/capistrano/scm/svn_spec.rb +137 -0
  126. data/spec/lib/capistrano/scm_spec.rb +103 -0
  127. data/spec/lib/capistrano/upload_task_spec.rb +19 -0
  128. data/spec/lib/capistrano/version_validator_spec.rb +118 -0
  129. data/spec/lib/capistrano_spec.rb +7 -0
  130. data/spec/spec_helper.rb +29 -0
  131. data/spec/support/matchers.rb +5 -0
  132. data/spec/support/tasks/database.rake +11 -0
  133. data/spec/support/tasks/fail.rake +8 -0
  134. data/spec/support/tasks/failed.rake +5 -0
  135. data/spec/support/tasks/plugin.rake +6 -0
  136. data/spec/support/tasks/root.rake +11 -0
  137. data/spec/support/test_app.rb +205 -0
  138. metadata +234 -208
  139. data/.rvmrc +0 -1
  140. data/CHANGELOG +0 -954
  141. data/README.mdown +0 -76
  142. data/lib/capistrano/callback.rb +0 -45
  143. data/lib/capistrano/cli/execute.rb +0 -85
  144. data/lib/capistrano/cli/help.rb +0 -125
  145. data/lib/capistrano/cli/help.txt +0 -81
  146. data/lib/capistrano/cli/options.rb +0 -243
  147. data/lib/capistrano/cli/ui.rb +0 -40
  148. data/lib/capistrano/cli.rb +0 -47
  149. data/lib/capistrano/command.rb +0 -286
  150. data/lib/capistrano/configuration/actions/file_transfer.rb +0 -51
  151. data/lib/capistrano/configuration/actions/inspect.rb +0 -46
  152. data/lib/capistrano/configuration/actions/invocation.rb +0 -298
  153. data/lib/capistrano/configuration/callbacks.rb +0 -148
  154. data/lib/capistrano/configuration/connections.rb +0 -230
  155. data/lib/capistrano/configuration/execution.rb +0 -143
  156. data/lib/capistrano/configuration/loading.rb +0 -197
  157. data/lib/capistrano/configuration/namespaces.rb +0 -197
  158. data/lib/capistrano/configuration/roles.rb +0 -73
  159. data/lib/capistrano/errors.rb +0 -19
  160. data/lib/capistrano/ext/string.rb +0 -5
  161. data/lib/capistrano/extensions.rb +0 -57
  162. data/lib/capistrano/logger.rb +0 -59
  163. data/lib/capistrano/processable.rb +0 -53
  164. data/lib/capistrano/recipes/compat.rb +0 -32
  165. data/lib/capistrano/recipes/deploy/assets.rb +0 -57
  166. data/lib/capistrano/recipes/deploy/dependencies.rb +0 -44
  167. data/lib/capistrano/recipes/deploy/local_dependency.rb +0 -54
  168. data/lib/capistrano/recipes/deploy/remote_dependency.rb +0 -111
  169. data/lib/capistrano/recipes/deploy/scm/accurev.rb +0 -169
  170. data/lib/capistrano/recipes/deploy/scm/base.rb +0 -196
  171. data/lib/capistrano/recipes/deploy/scm/bzr.rb +0 -86
  172. data/lib/capistrano/recipes/deploy/scm/cvs.rb +0 -153
  173. data/lib/capistrano/recipes/deploy/scm/darcs.rb +0 -96
  174. data/lib/capistrano/recipes/deploy/scm/git.rb +0 -282
  175. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +0 -137
  176. data/lib/capistrano/recipes/deploy/scm/none.rb +0 -44
  177. data/lib/capistrano/recipes/deploy/scm/perforce.rb +0 -138
  178. data/lib/capistrano/recipes/deploy/scm/subversion.rb +0 -121
  179. data/lib/capistrano/recipes/deploy/scm.rb +0 -19
  180. data/lib/capistrano/recipes/deploy/strategy/base.rb +0 -88
  181. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +0 -20
  182. data/lib/capistrano/recipes/deploy/strategy/copy.rb +0 -224
  183. data/lib/capistrano/recipes/deploy/strategy/export.rb +0 -20
  184. data/lib/capistrano/recipes/deploy/strategy/remote.rb +0 -52
  185. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +0 -57
  186. data/lib/capistrano/recipes/deploy/strategy.rb +0 -19
  187. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
  188. data/lib/capistrano/recipes/deploy.rb +0 -568
  189. data/lib/capistrano/recipes/standard.rb +0 -37
  190. data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
  191. data/lib/capistrano/role.rb +0 -102
  192. data/lib/capistrano/server_definition.rb +0 -56
  193. data/lib/capistrano/shell.rb +0 -260
  194. data/lib/capistrano/ssh.rb +0 -101
  195. data/lib/capistrano/task_definition.rb +0 -75
  196. data/lib/capistrano/transfer.rb +0 -216
  197. data/rvmrc.sample +0 -1
  198. data/test/cli/execute_test.rb +0 -132
  199. data/test/cli/help_test.rb +0 -165
  200. data/test/cli/options_test.rb +0 -329
  201. data/test/cli/ui_test.rb +0 -28
  202. data/test/cli_test.rb +0 -17
  203. data/test/command_test.rb +0 -289
  204. data/test/configuration/actions/file_transfer_test.rb +0 -61
  205. data/test/configuration/actions/inspect_test.rb +0 -65
  206. data/test/configuration/actions/invocation_test.rb +0 -247
  207. data/test/configuration/callbacks_test.rb +0 -220
  208. data/test/configuration/connections_test.rb +0 -420
  209. data/test/configuration/execution_test.rb +0 -175
  210. data/test/configuration/loading_test.rb +0 -132
  211. data/test/configuration/namespace_dsl_test.rb +0 -311
  212. data/test/configuration/roles_test.rb +0 -144
  213. data/test/configuration/servers_test.rb +0 -183
  214. data/test/configuration/variables_test.rb +0 -190
  215. data/test/configuration_test.rb +0 -88
  216. data/test/deploy/local_dependency_test.rb +0 -76
  217. data/test/deploy/remote_dependency_test.rb +0 -135
  218. data/test/deploy/scm/accurev_test.rb +0 -23
  219. data/test/deploy/scm/base_test.rb +0 -55
  220. data/test/deploy/scm/bzr_test.rb +0 -51
  221. data/test/deploy/scm/darcs_test.rb +0 -37
  222. data/test/deploy/scm/git_test.rb +0 -184
  223. data/test/deploy/scm/mercurial_test.rb +0 -134
  224. data/test/deploy/scm/none_test.rb +0 -35
  225. data/test/deploy/scm/subversion_test.rb +0 -32
  226. data/test/deploy/strategy/copy_test.rb +0 -321
  227. data/test/extensions_test.rb +0 -69
  228. data/test/fixtures/cli_integration.rb +0 -5
  229. data/test/fixtures/config.rb +0 -5
  230. data/test/fixtures/custom.rb +0 -3
  231. data/test/logger_test.rb +0 -123
  232. data/test/recipes_test.rb +0 -25
  233. data/test/role_test.rb +0 -11
  234. data/test/server_definition_test.rb +0 -121
  235. data/test/shell_test.rb +0 -90
  236. data/test/ssh_test.rb +0 -113
  237. data/test/task_definition_test.rb +0 -116
  238. data/test/transfer_test.rb +0 -160
  239. data/test/utils.rb +0 -37
@@ -0,0 +1,632 @@
1
+ require "spec_helper"
2
+
3
+ describe Capistrano::DSL do
4
+ let(:dsl) { Class.new.extend Capistrano::DSL }
5
+
6
+ before do
7
+ Capistrano::Configuration.reset!
8
+ end
9
+
10
+ describe "setting and fetching hosts" do
11
+ describe "when defining a host using the `server` syntax" do
12
+ before do
13
+ dsl.server "example1.com", roles: %w{web}, active: true
14
+ dsl.server "example2.com", roles: %w{web}
15
+ dsl.server "example3.com", roles: %w{app web}, active: true
16
+ dsl.server "example4.com", roles: %w{app}, primary: true
17
+ dsl.server "example5.com", roles: %w{db}, no_release: true, active: true
18
+ end
19
+
20
+ describe "fetching all servers" do
21
+ subject { dsl.roles(:all) }
22
+
23
+ it "returns all servers" do
24
+ expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com example5.com}
25
+ end
26
+ end
27
+
28
+ describe "fetching all release servers" do
29
+ context "with no additional options" do
30
+ subject { dsl.release_roles(:all) }
31
+
32
+ it "returns all release servers" do
33
+ expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com}
34
+ end
35
+ end
36
+
37
+ context "with property filter options" do
38
+ subject { dsl.release_roles(:all, filter: :active) }
39
+
40
+ it "returns all release servers that match the property filter" do
41
+ expect(subject.map(&:hostname)).to eq %w{example1.com example3.com}
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "fetching servers by multiple roles" do
47
+ it "does not confuse the last role with options" do
48
+ expect(dsl.roles(:app, :web).count).to eq 4
49
+ expect(dsl.roles(:app, :web, filter: :active).count).to eq 2
50
+ end
51
+ end
52
+
53
+ describe "fetching servers by role" do
54
+ subject { dsl.roles(:app) }
55
+
56
+ it "returns the servers" do
57
+ expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
58
+ end
59
+ end
60
+
61
+ describe "fetching servers by an array of roles" do
62
+ subject { dsl.roles([:app]) }
63
+
64
+ it "returns the servers" do
65
+ expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
66
+ end
67
+ end
68
+
69
+ describe "fetching filtered servers by role" do
70
+ subject { dsl.roles(:app, filter: :active) }
71
+
72
+ it "returns the servers" do
73
+ expect(subject.map(&:hostname)).to eq %w{example3.com}
74
+ end
75
+ end
76
+
77
+ describe "fetching selected servers by role" do
78
+ subject { dsl.roles(:app, select: :active) }
79
+
80
+ it "returns the servers" do
81
+ expect(subject.map(&:hostname)).to eq %w{example3.com}
82
+ end
83
+ end
84
+
85
+ describe "fetching the primary server by role" do
86
+ context "when inferring primary status based on order" do
87
+ subject { dsl.primary(:web) }
88
+ it "returns the servers" do
89
+ expect(subject.hostname).to eq "example1.com"
90
+ end
91
+ end
92
+
93
+ context "when the attribute `primary` is explicitly set" do
94
+ subject { dsl.primary(:app) }
95
+ it "returns the servers" do
96
+ expect(subject.hostname).to eq "example4.com"
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "setting an internal host filter" do
102
+ subject { dsl.roles(:app) }
103
+ it "is ignored" do
104
+ dsl.set :filter, host: "example3.com"
105
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
106
+ end
107
+ end
108
+
109
+ describe "setting an internal role filter" do
110
+ subject { dsl.roles(:app) }
111
+ it "ignores it" do
112
+ dsl.set :filter, role: :web
113
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
114
+ end
115
+ end
116
+
117
+ describe "setting an internal host and role filter" do
118
+ subject { dsl.roles(:app) }
119
+ it "ignores it" do
120
+ dsl.set :filter, role: :web, host: "example1.com"
121
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
122
+ end
123
+ end
124
+
125
+ describe "setting an internal regexp host filter" do
126
+ subject { dsl.roles(:all) }
127
+ it "is ignored" do
128
+ dsl.set :filter, host: /1/
129
+ expect(subject.map(&:hostname)).to eq(%w{example1.com example2.com example3.com example4.com example5.com})
130
+ end
131
+ end
132
+
133
+ describe "setting an internal hosts filter" do
134
+ subject { dsl.roles(:app) }
135
+ it "is ignored" do
136
+ dsl.set :filter, hosts: "example3.com"
137
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
138
+ end
139
+ end
140
+
141
+ describe "setting an internal roles filter" do
142
+ subject { dsl.roles(:app) }
143
+ it "ignores it" do
144
+ dsl.set :filter, roles: :web
145
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
146
+ end
147
+ end
148
+
149
+ describe "setting an internal hosts and roles filter" do
150
+ subject { dsl.roles(:app) }
151
+ it "ignores it" do
152
+ dsl.set :filter, roles: :web, hosts: "example1.com"
153
+ expect(subject.map(&:hostname)).to eq(["example3.com", "example4.com"])
154
+ end
155
+ end
156
+
157
+ describe "setting an internal regexp hosts filter" do
158
+ subject { dsl.roles(:all) }
159
+ it "is ignored" do
160
+ dsl.set :filter, hosts: /1/
161
+ expect(subject.map(&:hostname)).to eq(%w{example1.com example2.com example3.com example4.com example5.com})
162
+ end
163
+ end
164
+ end
165
+
166
+ describe "when defining role with reserved name" do
167
+ it "fails with ArgumentError" do
168
+ expect do
169
+ dsl.role :all, %w{example1.com}
170
+ end.to raise_error(ArgumentError, "all reserved name for role. Please choose another name")
171
+ end
172
+ end
173
+
174
+ describe "when defining hosts using the `role` syntax" do
175
+ before do
176
+ dsl.role :web, %w{example1.com example2.com example3.com}
177
+ dsl.role :web, %w{example1.com}, active: true
178
+ dsl.role :app, %w{example3.com example4.com}
179
+ dsl.role :app, %w{example3.com}, active: true
180
+ dsl.role :app, %w{example4.com}, primary: true
181
+ dsl.role :db, %w{example5.com}, no_release: true
182
+ end
183
+
184
+ describe "fetching all servers" do
185
+ subject { dsl.roles(:all) }
186
+
187
+ it "returns all servers" do
188
+ expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com example5.com}
189
+ end
190
+ end
191
+
192
+ describe "fetching all release servers" do
193
+ context "with no additional options" do
194
+ subject { dsl.release_roles(:all) }
195
+
196
+ it "returns all release servers" do
197
+ expect(subject.map(&:hostname)).to eq %w{example1.com example2.com example3.com example4.com}
198
+ end
199
+ end
200
+
201
+ context "with filter options" do
202
+ subject { dsl.release_roles(:all, filter: :active) }
203
+
204
+ it "returns all release servers that match the filter" do
205
+ expect(subject.map(&:hostname)).to eq %w{example1.com example3.com}
206
+ end
207
+ end
208
+ end
209
+
210
+ describe "fetching servers by role" do
211
+ subject { dsl.roles(:app) }
212
+
213
+ it "returns the servers" do
214
+ expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
215
+ end
216
+ end
217
+
218
+ describe "fetching servers by an array of roles" do
219
+ subject { dsl.roles([:app]) }
220
+
221
+ it "returns the servers" do
222
+ expect(subject.map(&:hostname)).to eq %w{example3.com example4.com}
223
+ end
224
+ end
225
+
226
+ describe "fetching filtered servers by role" do
227
+ subject { dsl.roles(:app, filter: :active) }
228
+
229
+ it "returns the servers" do
230
+ expect(subject.map(&:hostname)).to eq %w{example3.com}
231
+ end
232
+ end
233
+
234
+ describe "fetching selected servers by role" do
235
+ subject { dsl.roles(:app, select: :active) }
236
+
237
+ it "returns the servers" do
238
+ expect(subject.map(&:hostname)).to eq %w{example3.com}
239
+ end
240
+ end
241
+
242
+ describe "fetching the primary server by role" do
243
+ context "when inferring primary status based on order" do
244
+ subject { dsl.primary(:web) }
245
+ it "returns the servers" do
246
+ expect(subject.hostname).to eq "example1.com"
247
+ end
248
+ end
249
+
250
+ context "when the attribute `primary` is explicitly set" do
251
+ subject { dsl.primary(:app) }
252
+ it "returns the servers" do
253
+ expect(subject.hostname).to eq "example4.com"
254
+ end
255
+ end
256
+ end
257
+ end
258
+
259
+ describe "when defining a host using a combination of the `server` and `role` syntax" do
260
+ before do
261
+ dsl.server "db@example1.com:1234", roles: %w{db}, active: true
262
+ dsl.server "root@example1.com:1234", roles: %w{web}, active: true
263
+ dsl.server "example1.com:5678", roles: %w{web}, active: true
264
+ dsl.role :app, %w{deployer@example1.com:1234}
265
+ dsl.role :app, %w{example1.com:5678}
266
+ end
267
+
268
+ describe "fetching all servers" do
269
+ it "creates one server per hostname, ignoring user combinations" do
270
+ expect(dsl.roles(:all).size).to eq(2)
271
+ end
272
+ end
273
+
274
+ describe "fetching servers for a role" do
275
+ it "roles defined using the `server` syntax are included" do
276
+ as = dsl.roles(:web).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }
277
+ expect(as.size).to eq(2)
278
+ expect(as[0]).to eq("deployer@example1.com:1234")
279
+ expect(as[1]).to eq("@example1.com:5678")
280
+ end
281
+
282
+ it "roles defined using the `role` syntax are included" do
283
+ as = dsl.roles(:app).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }
284
+ expect(as.size).to eq(2)
285
+ expect(as[0]).to eq("deployer@example1.com:1234")
286
+ expect(as[1]).to eq("@example1.com:5678")
287
+ end
288
+ end
289
+ end
290
+
291
+ describe "when setting user and port" do
292
+ subject { dsl.roles(:all).map { |server| "#{server.user}@#{server.hostname}:#{server.port}" }.first }
293
+
294
+ describe "using the :user property" do
295
+ it "takes precedence over in the host string" do
296
+ dsl.server "db@example1.com:1234", roles: %w{db}, active: true, user: "brian"
297
+ expect(subject).to eq("brian@example1.com:1234")
298
+ end
299
+ end
300
+
301
+ describe "using the :port property" do
302
+ it "takes precedence over in the host string" do
303
+ dsl.server "db@example1.com:9090", roles: %w{db}, active: true, port: 1234
304
+ expect(subject).to eq("db@example1.com:1234")
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ describe "setting and fetching variables" do
311
+ before do
312
+ dsl.set :scm, :git
313
+ end
314
+
315
+ context "without a default" do
316
+ context "when the variables is defined" do
317
+ it "returns the variable" do
318
+ expect(dsl.fetch(:scm)).to eq :git
319
+ end
320
+ end
321
+
322
+ context "when the variables is undefined" do
323
+ it "returns nil" do
324
+ expect(dsl.fetch(:source_control)).to be_nil
325
+ end
326
+ end
327
+ end
328
+
329
+ context "with a default" do
330
+ context "when the variables is defined" do
331
+ it "returns the variable" do
332
+ expect(dsl.fetch(:scm, :svn)).to eq :git
333
+ end
334
+ end
335
+
336
+ context "when the variables is undefined" do
337
+ it "returns the default" do
338
+ expect(dsl.fetch(:source_control, :svn)).to eq :svn
339
+ end
340
+ end
341
+ end
342
+
343
+ context "with a block" do
344
+ context "when the variables is defined" do
345
+ it "returns the variable" do
346
+ expect(dsl.fetch(:scm) { :svn }).to eq :git
347
+ end
348
+ end
349
+
350
+ context "when the variables is undefined" do
351
+ it "calls the block" do
352
+ expect(dsl.fetch(:source_control) { :svn }).to eq :svn
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ describe "asking for a variable" do
359
+ let(:stdin) { stub(tty?: true) }
360
+
361
+ before do
362
+ dsl.ask(:scm, :svn, stdin: stdin)
363
+ $stdout.stubs(:print)
364
+ end
365
+
366
+ context "variable is provided" do
367
+ before do
368
+ stdin.expects(:gets).returns("git")
369
+ end
370
+
371
+ it "sets the input as the variable" do
372
+ expect(dsl.fetch(:scm)).to eq "git"
373
+ end
374
+ end
375
+
376
+ context "variable is not provided" do
377
+ before do
378
+ stdin.expects(:gets).returns("")
379
+ end
380
+
381
+ it "sets the variable as the default" do
382
+ expect(dsl.fetch(:scm)).to eq :svn
383
+ end
384
+ end
385
+ end
386
+
387
+ describe "checking for presence" do
388
+ subject { dsl.any? :linked_files }
389
+
390
+ before do
391
+ dsl.set(:linked_files, linked_files)
392
+ end
393
+
394
+ context "variable is an non-empty array" do
395
+ let(:linked_files) { %w{1} }
396
+
397
+ it { expect(subject).to be_truthy }
398
+ end
399
+
400
+ context "variable is an empty array" do
401
+ let(:linked_files) { [] }
402
+ it { expect(subject).to be_falsey }
403
+ end
404
+
405
+ context "variable exists, is not an array" do
406
+ let(:linked_files) { stub }
407
+ it { expect(subject).to be_truthy }
408
+ end
409
+
410
+ context "variable is nil" do
411
+ let(:linked_files) { nil }
412
+ it { expect(subject).to be_falsey }
413
+ end
414
+ end
415
+
416
+ describe "configuration SSHKit" do
417
+ let(:config) { SSHKit.config }
418
+ let(:backend) { SSHKit.config.backend.config }
419
+ let(:default_env) { { rails_env: :production } }
420
+
421
+ before do
422
+ dsl.set(:format, :dot)
423
+ dsl.set(:log_level, :debug)
424
+ dsl.set(:default_env, default_env)
425
+ dsl.set(:pty, true)
426
+ dsl.set(:connection_timeout, 10)
427
+ dsl.set(:ssh_options, keys: %w(/home/user/.ssh/id_rsa),
428
+ forward_agent: false,
429
+ auth_methods: %w(publickey password))
430
+ dsl.configure_backend
431
+ end
432
+
433
+ it "sets the output" do
434
+ expect(config.output).to be_a SSHKit::Formatter::Dot
435
+ end
436
+
437
+ it "sets the output verbosity" do
438
+ expect(config.output_verbosity).to eq 0
439
+ end
440
+
441
+ it "sets the default env" do
442
+ expect(config.default_env).to eq default_env
443
+ end
444
+
445
+ it "sets the backend pty" do
446
+ expect(backend.pty).to be_truthy
447
+ end
448
+
449
+ it "sets the backend connection timeout" do
450
+ expect(backend.connection_timeout).to eq 10
451
+ end
452
+
453
+ it "sets the backend ssh_options" do
454
+ expect(backend.ssh_options[:keys]).to eq %w(/home/user/.ssh/id_rsa)
455
+ expect(backend.ssh_options[:forward_agent]).to eq false
456
+ expect(backend.ssh_options[:auth_methods]).to eq %w(publickey password)
457
+ end
458
+ end
459
+
460
+ describe "on()" do
461
+ describe "when passed server objects" do
462
+ before do
463
+ dsl.server "example1.com", roles: %w{web}, active: true
464
+ dsl.server "example2.com", roles: %w{web}
465
+ dsl.server "example3.com", roles: %w{app web}, active: true
466
+ dsl.server "example4.com", roles: %w{app}, primary: true
467
+ dsl.server "example5.com", roles: %w{db}, no_release: true
468
+ @coordinator = mock("coordinator")
469
+ @coordinator.expects(:each).returns(nil)
470
+ ENV.delete "ROLES"
471
+ ENV.delete "HOSTS"
472
+ end
473
+
474
+ it "filters by role from the :filter variable" do
475
+ hosts = dsl.roles(:web)
476
+ all = dsl.roles(:all)
477
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
478
+ dsl.set :filter, role: "web"
479
+ dsl.on(all)
480
+ end
481
+
482
+ it "filters by host and role from the :filter variable" do
483
+ all = dsl.roles(:all)
484
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
485
+ dsl.set :filter, role: "db", host: "example3.com"
486
+ dsl.on(all)
487
+ end
488
+
489
+ it "filters by roles from the :filter variable" do
490
+ hosts = dsl.roles(:web)
491
+ all = dsl.roles(:all)
492
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
493
+ dsl.set :filter, roles: "web"
494
+ dsl.on(all)
495
+ end
496
+
497
+ it "filters by hosts and roles from the :filter variable" do
498
+ all = dsl.roles(:all)
499
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
500
+ dsl.set :filter, roles: "db", hosts: "example3.com"
501
+ dsl.on(all)
502
+ end
503
+
504
+ it "filters from ENV[ROLES]" do
505
+ hosts = dsl.roles(:db)
506
+ all = dsl.roles(:all)
507
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
508
+ ENV["ROLES"] = "db"
509
+ dsl.on(all)
510
+ end
511
+
512
+ it "filters from ENV[HOSTS]" do
513
+ hosts = dsl.roles(:db)
514
+ all = dsl.roles(:all)
515
+ SSHKit::Coordinator.expects(:new).with(hosts).returns(@coordinator)
516
+ ENV["HOSTS"] = "example5.com"
517
+ dsl.on(all)
518
+ end
519
+
520
+ it "filters by ENV[HOSTS] && ENV[ROLES]" do
521
+ all = dsl.roles(:all)
522
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
523
+ ENV["HOSTS"] = "example5.com"
524
+ ENV["ROLES"] = "web"
525
+ dsl.on(all)
526
+ end
527
+ end
528
+
529
+ describe "when passed server literal names" do
530
+ before do
531
+ ENV.delete "ROLES"
532
+ ENV.delete "HOSTS"
533
+ @coordinator = mock("coordinator")
534
+ @coordinator.expects(:each).returns(nil)
535
+ end
536
+
537
+ it "selects nothing when a role filter is present" do
538
+ dsl.set :filter, role: "web"
539
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
540
+ dsl.on("my.server")
541
+ end
542
+
543
+ it "selects using the string when a host filter is present" do
544
+ dsl.set :filter, host: "server.local"
545
+ SSHKit::Coordinator.expects(:new).with(["server.local"]).returns(@coordinator)
546
+ dsl.on("server.local")
547
+ end
548
+
549
+ it "doesn't select when a host filter is present that doesn't match" do
550
+ dsl.set :filter, host: "ruby.local"
551
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
552
+ dsl.on("server.local")
553
+ end
554
+
555
+ it "selects nothing when a roles filter is present" do
556
+ dsl.set :filter, roles: "web"
557
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
558
+ dsl.on("my.server")
559
+ end
560
+
561
+ it "selects using the string when a hosts filter is present" do
562
+ dsl.set :filter, hosts: "server.local"
563
+ SSHKit::Coordinator.expects(:new).with(["server.local"]).returns(@coordinator)
564
+ dsl.on("server.local")
565
+ end
566
+
567
+ it "doesn't select when a hosts filter is present that doesn't match" do
568
+ dsl.set :filter, hosts: "ruby.local"
569
+ SSHKit::Coordinator.expects(:new).with([]).returns(@coordinator)
570
+ dsl.on("server.local")
571
+ end
572
+ end
573
+ end
574
+
575
+ describe "role_properties()" do
576
+ before do
577
+ dsl.role :redis, %w[example1.com example2.com], redis: { port: 6379, type: :slave }
578
+ dsl.server "example1.com", roles: %w{web}, active: true, web: { port: 80 }
579
+ dsl.server "example2.com", roles: %w{web redis}, web: { port: 81 }, redis: { type: :master }
580
+ dsl.server "example3.com", roles: %w{app}, primary: true
581
+ end
582
+
583
+ it "retrieves properties for a single role as a set" do
584
+ rps = dsl.role_properties(:app)
585
+ expect(rps).to eq(Set[{ hostname: "example3.com", role: :app }])
586
+ end
587
+
588
+ it "retrieves properties for multiple roles as a set" do
589
+ rps = dsl.role_properties(:app, :web)
590
+ expect(rps).to eq(Set[{ hostname: "example3.com", role: :app }, { hostname: "example1.com", role: :web, port: 80 }, { hostname: "example2.com", role: :web, port: 81 }])
591
+ end
592
+
593
+ it "yields the properties for a single role" do
594
+ recipient = mock("recipient")
595
+ recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
596
+ recipient.expects(:doit).with("example2.com", :redis, { port: 6379, type: :master })
597
+ dsl.role_properties(:redis) do |host, role, props|
598
+ recipient.doit(host, role, props)
599
+ end
600
+ end
601
+
602
+ it "yields the properties for multiple roles" do
603
+ recipient = mock("recipient")
604
+ recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
605
+ recipient.expects(:doit).with("example2.com", :redis, { port: 6379, type: :master })
606
+ recipient.expects(:doit).with("example3.com", :app, nil)
607
+ dsl.role_properties(:redis, :app) do |host, role, props|
608
+ recipient.doit(host, role, props)
609
+ end
610
+ end
611
+
612
+ it "yields the merged properties for multiple roles" do
613
+ recipient = mock("recipient")
614
+ recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
615
+ recipient.expects(:doit).with("example2.com", :redis, { port: 6379, type: :master })
616
+ recipient.expects(:doit).with("example1.com", :web, { port: 80 })
617
+ recipient.expects(:doit).with("example2.com", :web, { port: 81 })
618
+ dsl.role_properties(:redis, :web) do |host, role, props|
619
+ recipient.doit(host, role, props)
620
+ end
621
+ end
622
+
623
+ it "honours a property filter before yielding" do
624
+ recipient = mock("recipient")
625
+ recipient.expects(:doit).with("example1.com", :redis, { port: 6379, type: :slave })
626
+ recipient.expects(:doit).with("example1.com", :web, { port: 80 })
627
+ dsl.role_properties(:redis, :web, select: :active) do |host, role, props|
628
+ recipient.doit(host, role, props)
629
+ end
630
+ end
631
+ end
632
+ end
@@ -0,0 +1,5 @@
1
+ require "spec_helper"
2
+ require "support/test_app"
3
+ require "support/matchers"
4
+
5
+ include TestApp
@@ -0,0 +1,60 @@
1
+ require "spec_helper"
2
+
3
+ describe Capistrano::Application do
4
+ it "provides a --trace option which enables SSHKit/NetSSH trace output"
5
+
6
+ it "provides a --format option which enables the choice of output formatting"
7
+
8
+ it "displays documentation URL as help banner", capture_io: true do
9
+ flags "--help", "-h"
10
+ expect($stdout.string.each_line.first).to match(/capistranorb.com/)
11
+ end
12
+
13
+ %w(quiet silent verbose).each do |switch|
14
+ it "doesn't include --#{switch} in help", capture_io: true do
15
+ flags "--help", "-h"
16
+ expect($stdout.string).not_to match(/--#{switch}/)
17
+ end
18
+ end
19
+
20
+ it "overrides the rake method, but still prints the rake version", capture_io: true do
21
+ flags "--version", "-V"
22
+ out = $stdout.string
23
+ expect(out).to match(/\bCapistrano Version\b/)
24
+ expect(out).to match(/\b#{Capistrano::VERSION}\b/)
25
+ expect(out).to match(/\bRake Version\b/)
26
+ expect(out).to match(/\b#{Rake::VERSION}\b/)
27
+ end
28
+
29
+ it "overrides the rake method, and sets the sshkit_backend to SSHKit::Backend::Printer", capture_io: true do
30
+ flags "--dry-run", "-n"
31
+ sshkit_backend = Capistrano::Configuration.fetch(:sshkit_backend)
32
+ expect(sshkit_backend).to eq(SSHKit::Backend::Printer)
33
+ end
34
+
35
+ it "enables printing all config variables on command line parameter", capture_io: true do
36
+ begin
37
+ flags "--print-config-variables", "-p"
38
+ expect(Capistrano::Configuration.fetch(:print_config_variables)).to be true
39
+ ensure
40
+ Capistrano::Configuration.reset!
41
+ end
42
+ end
43
+
44
+ def flags(*sets)
45
+ sets.each do |set|
46
+ ARGV.clear
47
+ @exit = catch(:system_exit) { command_line(*set) }
48
+ end
49
+ yield(subject.options) if block_given?
50
+ end
51
+
52
+ def command_line(*options)
53
+ options.each { |opt| ARGV << opt }
54
+ subject.define_singleton_method(:exit) do |*_args|
55
+ throw(:system_exit, :exit)
56
+ end
57
+ subject.run
58
+ subject.options
59
+ end
60
+ end