shuttle-deploy 0.2.0.beta1 → 0.2.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZTM3MDZmNjBlN2EzYTRkZmRlNDc5OTk1ZWM5MGU0MzhmMGVhZTg2Mg==
4
+ ODM5ZTBlNTBhMjQ3OGVhYzVjMGUyN2M5YzY2OGYxOTdmMTM3OWViOQ==
5
5
  data.tar.gz: !binary |-
6
- NGRkOTVmY2IzYzU3MDZmMTRmNWQ1YzE3MTYzMjk4NGFlZjc4NzdkNQ==
6
+ YjYxYzQyYzY2Y2U5OWQ3MzMyNGU1MTM5ZDgxZDQzMzFhZDUwNTUwMw==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZjBhNjhmOGQyNjNjMTA3MDJjNzM3MjcxOTBhMjIzMmJmYmU2YTk2ZmI0MjMz
10
- MDM0MTc5YzMwZjlmMTQxNTdmNGQyZjJhOTdlYjRkMWY5ODUwMDJhYjY2MDY5
11
- ZjRmYTczN2VhOGYyNjNiNGY5OTc2ZWQ3YWQ0YTI3MDE2MGI1ZjM=
9
+ ZDc0MzdhNWMxNmRkZThiYWE2OGU1NmM5YmI5ZjRmMmYwZTQ0NTZlMzJjNmE3
10
+ MGRhNzNkMzFjODk1MjhhMWMxNzMxMjUwODk2N2MyZTE0YmI4OGUyZDdmNzhh
11
+ YzQ0NWQ4M2Q3ZDY4YWIzNjdlY2JlOTFlZDJkNWU0NjFhZGJlZjc=
12
12
  data.tar.gz: !binary |-
13
- M2RkNzViNGNlZmY2ZWRjMTczOTVhNWFkNmYyMmRiZjQ3ZTE4NmNjNzViNWM3
14
- YTVjMGI5ZjViYzhiNjQ0MzUwOGRhZDFlMDFlZmM0MDNiNTJjZGFiZGViMWE4
15
- NTA4MTQyMTI4MGZmOGQ1YTYyMjI4ODVmNGYyMzJkNzE0MDAwNjg=
13
+ ODYzNTI5MDJiNzdjODZkZmIxMzgyM2M4M2JlYzAzNmJlYjMwMTkzZjFjMzE1
14
+ YmRlOTg0NWU1NzIzZjZhMTZlYjIxYzQxODA1YTQ5NTE4M2RlNjAzYWE5MmQ5
15
+ MWE1MDMzOTczMzNlMjkwMzFkOGZiZDI4MjNlYWI1NWQ0NGIwNjU=
data/README.md CHANGED
@@ -8,7 +8,13 @@ Operations are performed on SSH connection with target server.
8
8
 
9
9
  ## Install
10
10
 
11
- Clone repository and run:
11
+ Install from Rubygems:
12
+
13
+ ```
14
+ gem install shuttle-deploy
15
+ ```
16
+
17
+ Or install manually (clone repo first):
12
18
 
13
19
  ```
14
20
  rake install
@@ -42,16 +48,15 @@ Shared directory structure:
42
48
 
43
49
  ## Process
44
50
 
45
- Deployment flow is split into steps:
51
+ Deployment flow consists of steps:
46
52
 
47
- - Establish connection with target server
48
- - Prepare application structure. It'll create all required directories or skip if they already exist.
49
- - Clone repository or check out latest code. Submodules will be automatically updated as well.
50
- - Switch to specified branch (`master` by default)
51
- - Create a new release directory and checkout application code
52
- - Perform strategy-related tasks.
53
- - Create a symbolic link to the latest release
54
- - Clean up old releases (default count: 5)
53
+ - Connect to remote server
54
+ - Prepare application structure (releases, shared dirs, etc)
55
+ - Clone or update git/svn repository code from specified branch
56
+ - Create a new release and checkout application code
57
+ - Perform strategy-defined tasks
58
+ - Make new release current
59
+ - Cleanup old releases
55
60
 
56
61
  ## Strategies
57
62
 
@@ -71,7 +76,6 @@ Example configuration:
71
76
  ```yaml
72
77
  app:
73
78
  name: my-application
74
- strategy: static
75
79
  git: git@github.com:my-site.git
76
80
 
77
81
  target:
@@ -81,11 +85,55 @@ target:
81
85
  deploy_to: /home/deployer/www
82
86
  ```
83
87
 
84
- ### Wordpress Strategy
88
+ ### WordPress Strategy
85
89
 
86
90
  This strategy is designed to deploy wordpress sites developed as a separate theme.
87
91
  It requires `subversion` installed on the server (will be automatically installed).
88
92
 
93
+ ### Rails Strategy
94
+
95
+ Rails deployment strategy will deploy your basic application: install dependencies,
96
+ migrate database, precompile assets and start web server. Most of the steps are automatic.
97
+
98
+ Define strategy first:
99
+
100
+ ```yml
101
+ app:
102
+ name: myapp
103
+ strategy: rails
104
+ ```
105
+
106
+ Then add a separate section:
107
+
108
+ ```yml
109
+ rails:
110
+ environment: production
111
+ precompile_assets: true
112
+ start_server: true
113
+ ```
114
+
115
+ If using `start_server`, shuttle will try to start thin server.
116
+ You can modify settings for thin:
117
+
118
+ ```yml
119
+ thin:
120
+ host: 127.0.0.1
121
+ port: 9000
122
+ servers: 5
123
+ ```
124
+
125
+ You can also use `foreman` to run application:
126
+
127
+ ```yml
128
+ rails:
129
+ start_server: false
130
+
131
+ hooks:
132
+ before_link_release:
133
+ - "sudo bundle exec foreman export upstart /etc/init -a $DEPLOY_APP -u $DEPLOY_USER -p 9000 -l $DEPLOY_SHARED_PATH/log"
134
+ - "sudo start $DEPLOY_APP || sudo restart $DEPLOY_APP"
135
+ ```
136
+
89
137
  ## Deployment Config
90
138
 
91
139
  Deployment config has a few main sections: `app` and `target`.
@@ -158,6 +206,27 @@ targets:
158
206
  deploy_to: /home/staging/myapp
159
207
  ```
160
208
 
209
+ ### Deployment environment
210
+
211
+ During deployment shuttle sets a few environment variables:
212
+
213
+ - `DEPLOY_APP` - Application name
214
+ - `DEPLOY_USER` - Current deployment user
215
+ - `DEPLOY_PATH` - Path to application releases
216
+ - `DEPLOY_RELEASE` - New release number
217
+ - `DEPLOY_RELEASE_PATH` - Path to currently executing release
218
+ - `DEPLOY_CURRENT_PATH` - Path to current release (symlinked)
219
+ - `DEPLOY_SHARED_PATH` - Path to shared resources
220
+ - `DEPLOY_SCM_PATH` - Path to code repository
221
+
222
+ These could be used in hooks. Example:
223
+
224
+ ```
225
+ hooks:
226
+ before_link_release:
227
+ - "cp $DEPLOY_SHARED_PATH/myconfig $DEPLOY_RELEASE_PATH/myconfig"
228
+ ```
229
+
161
230
  ## Usage
162
231
 
163
232
  To execute a new deploy, simply type (in your project folder):
@@ -177,7 +246,6 @@ Shuttle v0.2.0
177
246
  -----> Using branch 'master'
178
247
  -----> Linking release
179
248
  -----> Release v35 has been deployed
180
- -----> Cleaning up old releases: 1
181
249
 
182
250
  Execution time: 2s
183
251
  ```
@@ -227,4 +295,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
227
295
  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
228
296
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
229
297
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
230
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
298
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,7 +1,7 @@
1
1
  module Shuttle
2
2
  class Deploy
3
- include Shuttle::Tasks
4
3
  include Shuttle::Helpers
4
+ include Shuttle::PathHelpers
5
5
 
6
6
  attr_reader :ssh
7
7
  attr_reader :target
@@ -22,37 +22,5 @@ module Shuttle
22
22
  @version = 1
23
23
  end
24
24
  end
25
-
26
- def deploy_path(path=nil)
27
- [target.deploy_to, path].compact.join('/')
28
- end
29
-
30
- def shared_path(path=nil)
31
- [deploy_path, 'shared', path].compact.join('/')
32
- end
33
-
34
- def current_path(path=nil)
35
- [deploy_path, 'current', path].compact.join('/')
36
- end
37
-
38
- def version_path
39
- deploy_path('version')
40
- end
41
-
42
- def release_path(path=nil)
43
- [deploy_path, 'releases', version, path].compact.join('/')
44
- end
45
-
46
- def scm_path
47
- deploy_path('scm')
48
- end
49
-
50
- def deploy
51
- setup
52
- update_code
53
- checkout_code
54
- link_release
55
- cleanup_releases
56
- end
57
25
  end
58
26
  end
@@ -1,5 +1,5 @@
1
1
  module Shuttle
2
- class Nodejs < Shuttle::Deploy
2
+ class Nodejs < Shuttle::Strategy
3
3
  def setup
4
4
  if node_installed?
5
5
  log "Using Node.js v#{node_version}, Npm v#{npm_version}"
@@ -1,5 +1,5 @@
1
1
  module Shuttle
2
- class Php < Shuttle::Deploy
2
+ class Php < Shuttle::Strategy
3
3
  def setup
4
4
  unless php_installed?
5
5
  error "Please install PHP first"
@@ -1,5 +1,5 @@
1
1
  module Shuttle
2
- class Rails < Shuttle::Deploy
2
+ class Rails < Shuttle::Strategy
3
3
  include Shuttle::Support::Bundler
4
4
  include Shuttle::Support::Thin
5
5
 
@@ -1,5 +1,5 @@
1
1
  module Shuttle
2
- class Ruby < Shuttle::Deploy
2
+ class Ruby < Shuttle::Strategy
3
3
  include Shuttle::Support::Bundler
4
4
  include Shuttle::Support::Thin
5
5
 
@@ -1,5 +1,5 @@
1
1
  module Shuttle
2
- class Static < Shuttle::Deploy
2
+ class Static < Shuttle::Strategy
3
3
  # Does not implement any custom functionality
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Shuttle
2
2
  class Error < StandardError ; end
3
- class ConfigError < Error ; end
4
- class DeployError < Error ; end
3
+ class ConfigError < Error ; end
4
+ class DeployError < Error ; end
5
5
  end
@@ -0,0 +1,39 @@
1
+ module Shuttle
2
+ module PathHelpers
3
+ # Get deployment root path, everything is based from here
4
+ # @return [String]
5
+ def deploy_path(path=nil)
6
+ [target.deploy_to, path].compact.join('/')
7
+ end
8
+
9
+ # Get shared path between releases
10
+ # @return [String]
11
+ def shared_path(path=nil)
12
+ [deploy_path, 'shared', path].compact.join('/')
13
+ end
14
+
15
+ # Get path to currently used release
16
+ # @return [String]
17
+ def release_path(path=nil)
18
+ [deploy_path, 'releases', version, path].compact.join('/')
19
+ end
20
+
21
+ # Get current release (symlinked) path
22
+ # @return [String]
23
+ def current_path(path=nil)
24
+ [deploy_path, 'current', path].compact.join('/')
25
+ end
26
+
27
+ # Get path to release version file
28
+ # @return [String]
29
+ def version_path
30
+ deploy_path('version')
31
+ end
32
+
33
+ # Get path to where repository code is stored
34
+ # @return [String]
35
+ def scm_path
36
+ deploy_path('scm')
37
+ end
38
+ end
39
+ end
@@ -1,7 +1,7 @@
1
1
  require 'uri'
2
2
 
3
3
  module Shuttle
4
- module Tasks
4
+ class Strategy < Shuttle::Deploy
5
5
  def setup
6
6
  log "Preparing application structure"
7
7
 
@@ -9,7 +9,6 @@ module Shuttle
9
9
 
10
10
  ssh.run "mkdir -p #{deploy_path}"
11
11
  ssh.run "mkdir -p #{deploy_path('releases')}"
12
- ssh.run "mkdir -p #{deploy_path('backups')}"
13
12
  ssh.run "mkdir -p #{deploy_path('shared')}"
14
13
  ssh.run "mkdir -p #{shared_path('tmp')}"
15
14
  ssh.run "mkdir -p #{shared_path('pids')}"
@@ -26,10 +25,6 @@ module Shuttle
26
25
  cleanup_releases
27
26
  end
28
27
 
29
- def keep_releases
30
- config.app.keep_releases || 10
31
- end
32
-
33
28
  def update_code
34
29
  if config.app.svn
35
30
  return update_code_svn
@@ -153,8 +148,8 @@ module Shuttle
153
148
 
154
149
  log "Release v#{version} has been deployed"
155
150
 
156
- # Execute after link_release hook
157
- execute_hook(:after_link_release)
151
+ # Execute after link_release hook, allow failures here
152
+ execute_hook(:after_link_release, true)
158
153
  end
159
154
 
160
155
  def write_lock
@@ -182,7 +177,7 @@ module Shuttle
182
177
  num = Integer(count) - Integer(keep_releases)
183
178
 
184
179
  if num > 0
185
- log "Cleaning up old releases: #{num}"
180
+ log "Cleaning up old releases: #{num}" if num > 1
186
181
 
187
182
  ssh.run("remove=$((count > #{keep_releases} ? count - #{keep_releases} : 0))")
188
183
  ssh.run("ls -1d [0-9]* | sort -rn | tail -n $remove | xargs rm -rf {}")
@@ -208,9 +203,11 @@ module Shuttle
208
203
 
209
204
  def export_environment
210
205
  ssh.export_hash(
206
+ 'DEPLOY_APP' => config.app.name,
211
207
  'DEPLOY_APPLICATION' => config.app.name,
212
208
  'DEPLOY_USER' => target.user,
213
209
  'DEPLOY_PATH' => deploy_path,
210
+ 'DEPLOY_RELEASE' => version,
214
211
  'DEPLOY_RELEASE_PATH' => release_path,
215
212
  'DEPLOY_CURRENT_PATH' => current_path,
216
213
  'DEPLOY_SHARED_PATH' => shared_path,
@@ -226,9 +223,9 @@ module Shuttle
226
223
  end
227
224
  end
228
225
 
229
- def execute_hook(name)
226
+ def execute_hook(name, allow_failures=false)
230
227
  if config.hooks && config.hooks[name]
231
- execute_commands(config.hooks[name])
228
+ execute_commands(config.hooks[name], allow_failures)
232
229
  end
233
230
  end
234
231
 
@@ -240,12 +237,16 @@ module Shuttle
240
237
  exec("ssh #{target.user}@#{target.host}")
241
238
  end
242
239
 
240
+ def keep_releases
241
+ config.app.keep_releases || 10
242
+ end
243
+
243
244
  def changes_at?(path)
244
245
  result = ssh.run(%{diff -r #{current_path}/#{path} #{release_path}/#{path} 2>/dev/null})
245
246
  result.success? ? false : true
246
247
  end
247
248
 
248
- def execute_commands(commands=[])
249
+ def execute_commands(commands=[], allow_failures=false)
249
250
  commands.flatten.compact.uniq.each do |cmd|
250
251
  log %{Executing "#{cmd.strip}"}
251
252
  command = cmd
@@ -253,7 +254,7 @@ module Shuttle
253
254
 
254
255
  result = ssh.run(command)
255
256
 
256
- if result.failure?
257
+ if result.failure? && allow_failures == false
257
258
  error "Failed: #{result.output}"
258
259
  else
259
260
  stream_output(result.output)
@@ -261,4 +262,4 @@ module Shuttle
261
262
  end
262
263
  end
263
264
  end
264
- end
265
+ end
@@ -15,8 +15,8 @@ module Shuttle
15
15
  end
16
16
 
17
17
  def validate!
18
- raise Shuttle::ConfigError, "Host required" if host.nil?
19
- raise Shuttle::ConfigError, "User required" if user.nil?
18
+ raise Shuttle::ConfigError, "Host required" if host.nil?
19
+ raise Shuttle::ConfigError, "User required" if user.nil?
20
20
  raise Shuttle::ConfigError, "Deploy path required" if deploy_to.nil?
21
21
  end
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module Shuttle
2
- VERSION = '0.2.0.beta1'
2
+ VERSION = '0.2.0.beta2'
3
3
  end
data/lib/shuttle.rb CHANGED
@@ -13,23 +13,24 @@ require 'shuttle/version'
13
13
  require 'shuttle/errors'
14
14
 
15
15
  module Shuttle
16
- autoload :Session, 'shuttle/session'
17
- autoload :Runner, 'shuttle/runner'
18
- autoload :Deploy, 'shuttle/deploy'
19
- autoload :Tasks, 'shuttle/tasks'
20
- autoload :Target, 'shuttle/target'
21
- autoload :Helpers, 'shuttle/helpers'
16
+ autoload :Session, 'shuttle/session'
17
+ autoload :Runner, 'shuttle/runner'
18
+ autoload :Deploy, 'shuttle/deploy'
19
+ autoload :Target, 'shuttle/target'
20
+ autoload :Helpers, 'shuttle/helpers'
21
+ autoload :PathHelpers, 'shuttle/path_helpers'
22
+ autoload :Strategy, 'shuttle/strategy'
22
23
 
23
- autoload :Static, 'shuttle/deployment/static'
24
- autoload :Php, 'shuttle/deployment/php'
25
- autoload :Wordpress, 'shuttle/deployment/wordpress'
26
- autoload :Ruby, 'shuttle/deployment/ruby'
27
- autoload :Rails, 'shuttle/deployment/rails'
28
- autoload :Nodejs, 'shuttle/deployment/nodejs'
24
+ autoload :Static, 'shuttle/deployment/static'
25
+ autoload :Php, 'shuttle/deployment/php'
26
+ autoload :Wordpress, 'shuttle/deployment/wordpress'
27
+ autoload :Ruby, 'shuttle/deployment/ruby'
28
+ autoload :Rails, 'shuttle/deployment/rails'
29
+ autoload :Nodejs, 'shuttle/deployment/nodejs'
29
30
 
30
31
  module Support
31
- autoload :Bundler, 'shuttle/support/bundler'
32
- autoload :Foreman, 'shuttle/support/foreman'
33
- autoload :Thin, 'shuttle/support/thin'
32
+ autoload :Bundler, 'shuttle/support/bundler'
33
+ autoload :Foreman, 'shuttle/support/foreman'
34
+ autoload :Thin, 'shuttle/support/thin'
34
35
  end
35
36
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'simplecov'
2
- SimpleCov.start
2
+ SimpleCov.start do
3
+ add_filter "/spec/"
4
+ end
3
5
 
4
6
  $:.unshift File.expand_path("../..", __FILE__)
5
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shuttle-deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.beta1
4
+ version: 0.2.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Sosedoff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-14 00:00:00.000000000 Z
11
+ date: 2013-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -184,13 +184,14 @@ files:
184
184
  - lib/shuttle/deployment/wordpress/vip.rb
185
185
  - lib/shuttle/errors.rb
186
186
  - lib/shuttle/helpers.rb
187
+ - lib/shuttle/path_helpers.rb
187
188
  - lib/shuttle/runner.rb
188
189
  - lib/shuttle/session.rb
190
+ - lib/shuttle/strategy.rb
189
191
  - lib/shuttle/support/bundler.rb
190
192
  - lib/shuttle/support/foreman.rb
191
193
  - lib/shuttle/support/thin.rb
192
194
  - lib/shuttle/target.rb
193
- - lib/shuttle/tasks.rb
194
195
  - lib/shuttle/version.rb
195
196
  - shuttle-deploy.gemspec
196
197
  - spec/deploy_spec.rb