deployml 0.3.0 → 0.4.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/ChangeLog.md CHANGED
@@ -1,3 +1,29 @@
1
+ ### 0.4.0 / 2010-11-29
2
+
3
+ * Require addressable ~> 2.2.0.
4
+ * Added methods to {DeploYML::Environment} inorder to mirror
5
+ {DeploYML::Project}:
6
+ * `invoke`
7
+ * `setup!`
8
+ * `update!`
9
+ * `install!`
10
+ * `migrate!`
11
+ * `config!`
12
+ * `start!`
13
+ * `stop!`
14
+ * Added {DeploYML::Shell#status} for printing ANSI colored status messages.
15
+ * Added {DeploYML::RemoteShell#uri}.
16
+ * Added {DeploYML::RemoteShell#history}.
17
+ * Added missing documentation.
18
+ * Give the root directory passed to {DeploYML::Project#initialize} the
19
+ default of `Dir.pwd`.
20
+ * If the destination URI has the scheme of `file:`, have
21
+ {DeploYML::Environment#remote_shell} return a {DeploYML::LocalShell}.
22
+ * This should facilitate local deploys.
23
+ * Perform a forced pull in {DeploYML::Environment#update}.
24
+ * Override {DeploYML::Environment#rake} in {DeploYML::Frameworks::Rails}.
25
+ * Escape all arguments of all commands in {DeploYML::RemoteShell#join}.
26
+
1
27
  ### 0.3.0 / 2010-11-21
2
28
 
3
29
  * Initial release:
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  * [Source](http://github.com/postmodern/deployml)
4
4
  * [Issues](http://github.com/postmodern/deployml/issues)
5
+ * [Documentation](http://rubydoc.info/gems/deployml/frames)
5
6
  * Postmodern (postmodern.mod3 at gmail.com)
6
7
 
7
8
  ## Description
@@ -63,6 +64,29 @@ Specifying a `server` with options:
63
64
  socket: /var/run/thin.sock
64
65
  rackup: true
65
66
 
67
+ Multiple environments:
68
+
69
+ # config/deploy.yml
70
+ source: git@github.com:user/project.git
71
+ framework: rails3
72
+ orm: datamapper
73
+
74
+ # config/deploy/staging.yml
75
+ dest: ssh://deploy@www.example.com/srv/staging
76
+ server:
77
+ name: thin
78
+ options:
79
+ config: /etc/thin/staging.yml
80
+ socket: /tmp/thin.staging.sock
81
+
82
+ # config/deploy/production.yml
83
+ dest: ssh://deploy@www.example.com/srv/project
84
+ server:
85
+ name: thin
86
+ options:
87
+ config: /etc/thin/example.yml
88
+ socket: /tmp/thin.example.sock
89
+
66
90
  ## Synopsis
67
91
 
68
92
  Cold-Deploy a new project:
@@ -91,7 +115,7 @@ List available tasks:
91
115
 
92
116
  ## Requirements
93
117
 
94
- * [addressable](http://addressable.rubyforge.org/) ~> 2.1.1
118
+ * [addressable](http://addressable.rubyforge.org/) ~> 2.2.0
95
119
  * [rprogram](http://github.com/postmodern/rprogram) ~> 0.2.0
96
120
  * [thor](http://github.com/wycats/thor) ~> 0.14.3
97
121
 
data/gemspec.yml CHANGED
@@ -11,7 +11,7 @@ homepage: http://github.com/postmodern/deployml
11
11
  has_yard: true
12
12
 
13
13
  dependencies:
14
- addressable: ~> 2.1.1
14
+ addressable: ~> 2.2.0
15
15
  rprogram: ~> 0.2.0
16
16
  thor: ~> 0.14.3
17
17
 
data/lib/deployml/cli.rb CHANGED
@@ -4,31 +4,65 @@ require 'thor'
4
4
  require 'pathname'
5
5
 
6
6
  module DeploYML
7
+ #
8
+ # The command-line interface to {DeploYML} using
9
+ # [Thor](http://github.com/wycats/thor#readme).
10
+ #
7
11
  class CLI < Thor
8
12
 
9
13
  namespace 'deploy'
10
14
 
11
15
  desc 'exec', 'Runs a command on the deploy server'
12
- method_option :environment, :type => :string, :default => 'production'
16
+ method_option :environment, :type => :string,
17
+ :default => 'production',
18
+ :aliases => '-E'
19
+
20
+ #
21
+ # Executes a command in the specified environment.
22
+ #
23
+ # @param [String] command
24
+ # The full command to execute.
25
+ #
13
26
  def exec(command)
14
27
  environment.exec(command)
15
28
  end
16
29
 
17
30
  desc 'rake', 'Executes a rake task on the deploy server'
18
- method_option :environment, :type => :string, :default => 'production'
31
+ method_option :environment, :type => :string,
32
+ :default => 'production',
33
+ :aliases => '-E'
19
34
  method_option :args, :type => :array
35
+
36
+ #
37
+ # Invokes a rake task in the specified environment.
38
+ #
39
+ # @param [String] task
40
+ # The name of the rake task.
41
+ #
20
42
  def rake(task)
21
43
  environment.rake(task,*(options[:args]))
22
44
  end
23
45
 
24
46
  desc 'ssh', 'Starts a SSH session with the deploy server'
25
- method_option :environment, :type => :string, :default => 'production'
47
+ method_option :environment, :type => :string,
48
+ :default => 'production',
49
+ :aliases => '-E'
50
+
51
+ #
52
+ # Starts an SSH session with the specified environment.
53
+ #
26
54
  def ssh
27
55
  environment.ssh
28
56
  end
29
57
 
30
58
  desc 'setup', 'Sets up the deployment repository for the project'
31
- method_option :environment, :type => :string, :default => 'production'
59
+ method_option :environment, :type => :string,
60
+ :default => 'production',
61
+ :aliases => '-E'
62
+
63
+ #
64
+ # Sets up the specified environment.
65
+ #
32
66
  def setup
33
67
  status 'Setting up ...'
34
68
 
@@ -38,7 +72,13 @@ module DeploYML
38
72
  end
39
73
 
40
74
  desc 'update', 'Updates the deployment repository of the project'
41
- method_option :environment, :type => :string, :default => 'production'
75
+ method_option :environment, :type => :string,
76
+ :default => 'production',
77
+ :aliases => '-E'
78
+
79
+ #
80
+ # Updates the deployment repository of the specified environment.
81
+ #
42
82
  def update
43
83
  status 'Updating'
44
84
 
@@ -48,7 +88,13 @@ module DeploYML
48
88
  end
49
89
 
50
90
  desc 'install', 'Installs the project on the deploy server'
51
- method_option :environment, :type => :string, :default => 'production'
91
+ method_option :environment, :type => :string,
92
+ :default => 'production',
93
+ :aliases => '-E'
94
+
95
+ #
96
+ # Installs any needed dependencies in the specified environment.
97
+ #
52
98
  def install
53
99
  status 'Installing ...'
54
100
 
@@ -58,7 +104,13 @@ module DeploYML
58
104
  end
59
105
 
60
106
  desc 'migrate', 'Migrates the database for the project'
61
- method_option :environment, :type => :string, :default => 'production'
107
+ method_option :environment, :type => :string,
108
+ :default => 'production',
109
+ :aliases => '-E'
110
+
111
+ #
112
+ # Migrates the database for the specified environment.
113
+ #
62
114
  def migrate
63
115
  status 'Migrating ...'
64
116
 
@@ -68,7 +120,13 @@ module DeploYML
68
120
  end
69
121
 
70
122
  desc 'config', 'Configures the server for the project'
71
- method_option :environment, :type => :string, :default => 'production'
123
+ method_option :environment, :type => :string,
124
+ :default => 'production',
125
+ :aliases => '-E'
126
+
127
+ #
128
+ # Configures the server for the specified environment.
129
+ #
72
130
  def config
73
131
  status 'Configuring ...'
74
132
 
@@ -78,8 +136,13 @@ module DeploYML
78
136
  end
79
137
 
80
138
  desc 'start', 'Starts the server for the project'
81
- method_option :environment, :type => :string, :default => 'production'
139
+ method_option :environment, :type => :string,
140
+ :default => 'production',
141
+ :aliases => '-E'
82
142
 
143
+ #
144
+ # Starts the server in the specified environment.
145
+ #
83
146
  def start
84
147
  status 'Starting ...'
85
148
 
@@ -89,8 +152,13 @@ module DeploYML
89
152
  end
90
153
 
91
154
  desc 'stop', 'Stops the server for the project'
92
- method_option :environment, :type => :string, :default => 'production'
155
+ method_option :environment, :type => :string,
156
+ :default => 'production',
157
+ :aliases => '-E'
93
158
 
159
+ #
160
+ # Stops the server in the specified environment.
161
+ #
94
162
  def stop
95
163
  status 'Stopping ...'
96
164
 
@@ -100,8 +168,13 @@ module DeploYML
100
168
  end
101
169
 
102
170
  desc 'restart', 'Restarts the server for the project'
103
- method_option :environment, :type => :string, :default => 'production'
171
+ method_option :environment, :type => :string,
172
+ :default => 'production',
173
+ :aliases => '-E'
104
174
 
175
+ #
176
+ # Restarts the server in the specified environment.
177
+ #
105
178
  def restart
106
179
  status 'Restarting ...'
107
180
 
@@ -111,8 +184,13 @@ module DeploYML
111
184
  end
112
185
 
113
186
  desc 'deploy', 'Cold-Deploys a new project'
114
- method_option :environment, :type => :string, :default => 'production'
187
+ method_option :environment, :type => :string,
188
+ :default => 'production',
189
+ :aliases => '-E'
115
190
 
191
+ #
192
+ # Cold-deploys into the specified environment.
193
+ #
116
194
  def deploy
117
195
  status 'Deploying ...'
118
196
 
@@ -122,8 +200,13 @@ module DeploYML
122
200
  end
123
201
 
124
202
  desc 'redeploy', 'Redeploys the project'
125
- method_option :environment, :type => :string, :default => 'production'
203
+ method_option :environment, :type => :string,
204
+ :default => 'production',
205
+ :aliases => '-E'
126
206
 
207
+ #
208
+ # Redeploys into the specified environment.
209
+ #
127
210
  def redeploy
128
211
  status 'Redeploying ...'
129
212
 
@@ -184,6 +267,12 @@ module DeploYML
184
267
  project.environment(options[:environment])
185
268
  end
186
269
 
270
+ #
271
+ # Prints a status message.
272
+ #
273
+ # @param [String] message
274
+ # The message to print.
275
+ #
187
276
  def status(message)
188
277
  shell.say_status "[#{options[:environment]}]", message
189
278
  end
@@ -8,6 +8,10 @@ require 'deployml/servers'
8
8
  require 'deployml/frameworks'
9
9
 
10
10
  module DeploYML
11
+ #
12
+ # Contains environment specific configuration loaded by {Project}
13
+ # from YAML files within `config/deploy/`.
14
+ #
11
15
  class Environment < Configuration
12
16
 
13
17
  # Mapping of possible 'server' names to their mixins.
@@ -82,13 +86,18 @@ module DeploYML
82
86
  # @yieldparam [RemoteShell] shell
83
87
  # The remote shell.
84
88
  #
85
- # @return [RemoteShell]
86
- # The remote shell.
89
+ # @return [RemoteShell, LocalShell]
90
+ # The remote shell. If the destination is a local `file://` URI,
91
+ # a local shell will be returned instead.
87
92
  #
88
93
  # @since 0.3.0
89
94
  #
90
95
  def remote_shell(&block)
91
- RemoteShell.new(@dest,&block)
96
+ unless @dest.scheme == 'file'
97
+ RemoteShell.new(@dest,&block)
98
+ else
99
+ LocalShell.new(&block)
100
+ end
92
101
  end
93
102
 
94
103
  #
@@ -162,7 +171,7 @@ module DeploYML
162
171
  #
163
172
  def update(shell)
164
173
  shell.run 'git', 'reset', '--hard', 'HEAD'
165
- shell.run 'git', 'pull'
174
+ shell.run 'git', 'pull', '-f'
166
175
  end
167
176
 
168
177
  #
@@ -231,6 +240,192 @@ module DeploYML
231
240
  def server_restart(shell)
232
241
  end
233
242
 
243
+ #
244
+ # Deploys the project.
245
+ #
246
+ # @param [Array<Symbol>] tasks
247
+ # The tasks to run during the deployment.
248
+ #
249
+ # @return [true]
250
+ # Indicates that the tasks were successfully completed.
251
+ #
252
+ # @since 0.4.0
253
+ #
254
+ def invoke(tasks)
255
+ remote_shell do |shell|
256
+ # setup the deployment repository
257
+ if tasks.include?(:setup)
258
+ shell.status "Cloning #{@source} ..."
259
+ setup(shell)
260
+ shell.status "Cloned."
261
+ end
262
+
263
+ # cd into the deployment repository
264
+ shell.cd @dest.path
265
+
266
+ # update the deployment repository
267
+ if tasks.include?(:update)
268
+ shell.status "Updating #{@dest.path} ..."
269
+ update(shell)
270
+ shell.status "Updated."
271
+ end
272
+
273
+ # framework tasks
274
+ if tasks.include?(:install)
275
+ shell.status "Installing additional dependencies ..."
276
+ install(shell)
277
+ shell.status "Dependencies installed."
278
+ end
279
+
280
+ if tasks.include?(:migrate)
281
+ shell.status "Migrating database ..."
282
+ migrate(shell)
283
+ shell.status "Database migrated."
284
+ end
285
+
286
+ # server tasks
287
+ if tasks.include?(:config)
288
+ shell.status "Configuring server ..."
289
+ server_config(shell)
290
+ shell.status "Server configured."
291
+ elsif tasks.include?(:start)
292
+ shell.status "Starting server ..."
293
+ server_start(shell)
294
+ shell.status "Server started."
295
+ elsif tasks.include?(:stop)
296
+ shell.status "Stopping server ..."
297
+ server_stop(shell)
298
+ shell.status "Server stopped."
299
+ elsif tasks.include?(:restart)
300
+ shell.status "Restarting server ..."
301
+ server_restart(shell)
302
+ shell.status "Server restarted."
303
+ end
304
+ end
305
+
306
+ return true
307
+ end
308
+
309
+ #
310
+ # Sets up the deployment repository for the project.
311
+ #
312
+ # @return [true]
313
+ # Indicates that the tasks were successfully completed.
314
+ #
315
+ # @since 0.4.0
316
+ #
317
+ def setup!
318
+ invoke [:setup]
319
+ end
320
+
321
+ #
322
+ # Updates the deployed repository of the project.
323
+ #
324
+ # @return [true]
325
+ # Indicates that the tasks were successfully completed.
326
+ #
327
+ # @since 0.4.0
328
+ #
329
+ def update!
330
+ invoke [:update]
331
+ end
332
+
333
+ #
334
+ # Installs the project on the destination server.
335
+ #
336
+ # @return [true]
337
+ # Indicates that the tasks were successfully completed.
338
+ #
339
+ # @since 0.4.0
340
+ #
341
+ def install!
342
+ invoke [:install]
343
+ end
344
+
345
+ #
346
+ # Migrates the database used by the project.
347
+ #
348
+ # @return [true]
349
+ # Indicates that the tasks were successfully completed.
350
+ #
351
+ # @since 0.4.0
352
+ #
353
+ def migrate!
354
+ invoke [:migrate]
355
+ end
356
+
357
+ #
358
+ # Configures the Web server to be ran on the destination server.
359
+ #
360
+ # @return [true]
361
+ # Indicates that the tasks were successfully completed.
362
+ #
363
+ # @since 0.4.0
364
+ #
365
+ def config!
366
+ invoke [:config]
367
+ end
368
+
369
+ #
370
+ # Starts the Web server for the project.
371
+ #
372
+ # @return [true]
373
+ # Indicates that the tasks were successfully completed.
374
+ #
375
+ # @since 0.4.0
376
+ #
377
+ def start!
378
+ invoke [:start]
379
+ end
380
+
381
+ #
382
+ # Stops the Web server for the project.
383
+ #
384
+ # @return [true]
385
+ # Indicates that the tasks were successfully completed.
386
+ #
387
+ # @since 0.4.0
388
+ #
389
+ def stop!
390
+ invoke [:stop]
391
+ end
392
+
393
+ #
394
+ # Restarts the Web server for the project.
395
+ #
396
+ # @return [true]
397
+ # Indicates that the tasks were successfully completed.
398
+ #
399
+ # @since 0.4.0
400
+ #
401
+ def restart!
402
+ invoke [:restart]
403
+ end
404
+
405
+ #
406
+ # Deploys a new project.
407
+ #
408
+ # @return [true]
409
+ # Indicates that the tasks were successfully completed.
410
+ #
411
+ # @since 0.4.0
412
+ #
413
+ def deploy!
414
+ invoke [:setup, :install, :migrate, :config, :start]
415
+ end
416
+
417
+ #
418
+ # Redeploys a project.
419
+ #
420
+ # @return [true]
421
+ # Indicates that the tasks were successfully completed.
422
+ #
423
+ # @since 0.4.0
424
+ #
425
+ def redeploy!
426
+ invoke [:update, :install, :migrate, :restart]
427
+ end
428
+
234
429
  protected
235
430
 
236
431
  #
@@ -0,0 +1,20 @@
1
+ module DeploYML
2
+ module Frameworks
3
+ #
4
+ # Provides common methods needed to deploy Rails 2 and 3 projects.
5
+ #
6
+ module Rails
7
+ #
8
+ # Overrides the default `rake` method to add a `RAILS_ENV`
9
+ # environment variable.
10
+ #
11
+ # @see {Environment#rake}
12
+ #
13
+ def rake(task,*args)
14
+ args += ["RAILS_ENV=#{@environment}"]
15
+
16
+ super(task,*args)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,19 @@
1
+ require 'deployml/frameworks/rails'
2
+
1
3
  module DeploYML
2
4
  module Frameworks
5
+ #
6
+ # Provides methods for deploying Rails 2 projects.
7
+ #
3
8
  module Rails2
9
+ include Rails
10
+
11
+ #
12
+ # Migrates the database using the `db:migrate` task.
13
+ #
14
+ # @param [LocalShell, RemoteShell] shell
15
+ # The shell to execute commands in.
16
+ #
4
17
  def migrate(shell)
5
18
  shell.run 'rake', 'db:migrate', "RAILS_ENV=#{@environment}"
6
19
  end
@@ -1,10 +1,31 @@
1
+ require 'deployml/frameworks/rails'
2
+
1
3
  module DeploYML
2
4
  module Frameworks
5
+ #
6
+ # Provides methods for deploying Rails 3 projects.
7
+ #
3
8
  module Rails3
9
+ include Rails
10
+
11
+ #
12
+ # Installs any dependencies using `bundle install --deployment`.
13
+ #
14
+ # @param [LocalShell, RemoteShell] shell
15
+ # The shell to execute commands in.
16
+ #
4
17
  def install(shell)
5
18
  shell.run 'bundle', 'install', '--deployment'
6
19
  end
7
20
 
21
+ #
22
+ # Migrates the database using the `db:autoupgrade` if
23
+ # [DataMapper](http://datamapper.org) is being used, or the typical
24
+ # `db:migrate` task.
25
+ #
26
+ # @param [LocalShell, RemoteShell] shell
27
+ # The shell to execute commands in.
28
+ #
8
29
  def migrate(shell)
9
30
  task = case @orm
10
31
  when :datamapper
@@ -1,6 +1,9 @@
1
1
  require 'deployml/shell'
2
2
 
3
3
  module DeploYML
4
+ #
5
+ # Represents a shell running on the local system.
6
+ #
4
7
  class LocalShell
5
8
 
6
9
  include Shell
@@ -39,15 +42,7 @@ module DeploYML
39
42
  # the block has returned.
40
43
  #
41
44
  def cd(path,&block)
42
- if block
43
- cwd = Dir.pwd
44
-
45
- Dir.chdir(path)
46
- block.call()
47
- Dir.chdir(cwd)
48
- else
49
- Dir.chdir(path)
50
- end
45
+ Dir.chdir(path,&block)
51
46
  end
52
47
 
53
48
  end
@@ -2,8 +2,12 @@ require 'rprogram/task'
2
2
 
3
3
  module DeploYML
4
4
  module Options
5
+ #
6
+ # Maps in command-line options for the `mongrel_rails` utility.
7
+ #
5
8
  class Mongrel < RProgram::Task
6
9
 
10
+ # Default options for Mongrel
7
11
  DEFAULTS = {
8
12
  :environment => :production,
9
13
  :address => '127.0.0.1',
@@ -2,6 +2,9 @@ require 'rprogram/task'
2
2
 
3
3
  module DeploYML
4
4
  module Options
5
+ #
6
+ # Maps in command-line options for the `thin` utility.
7
+ #
5
8
  class Thin < RProgram::Task
6
9
 
7
10
  # Default options for Thin
@@ -37,7 +37,7 @@ module DeploYML
37
37
  # The configuration file for the project could not be found
38
38
  # in any of the common directories.
39
39
  #
40
- def initialize(root)
40
+ def initialize(root=Dir.pwd)
41
41
  @root = File.expand_path(root)
42
42
  @config_file = File.join(@root,CONFIG_DIR,CONFIG_FILE)
43
43
  @environments_dir = File.join(@root,CONFIG_DIR,ENVIRONMENTS_DIR)
@@ -117,39 +117,12 @@ module DeploYML
117
117
  # The environment to deploy to.
118
118
  #
119
119
  # @return [true]
120
+ # Indicates that the tasks were successfully completed.
120
121
  #
121
122
  # @since 0.2.0
122
123
  #
123
124
  def invoke(tasks,env=:production)
124
- env = environment(env)
125
-
126
- env.remote_shell do |shell|
127
- # setup the deployment repository
128
- env.setup(shell) if tasks.include?(:setup)
129
-
130
- # cd into the deployment repository
131
- shell.cd env.dest.path
132
-
133
- # update the deployment repository
134
- env.update(shell) if tasks.include?(:update)
135
-
136
- # framework tasks
137
- env.install(shell) if tasks.include?(:install)
138
- env.migrate(shell) if tasks.include?(:migrate)
139
-
140
- # server tasks
141
- if tasks.include?(:config)
142
- env.server_config(shell)
143
- elsif tasks.include?(:start)
144
- env.server_start(shell)
145
- elsif tasks.include?(:stop)
146
- env.server_stop(shell)
147
- elsif tasks.include?(:restart)
148
- env.server_restart(shell)
149
- end
150
- end
151
-
152
- return true
125
+ environment(env).invoke(tasks)
153
126
  end
154
127
 
155
128
  #
@@ -158,8 +131,11 @@ module DeploYML
158
131
  # @param [Symbol, String] env
159
132
  # The environment to deploy to.
160
133
  #
134
+ # @return [true]
135
+ # Indicates that the tasks were successfully completed.
136
+ #
161
137
  def setup!(env=:production)
162
- invoke [:setup], env
138
+ environment(env).setup!
163
139
  end
164
140
 
165
141
  #
@@ -168,8 +144,11 @@ module DeploYML
168
144
  # @param [Symbol, String] env
169
145
  # The environment to deploy to.
170
146
  #
147
+ # @return [true]
148
+ # Indicates that the tasks were successfully completed.
149
+ #
171
150
  def update!(env=:production)
172
- invoke [:update], env
151
+ environment(env).update!
173
152
  end
174
153
 
175
154
  #
@@ -178,8 +157,11 @@ module DeploYML
178
157
  # @param [Symbol, String] env
179
158
  # The environment to deploy to.
180
159
  #
160
+ # @return [true]
161
+ # Indicates that the tasks were successfully completed.
162
+ #
181
163
  def install!(env=:production)
182
- invoke [:install], env
164
+ environment(env).install!
183
165
  end
184
166
 
185
167
  #
@@ -188,8 +170,11 @@ module DeploYML
188
170
  # @param [Symbol, String] env
189
171
  # The environment to deploy to.
190
172
  #
173
+ # @return [true]
174
+ # Indicates that the tasks were successfully completed.
175
+ #
191
176
  def migrate!(env=:production)
192
- invoke [:migrate], env
177
+ environment(env).migrate!
193
178
  end
194
179
 
195
180
  #
@@ -198,8 +183,11 @@ module DeploYML
198
183
  # @param [Symbol, String] env
199
184
  # The environment to deploy to.
200
185
  #
186
+ # @return [true]
187
+ # Indicates that the tasks were successfully completed.
188
+ #
201
189
  def config!(env=:production)
202
- invoke [:config], env
190
+ environment(env).config!
203
191
  end
204
192
 
205
193
  #
@@ -208,8 +196,11 @@ module DeploYML
208
196
  # @param [Symbol, String] env
209
197
  # The environment to deploy to.
210
198
  #
199
+ # @return [true]
200
+ # Indicates that the tasks were successfully completed.
201
+ #
211
202
  def start!(env=:production)
212
- invoke [:start], env
203
+ environment(env).start!
213
204
  end
214
205
 
215
206
  #
@@ -218,8 +209,11 @@ module DeploYML
218
209
  # @param [Symbol, String] env
219
210
  # The environment to deploy to.
220
211
  #
212
+ # @return [true]
213
+ # Indicates that the tasks were successfully completed.
214
+ #
221
215
  def stop!(env=:production)
222
- invoke [:stop], env
216
+ environment(env).stop!
223
217
  end
224
218
 
225
219
  #
@@ -228,8 +222,11 @@ module DeploYML
228
222
  # @param [Symbol, String] env
229
223
  # The environment to deploy to.
230
224
  #
225
+ # @return [true]
226
+ # Indicates that the tasks were successfully completed.
227
+ #
231
228
  def restart!(env=:production)
232
- invoke [:restart], env
229
+ environment(env).restart!
233
230
  end
234
231
 
235
232
  #
@@ -238,10 +235,13 @@ module DeploYML
238
235
  # @param [Symbol, String] env
239
236
  # The environment to deploy to.
240
237
  #
238
+ # @return [true]
239
+ # Indicates that the tasks were successfully completed.
240
+ #
241
241
  # @since 0.2.0
242
242
  #
243
243
  def deploy!(env=:production)
244
- invoke [:setup, :install, :migrate, :config, :start], env
244
+ environment(env).deploy!
245
245
  end
246
246
 
247
247
  #
@@ -250,10 +250,13 @@ module DeploYML
250
250
  # @param [Symbol, String] env
251
251
  # The environment to deploy to.
252
252
  #
253
+ # @return [true]
254
+ # Indicates that the tasks were successfully completed.
255
+ #
253
256
  # @since 0.2.0
254
257
  #
255
258
  def redeploy!(env=:production)
256
- invoke [:update, :install, :migrate, :restart], env
259
+ environment(env).redeploy!
257
260
  end
258
261
 
259
262
  protected
@@ -1,9 +1,22 @@
1
1
  require 'deployml/shell'
2
2
 
3
+ require 'addressable/uri'
4
+ require 'shellwords'
5
+
3
6
  module DeploYML
7
+ #
8
+ # Represents a shell running on a remote server.
9
+ #
4
10
  class RemoteShell
5
11
 
6
12
  include Shell
13
+ include Shellwords
14
+
15
+ # The URI of the remote shell
16
+ attr_reader :uri
17
+
18
+ # The history of the Remote Shell
19
+ attr_reader :history
7
20
 
8
21
  #
9
22
  # Initializes a remote shell session.
@@ -51,7 +64,7 @@ module DeploYML
51
64
  # @param [String] message
52
65
  # The message to echo.
53
66
  #
54
- def each(message)
67
+ def echo(message)
55
68
  run 'echo', message
56
69
  end
57
70
 
@@ -65,12 +78,11 @@ module DeploYML
65
78
  # If a block is given, then the directory will be changed back after
66
79
  # the block has returned.
67
80
  #
68
- def cd(path,&block)
81
+ def cd(path)
69
82
  @history << ['cd', path]
70
83
 
71
- if block
72
- block.call() if block
73
-
84
+ if block_given?
85
+ yield
74
86
  @history << ['cd', '-']
75
87
  end
76
88
  end
@@ -83,7 +95,9 @@ module DeploYML
83
95
  # A single command string.
84
96
  #
85
97
  def join
86
- @history.map { |command| command.join(' ') }.join(' && ')
98
+ @history.map { |command|
99
+ command.map { |word| shellescape(word) }.join(' ')
100
+ }.join(' && ')
87
101
  end
88
102
 
89
103
  #
@@ -2,15 +2,37 @@ require 'deployml/exceptions/invalid_config'
2
2
 
3
3
  module DeploYML
4
4
  module Servers
5
+ #
6
+ # Provides methods for starting, stoping and restarting the
7
+ # [Apache](http://httpd.apache.org/) web server.
8
+ #
5
9
  module Apache
10
+ #
11
+ # Starts Apache using the `apachectl start` command.
12
+ #
13
+ # @param [LocalShell, RemoteShell] shell
14
+ # The shell to execute commands in.
15
+ #
6
16
  def server_start(shell)
7
17
  shell.run 'apachectl', 'start'
8
18
  end
9
19
 
20
+ #
21
+ # Restarts Apache using the `apachectl restart` command.
22
+ #
23
+ # @param [LocalShell, RemoteShell] shell
24
+ # The shell to execute commands in.
25
+ #
10
26
  def server_restart(shell)
11
27
  shell.run 'apachectl', 'restart'
12
28
  end
13
29
 
30
+ #
31
+ # Stops Apache using the `apachectl stop` command.
32
+ #
33
+ # @param [LocalShell, RemoteShell] shell
34
+ # The shell to execute commands in.
35
+ #
14
36
  def server_stop(shell)
15
37
  shell.run 'apachectl', 'stop'
16
38
  end
@@ -3,18 +3,44 @@ require 'deployml/options/mongrel'
3
3
 
4
4
  module DeploYML
5
5
  module Servers
6
+ #
7
+ # Provides methods for configuring, starting, stoping and restarting
8
+ # the [Mongrel](https://github.com/fauna/mongrel) web server.
9
+ #
6
10
  module Mongrel
11
+ #
12
+ # Initializes options used when calling `mongrel`.
13
+ #
7
14
  def initialize_server
8
15
  @mongrel = Options::Mongrel.new(@server_options)
9
16
  @mongrel.environment ||= @name
10
17
  end
11
18
 
19
+ #
20
+ # Executes a command via the `mongrel_rails` command.
21
+ #
22
+ # @param [LocalShell, RemoteShell] shell
23
+ # The shell to execute commands in.
24
+ #
25
+ # @param [Array] args
26
+ # Additional arguments to call `mongrel_rails` with.
27
+ #
12
28
  def mongrel_cluster(shell,*args)
13
29
  options = args + ['-c', @mongrel.config]
14
30
 
15
31
  shell.run 'mongrel_rails', *options
16
32
  end
17
33
 
34
+ #
35
+ # Configures Mongrel by calling `mongrel_rails cluster::configure`.
36
+ #
37
+ # @param [LocalShell, RemoteShell] shell
38
+ # The shell to execute commands in.
39
+ #
40
+ # @raise [MissingOption]
41
+ # No `config` option was listed under the `server` option in the
42
+ # `deploy.yml` configuration file.
43
+ #
18
44
  def server_config(shell)
19
45
  unless @mongrel.config
20
46
  raise(MissingOption,"No 'config' option specified under server options",caller)
@@ -25,14 +51,32 @@ module DeploYML
25
51
  shell.run 'mongrel_rails', 'cluster::configure', *options
26
52
  end
27
53
 
54
+ #
55
+ # Starts Mongrel by calling `mongrel_rails cluster::start`.
56
+ #
57
+ # @param [LocalShell, RemoteShell] shell
58
+ # The shell to execute commands in.
59
+ #
28
60
  def server_start(shell)
29
61
  mongrel_cluster 'cluster::start'
30
62
  end
31
63
 
64
+ #
65
+ # Stops Mongrel by calling `mongrel_rails cluster::stop`.
66
+ #
67
+ # @param [LocalShell, RemoteShell] shell
68
+ # The shell to execute commands in.
69
+ #
32
70
  def server_stop(shell)
33
71
  mongrel_cluster 'cluster::stop'
34
72
  end
35
73
 
74
+ #
75
+ # Restarts Mongrel by calling `mongrel_rails cluster::restart`.
76
+ #
77
+ # @param [LocalShell, RemoteShell] shell
78
+ # The shell to execute commands in.
79
+ #
36
80
  def server_restart(shell)
37
81
  mongrel_cluster 'cluster::restart'
38
82
  end
@@ -3,18 +3,44 @@ require 'deployml/options/thin'
3
3
 
4
4
  module DeploYML
5
5
  module Servers
6
+ #
7
+ # Provides methods for configuring, starting, stoping and restarting
8
+ # the [Thin](http://code.macournoyer.com/thin/) web server.
9
+ #
6
10
  module Thin
11
+ #
12
+ # Initializes options used when calling `thin`.
13
+ #
7
14
  def initialize_server
8
15
  @thin = Options::Thin.new(@server_options)
9
16
  @thin.environment ||= @name
10
17
  end
11
18
 
19
+ #
20
+ # Runs a command via the `thin` command.
21
+ #
22
+ # @param [LocalShell, RemoteShell] shell
23
+ # The shell to execute commands in.
24
+ #
25
+ # @param [Array] args
26
+ # Additional arguments to call `thin` with.
27
+ #
12
28
  def thin(shell,*args)
13
29
  options = args + ['-C', @thin.config, '-s', @thin.servers]
14
30
 
15
31
  shell.run 'thin', *options
16
32
  end
17
33
 
34
+ #
35
+ # Configures Thin by calling `thin config`.
36
+ #
37
+ # @param [LocalShell, RemoteShell] shell
38
+ # The shell to execute commands in.
39
+ #
40
+ # @raise [MissingOption]
41
+ # No `config` option was listed under the `server` option in the
42
+ # `deploy.yml` configuration file.
43
+ #
18
44
  def server_config(shell)
19
45
  unless @thin.config
20
46
  raise(MissingOption,"No 'config' option specified under the server options",caller)
@@ -25,14 +51,32 @@ module DeploYML
25
51
  shell.run 'thin', 'config', *options
26
52
  end
27
53
 
54
+ #
55
+ # Starts Thin by calling `thin start`.
56
+ #
57
+ # @param [LocalShell, RemoteShell] shell
58
+ # The shell to execute commands in.
59
+ #
28
60
  def server_start(shell)
29
61
  thin shell, 'start'
30
62
  end
31
63
 
64
+ #
65
+ # Stops Thin by calling `thin stop`.
66
+ #
67
+ # @param [LocalShell, RemoteShell] shell
68
+ # The shell to execute commands in.
69
+ #
32
70
  def server_stop(shell)
33
71
  thin shell, 'stop'
34
72
  end
35
73
 
74
+ #
75
+ # Restarts Thin by calling `thin restart`.
76
+ #
77
+ # @param [LocalShell, RemoteShell] shell
78
+ # The shell to execute commands in.
79
+ #
36
80
  def server_restart(shell)
37
81
  thin shell, 'restart'
38
82
  end
@@ -1,20 +1,15 @@
1
+ require 'thor/shell/color'
2
+
1
3
  module DeploYML
4
+ #
5
+ # Provides common methods used by both {LocalShell} and {RemoteShell}.
6
+ #
2
7
  module Shell
3
8
 
4
- def initialize(&block)
5
- block.call(self) if block
6
- end
9
+ include Thor::Shell
7
10
 
8
- #
9
- # Place-holder method.
10
- #
11
- # @param [String] program
12
- # The name or path of the program to run.
13
- #
14
- # @param [Array<String>] args
15
- # Additional arguments for the program.
16
- #
17
- def run(program,*args)
11
+ def initialize
12
+ yield self if block_given?
18
13
  end
19
14
 
20
15
  #
@@ -30,8 +25,32 @@ module DeploYML
30
25
  run 'rake', rake_task(task,*args)
31
26
  end
32
27
 
28
+ #
29
+ # Prints a status message.
30
+ #
31
+ # @param [String] message
32
+ # The message to print.
33
+ #
34
+ # @since 0.4.0
35
+ #
36
+ def status(message)
37
+ echo "#{Color::GREEN}>>> #{message}#{Color::CLEAR}"
38
+ end
39
+
33
40
  protected
34
41
 
42
+ #
43
+ # Builds a `rake` task name.
44
+ #
45
+ # @param [String, Symbol] name
46
+ # The name of the `rake` task.
47
+ #
48
+ # @param [Array] args
49
+ # Additional arguments to pass to the `rake` task.
50
+ #
51
+ # @param [String]
52
+ # The `rake` task name to be called.
53
+ #
35
54
  def rake_task(name,*args)
36
55
  name = name.to_s
37
56
 
@@ -1,4 +1,4 @@
1
1
  module DeploYML
2
2
  # deploYML version
3
- VERSION = '0.3.0'
3
+ VERSION = '0.4.0'
4
4
  end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'deployml/remote_shell'
3
+
4
+ describe RemoteShell do
5
+ let(:uri) { 'ssh://deploy@www.example.com/path' }
6
+
7
+ subject { RemoteShell.new(uri) }
8
+
9
+ it "should parse the given URI" do
10
+ subject.uri.should be_kind_of(Addressable::URI)
11
+
12
+ subject.uri.user.should == 'deploy'
13
+ subject.uri.host.should == 'www.example.com'
14
+ subject.uri.path.should == '/path'
15
+ end
16
+
17
+ it "should convert normal URIs to SSH URIs" do
18
+ subject.ssh_uri.should == 'deploy@www.example.com'
19
+ end
20
+
21
+ it "should enqueue programs to run" do
22
+ subject.run 'echo', 'one'
23
+ subject.run 'echo', 'two'
24
+
25
+ subject.history[0].should == ['echo', 'one']
26
+ subject.history[1].should == ['echo', 'two']
27
+ end
28
+
29
+ it "should enqueue echo commands" do
30
+ subject.echo 'one'
31
+ subject.echo 'two'
32
+
33
+ subject.history[0].should == ['echo', 'one']
34
+ subject.history[1].should == ['echo', 'two']
35
+ end
36
+
37
+ it "should enqueue directory changes" do
38
+ subject.cd '/other'
39
+
40
+ subject.history[0].should == ['cd', '/other']
41
+ end
42
+
43
+ it "should enqueue temporary directory changes" do
44
+ subject.cd '/other' do
45
+ subject.run 'pwd'
46
+ end
47
+
48
+ subject.history[0].should == ['cd', '/other']
49
+ subject.history[1].should == ['pwd']
50
+ subject.history[2].should == ['cd', '-']
51
+ end
52
+
53
+ it "should join all commands together into one command" do
54
+ subject.run 'echo', 'one'
55
+ subject.run 'echo', 'two'
56
+
57
+ subject.join.should == 'echo one && echo two'
58
+ end
59
+
60
+ it "should escape all command arguments" do
61
+ subject.run 'the program'
62
+ subject.run 'echo', '>>> status'
63
+
64
+ subject.join.should == "the\\ program && echo \\>\\>\\>\\ status"
65
+ end
66
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
7
+ - 4
8
8
  - 0
9
- version: 0.3.0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Postmodern
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-21 00:00:00 -08:00
17
+ date: 2010-11-29 00:00:00 -08:00
18
18
  default_executable: deployml
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -27,9 +27,9 @@ dependencies:
27
27
  - !ruby/object:Gem::Version
28
28
  segments:
29
29
  - 2
30
- - 1
31
- - 1
32
- version: 2.1.1
30
+ - 2
31
+ - 0
32
+ version: 2.2.0
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
35
  - !ruby/object:Gem::Dependency
@@ -139,6 +139,7 @@ files:
139
139
  - lib/deployml/exceptions/unknown_framework.rb
140
140
  - lib/deployml/exceptions/unknown_server.rb
141
141
  - lib/deployml/frameworks.rb
142
+ - lib/deployml/frameworks/rails.rb
142
143
  - lib/deployml/frameworks/rails2.rb
143
144
  - lib/deployml/frameworks/rails3.rb
144
145
  - lib/deployml/local_shell.rb
@@ -167,6 +168,7 @@ files:
167
168
  - spec/helpers/projects/rails/config/deploy/production.yml
168
169
  - spec/helpers/projects/rails/config/deploy/staging.yml
169
170
  - spec/project_spec.rb
171
+ - spec/remote_shell_spec.rb
170
172
  - spec/spec_helper.rb
171
173
  has_rdoc: yard
172
174
  homepage: http://github.com/postmodern/deployml
@@ -201,6 +203,7 @@ signing_key:
201
203
  specification_version: 3
202
204
  summary: A simple deployment solution that works.
203
205
  test_files:
206
+ - spec/remote_shell_spec.rb
204
207
  - spec/project_spec.rb
205
208
  - spec/environment_spec.rb
206
209
  - spec/configuration_spec.rb