deployml 0.4.0 → 0.4.1

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,13 @@
1
+ ### 0.4.1 / 2010-12-08
2
+
3
+ * Added support for Ruby 1.8.6.
4
+ * Added {DeploYML::Configuration#bundler}.
5
+ * Auto-detect usage of [Bundler](http://gembundler.com/) by checking for a
6
+ `Gemfile` in project directories.
7
+ * Fixed a Ruby 1.8.x specific bug where non-Strings were being passed to
8
+ `Kernel.system`.
9
+ * Only print status messages if the mixin is enabled.
10
+
1
11
  ### 0.4.0 / 2010-11-29
2
12
 
3
13
  * Require addressable ~> 2.2.0.
data/README.md CHANGED
@@ -115,6 +115,7 @@ List available tasks:
115
115
 
116
116
  ## Requirements
117
117
 
118
+ * [ruby](http://www.ruby-lang.org/) >= 1.8.6
118
119
  * [addressable](http://addressable.rubyforge.org/) ~> 2.2.0
119
120
  * [rprogram](http://github.com/postmodern/rprogram) ~> 0.2.0
120
121
  * [thor](http://github.com/wycats/thor) ~> 0.14.3
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ rescue LoadError => e
12
12
  end
13
13
 
14
14
  begin
15
- gem 'rspec', '~> 2.1.0'
15
+ gem 'rspec', '~> 2.2.0'
16
16
  require 'rspec/core/rake_task'
17
17
 
18
18
  RSpec::Core::RakeTask.new
data/gemspec.yml CHANGED
@@ -10,6 +10,8 @@ email: postmodern.mod3@gmail.com
10
10
  homepage: http://github.com/postmodern/deployml
11
11
  has_yard: true
12
12
 
13
+ required_ruby_version: >= 1.8.6
14
+
13
15
  dependencies:
14
16
  addressable: ~> 2.2.0
15
17
  rprogram: ~> 0.2.0
@@ -17,5 +19,5 @@ dependencies:
17
19
 
18
20
  development_dependencies:
19
21
  ore-tasks: ~> 0.3.0
20
- rspec: ~> 2.1.0
22
+ rspec: ~> 2.2.0
21
23
  yard: ~> 0.6.0
@@ -24,6 +24,9 @@ module DeploYML
24
24
  # The destination URI to upload the project to.
25
25
  attr_reader :dest
26
26
 
27
+ # Whether the project uses Bundler.
28
+ attr_reader :bundler
29
+
27
30
  # The framework used by the project
28
31
  attr_reader :framework
29
32
 
@@ -48,6 +51,10 @@ module DeploYML
48
51
  # @option config [String, Hash] :dest
49
52
  # The destination URI to upload the project to.
50
53
  #
54
+ # @option config [Boolean] :bundler
55
+ # Specifies whether the projects dependencies are controlled by
56
+ # [Bundler](http://gembundler.com).
57
+ #
51
58
  # @option config [Symbol] :framework
52
59
  # The framework used by the project.
53
60
  #
@@ -70,6 +77,7 @@ module DeploYML
70
77
  @server_name = nil
71
78
  @server_options = {}
72
79
 
80
+ @bundler = false
73
81
  @framework = nil
74
82
  @orm = nil
75
83
 
@@ -78,6 +86,8 @@ module DeploYML
78
86
 
79
87
  config = normalize_hash(config)
80
88
 
89
+ @bundler = config[:bundler]
90
+
81
91
  if config[:framework]
82
92
  @framework = config[:framework].to_sym
83
93
  end
@@ -158,7 +158,11 @@ module DeploYML
158
158
  # @since 0.3.0
159
159
  #
160
160
  def setup(shell)
161
+ shell.status "Cloning #{@source} ..."
162
+
161
163
  shell.run 'git', 'clone', '--depth', 1, @source, @dest.path
164
+
165
+ shell.status "Cloned."
162
166
  end
163
167
 
164
168
  #
@@ -170,12 +174,16 @@ module DeploYML
170
174
  # @since 0.3.0
171
175
  #
172
176
  def update(shell)
177
+ shell.status "Updating #{@dest.path} ..."
178
+
173
179
  shell.run 'git', 'reset', '--hard', 'HEAD'
174
180
  shell.run 'git', 'pull', '-f'
181
+
182
+ shell.status "Updated."
175
183
  end
176
184
 
177
185
  #
178
- # Place-holder method.
186
+ # Installs any additional dependencies.
179
187
  #
180
188
  # @param [RemoteShell] shell
181
189
  # The remote shell to execute commands through.
@@ -183,6 +191,13 @@ module DeploYML
183
191
  # @since 0.3.0
184
192
  #
185
193
  def install(shell)
194
+ if @bundler
195
+ shell.status "Bundling dependencies ..."
196
+
197
+ shell.run 'bundle', 'install', '--deployment'
198
+
199
+ shell.status "Dependencies bundled."
200
+ end
186
201
  end
187
202
 
188
203
  #
@@ -254,52 +269,28 @@ module DeploYML
254
269
  def invoke(tasks)
255
270
  remote_shell do |shell|
256
271
  # setup the deployment repository
257
- if tasks.include?(:setup)
258
- shell.status "Cloning #{@source} ..."
259
- setup(shell)
260
- shell.status "Cloned."
261
- end
272
+ setup(shell) if tasks.include?(:setup)
262
273
 
263
274
  # cd into the deployment repository
264
275
  shell.cd @dest.path
265
276
 
266
277
  # update the deployment repository
267
- if tasks.include?(:update)
268
- shell.status "Updating #{@dest.path} ..."
269
- update(shell)
270
- shell.status "Updated."
271
- end
278
+ update(shell) if tasks.include?(:update)
272
279
 
273
280
  # framework tasks
274
- if tasks.include?(:install)
275
- shell.status "Installing additional dependencies ..."
276
- install(shell)
277
- shell.status "Dependencies installed."
278
- end
281
+ install(shell) if tasks.include?(:install)
279
282
 
280
- if tasks.include?(:migrate)
281
- shell.status "Migrating database ..."
282
- migrate(shell)
283
- shell.status "Database migrated."
284
- end
283
+ migrate(shell) if tasks.include?(:migrate)
285
284
 
286
285
  # server tasks
287
286
  if tasks.include?(:config)
288
- shell.status "Configuring server ..."
289
287
  server_config(shell)
290
- shell.status "Server configured."
291
288
  elsif tasks.include?(:start)
292
- shell.status "Starting server ..."
293
289
  server_start(shell)
294
- shell.status "Server started."
295
290
  elsif tasks.include?(:stop)
296
- shell.status "Stopping server ..."
297
291
  server_stop(shell)
298
- shell.status "Server stopped."
299
292
  elsif tasks.include?(:restart)
300
- shell.status "Restarting server ..."
301
293
  server_restart(shell)
302
- shell.status "Server restarted."
303
294
  end
304
295
  end
305
296
 
@@ -15,7 +15,11 @@ module DeploYML
15
15
  # The shell to execute commands in.
16
16
  #
17
17
  def migrate(shell)
18
+ shell.status "Migrating the ActiveRecord Database ..."
19
+
18
20
  shell.run 'rake', 'db:migrate', "RAILS_ENV=#{@environment}"
21
+
22
+ shell.status "ActiveRecord Database migrated."
19
23
  end
20
24
  end
21
25
  end
@@ -8,16 +8,6 @@ module DeploYML
8
8
  module Rails3
9
9
  include Rails
10
10
 
11
- #
12
- # Installs any dependencies using `bundle install --deployment`.
13
- #
14
- # @param [LocalShell, RemoteShell] shell
15
- # The shell to execute commands in.
16
- #
17
- def install(shell)
18
- shell.run 'bundle', 'install', '--deployment'
19
- end
20
-
21
11
  #
22
12
  # Migrates the database using the `db:autoupgrade` if
23
13
  # [DataMapper](http://datamapper.org) is being used, or the typical
@@ -27,14 +17,16 @@ module DeploYML
27
17
  # The shell to execute commands in.
28
18
  #
29
19
  def migrate(shell)
30
- task = case @orm
31
- when :datamapper
32
- 'db:autoupgrade'
33
- else
34
- 'db:migrate'
35
- end
20
+ case @orm
21
+ when :datamapper
22
+ shell.status "Running DataMapper auto-upgrades ..."
23
+ shell.run 'rake', 'db:autoupgrade', "RAILS_ENV=#{@environment}"
24
+ else
25
+ shell.status "Running ActiveRecord migrations ..."
26
+ shell.run 'rake', 'db:migrate', "RAILS_ENV=#{@environment}"
27
+ end
36
28
 
37
- shell.run 'rake', task, "RAILS_ENV=#{@environment}"
29
+ shell.status "Database migrated."
38
30
  end
39
31
  end
40
32
  end
@@ -18,6 +18,9 @@ module DeploYML
18
18
  # Additional arguments for the program.
19
19
  #
20
20
  def run(program,*args)
21
+ program = program.to_s
22
+ args = args.map { |arg| arg.to_s }
23
+
21
24
  system(program,*args)
22
25
  end
23
26
 
@@ -262,41 +262,68 @@ module DeploYML
262
262
  protected
263
263
 
264
264
  #
265
- # Loads the project configuration.
265
+ # Infers the configuration from the project root directory.
266
266
  #
267
- # @raise [InvalidConfig]
268
- # The YAML configuration file did not contain a Hash.
267
+ # @return [Hash{Symbol => Object}]
268
+ # The infered configuration.
269
269
  #
270
- # @raise [MissingOption]
271
- # The `source` or `dest` options were not specified.
270
+ # @since 0.4.1
272
271
  #
273
- # @since 0.3.0
272
+ def infer_configuration
273
+ config = {}
274
+
275
+ # check for Bundler
276
+ if File.file?(File.join(@root,'Gemfile'))
277
+ config[:bundler] = true
278
+ end
279
+
280
+ return config
281
+ end
282
+
274
283
  #
275
- def load_environments!
276
- base_config = {}
284
+ # Loads configuration from a YAML file.
285
+ #
286
+ # @param [String] path
287
+ # The path to the configuration file.
288
+ #
289
+ # @return [Hash]
290
+ # The loaded configuration.
291
+ #
292
+ # @raise [InvalidConfig]
293
+ # The configuration file did not contain a YAML Hash.
294
+ #
295
+ # @since 0.4.1
296
+ #
297
+ def load_configuration(path)
298
+ config = YAML.load_file(path)
277
299
 
278
- load_config_data = lambda { |path|
279
- config_data = YAML.load_file(path)
300
+ unless config.kind_of?(Hash)
301
+ raise(InvalidConfig,"DeploYML file #{path.dump} does not contain a Hash")
302
+ end
280
303
 
281
- unless config_data.kind_of?(Hash)
282
- raise(InvalidConfig,"DeploYML file '#{path}' does not contain a Hash")
283
- end
304
+ return config
305
+ end
284
306
 
285
- config_data
286
- }
307
+ #
308
+ # Loads the project configuration.
309
+ #
310
+ # @since 0.3.0
311
+ #
312
+ def load_environments!
313
+ base_config = infer_configuration
287
314
 
288
315
  if File.file?(@config_file)
289
- base_config.merge!(load_config_data[@config_file])
316
+ base_config.merge!(load_configuration(@config_file))
290
317
  end
291
318
 
292
319
  @environments = {}
293
320
 
294
321
  if File.directory?(@environments_dir)
295
322
  Dir.glob(File.join(@environments_dir,'*.yml')) do |path|
296
- config_data = base_config.merge(load_config_data[path])
323
+ config = base_config.merge(load_configuration(path))
297
324
  name = File.basename(path).sub(/\.yml$/,'').to_sym
298
325
 
299
- @environments[name] = Environment.new(name,config_data)
326
+ @environments[name] = Environment.new(name,config)
300
327
  end
301
328
  else
302
329
  @environments[:production] = Environment.new(:production,base_config)
@@ -1,7 +1,6 @@
1
1
  require 'deployml/shell'
2
2
 
3
3
  require 'addressable/uri'
4
- require 'shellwords'
5
4
 
6
5
  module DeploYML
7
6
  #
@@ -10,7 +9,6 @@ module DeploYML
10
9
  class RemoteShell
11
10
 
12
11
  include Shell
13
- include Shellwords
14
12
 
15
13
  # The URI of the remote shell
16
14
  attr_reader :uri
@@ -96,7 +94,7 @@ module DeploYML
96
94
  #
97
95
  def join
98
96
  @history.map { |command|
99
- command.map { |word| shellescape(word) }.join(' ')
97
+ command.map { |word| shellescape(word.to_s) }.join(' ')
100
98
  }.join(' && ')
101
99
  end
102
100
 
@@ -127,8 +125,11 @@ module DeploYML
127
125
  options += ['-p', @uri.port.to_s]
128
126
  end
129
127
 
128
+ # append the SSH URI
130
129
  options << ssh_uri
131
- options += args
130
+
131
+ # append the additional arguments
132
+ args.each { |arg| options << arg.to_s }
132
133
 
133
134
  return system('ssh',*options)
134
135
  end
@@ -140,5 +141,44 @@ module DeploYML
140
141
  ssh(self.join) unless @history.empty?
141
142
  end
142
143
 
144
+ protected
145
+
146
+ #
147
+ # Escapes a string so that it can be safely used in a Bourne shell
148
+ # command line.
149
+ #
150
+ # Note that a resulted string should be used unquoted and is not
151
+ # intended for use in double quotes nor in single quotes.
152
+ #
153
+ # @param [String] str
154
+ # The string to escape.
155
+ #
156
+ # @return [String]
157
+ # The shell-escaped string.
158
+ #
159
+ # @example
160
+ # open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
161
+ # # ...
162
+ # }
163
+ #
164
+ # @note Vendored from `shellwords.rb` line 72 from Ruby 1.9.2.
165
+ #
166
+ def shellescape(str)
167
+ # An empty argument will be skipped, so return empty quotes.
168
+ return "''" if str.empty?
169
+
170
+ str = str.dup
171
+
172
+ # Process as a single byte sequence because not all shell
173
+ # implementations are multibyte aware.
174
+ str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
175
+
176
+ # A LF cannot be escaped with a backslash because a backslash + LF
177
+ # combo is regarded as line continuation and simply ignored.
178
+ str.gsub!(/\n/, "'\n'")
179
+
180
+ return str
181
+ end
182
+
143
183
  end
144
184
  end
@@ -14,7 +14,11 @@ module DeploYML
14
14
  # The shell to execute commands in.
15
15
  #
16
16
  def server_start(shell)
17
+ shell.status "Starting Apache ..."
18
+
17
19
  shell.run 'apachectl', 'start'
20
+
21
+ shell.status "Apache started."
18
22
  end
19
23
 
20
24
  #
@@ -24,7 +28,11 @@ module DeploYML
24
28
  # The shell to execute commands in.
25
29
  #
26
30
  def server_restart(shell)
31
+ shell.status "Restarting Apache ..."
32
+
27
33
  shell.run 'apachectl', 'restart'
34
+
35
+ shell.status "Apache restarted."
28
36
  end
29
37
 
30
38
  #
@@ -34,7 +42,11 @@ module DeploYML
34
42
  # The shell to execute commands in.
35
43
  #
36
44
  def server_stop(shell)
45
+ shell.status "Stopping Apache ..."
46
+
37
47
  shell.run 'apachectl', 'stop'
48
+
49
+ shell.status "Apache stoped."
38
50
  end
39
51
  end
40
52
  end
@@ -46,9 +46,12 @@ module DeploYML
46
46
  raise(MissingOption,"No 'config' option specified under server options",caller)
47
47
  end
48
48
 
49
- options = ['-c', dest.path] + @mongrel.arguments
49
+ shell.status "Configuring Mongrel ..."
50
50
 
51
+ options = ['-c', dest.path] + @mongrel.arguments
51
52
  shell.run 'mongrel_rails', 'cluster::configure', *options
53
+
54
+ shell.status "Mongrel configured."
52
55
  end
53
56
 
54
57
  #
@@ -58,7 +61,11 @@ module DeploYML
58
61
  # The shell to execute commands in.
59
62
  #
60
63
  def server_start(shell)
64
+ shell.status "Starting Mongrel(s) ..."
65
+
61
66
  mongrel_cluster 'cluster::start'
67
+
68
+ shell.status "Mongrel(s) started."
62
69
  end
63
70
 
64
71
  #
@@ -68,7 +75,11 @@ module DeploYML
68
75
  # The shell to execute commands in.
69
76
  #
70
77
  def server_stop(shell)
78
+ shell.status "Stopping Mongrel(s) ..."
79
+
71
80
  mongrel_cluster 'cluster::stop'
81
+
82
+ shell.status "Mongrel(s) stopped."
72
83
  end
73
84
 
74
85
  #
@@ -78,7 +89,11 @@ module DeploYML
78
89
  # The shell to execute commands in.
79
90
  #
80
91
  def server_restart(shell)
92
+ shell.status "Restarting Mongrel(s) ..."
93
+
81
94
  mongrel_cluster 'cluster::restart'
95
+
96
+ shell.status "Mongrel(s) restarted."
82
97
  end
83
98
  end
84
99
  end
@@ -46,9 +46,12 @@ module DeploYML
46
46
  raise(MissingOption,"No 'config' option specified under the server options",caller)
47
47
  end
48
48
 
49
- options = ['-c', dest.path] + @thin.arguments
49
+ shell.status "Configuring Thin ..."
50
50
 
51
+ options = ['-c', dest.path] + @thin.arguments
51
52
  shell.run 'thin', 'config', *options
53
+
54
+ shell.status "Thin configured."
52
55
  end
53
56
 
54
57
  #
@@ -58,7 +61,11 @@ module DeploYML
58
61
  # The shell to execute commands in.
59
62
  #
60
63
  def server_start(shell)
64
+ shell.status "Starting Thin ..."
65
+
61
66
  thin shell, 'start'
67
+
68
+ shell.status "Thin started."
62
69
  end
63
70
 
64
71
  #
@@ -68,7 +75,11 @@ module DeploYML
68
75
  # The shell to execute commands in.
69
76
  #
70
77
  def server_stop(shell)
78
+ shell.status "Stopping Thin ..."
79
+
71
80
  thin shell, 'stop'
81
+
82
+ shell.status "Thin stopped."
72
83
  end
73
84
 
74
85
  #
@@ -78,7 +89,11 @@ module DeploYML
78
89
  # The shell to execute commands in.
79
90
  #
80
91
  def server_restart(shell)
92
+ shell.status "Restarting Thin ..."
93
+
81
94
  thin shell, 'restart'
95
+
96
+ shell.status "Thin restarted."
82
97
  end
83
98
  end
84
99
  end
@@ -1,4 +1,4 @@
1
1
  module DeploYML
2
2
  # deploYML version
3
- VERSION = '0.4.0'
3
+ VERSION = '0.4.1'
4
4
  end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
-
3
- gem 'rspec', '~> 2.1.0'
2
+ gem 'rspec', '~> 2.2.0'
4
3
  require 'rspec'
5
4
 
6
5
  require 'deployml/version'
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 4
8
- - 0
9
- version: 0.4.0
8
+ - 1
9
+ version: 0.4.1
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-29 00:00:00 -08:00
17
+ date: 2010-12-08 00:00:00 -08:00
18
18
  default_executable: deployml
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -87,9 +87,9 @@ dependencies:
87
87
  - !ruby/object:Gem::Version
88
88
  segments:
89
89
  - 2
90
- - 1
90
+ - 2
91
91
  - 0
92
- version: 2.1.0
92
+ version: 2.2.0
93
93
  type: :development
94
94
  version_requirements: *id005
95
95
  - !ruby/object:Gem::Dependency
@@ -185,8 +185,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
185
185
  - - ">="
186
186
  - !ruby/object:Gem::Version
187
187
  segments:
188
- - 0
189
- version: "0"
188
+ - 1
189
+ - 8
190
+ - 6
191
+ version: 1.8.6
190
192
  required_rubygems_version: !ruby/object:Gem::Requirement
191
193
  none: false
192
194
  requirements: