deployml 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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: