deployer 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Michael van Rooijen
1
+ Copyright (c) 2010 Michael van Rooijen
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # Deployer
2
+
3
+ Deployer is gem that enhances Capistrano to simplify the deployment of Ruby on Rails applications.
4
+
5
+ It assumes you are using Passenger to serve your Ruby on Rails applications.
6
+
7
+
8
+ ## Getting Started
9
+
10
+ install the gem
11
+
12
+ gem install deployer
13
+
14
+ create a new Rails app
15
+
16
+ rails new my_application
17
+
18
+ move into the Rails app and execute the "capify" and "enhancify" commands
19
+
20
+ cd my_application
21
+ capify .
22
+ enhancify .
23
+
24
+ enhancify is a command, provided by deployer that will inject some code into the Capfile and replace the config/deploy.rb with the one used for *Deployer*. If the deploy.rb file already exists, it will simply rename it to "deploy.old.1.rb", and if that also exists it will rename it to deploy.old.2.rb, etc. etc. So you will never accidentally overwrite your initial deploy.rb file.
25
+
26
+ This is what the deploy.rb looks like: "config/deploy.rb":http://github.com/meskyanichi/deployer/blob/master/setup/deploy.rb
27
+
28
+ *Next, open the config/deploy.rb file and edit the following variables.*
29
+
30
+ set :appname, "example.com" # the name of your application
31
+ set :ip, "123.45.678.90" # the ip address of the production server
32
+ set :user, "deployer" # the user that will deploy to the production server
33
+ set :remote, "origin" # the remote that should be deployed
34
+ set :branch, "production" # the branch that should be deployed
35
+
36
+
37
+ And *that's it!* You are now ready to do the following through *Deployer*:
38
+
39
+ - Create a remote git repository (only works if on production server)
40
+ - Push your initial commit to the remote repository
41
+ - Create the production environment to where you will deploy your application to
42
+ - And, of course, deploy and run your Rails application!
43
+
44
+ Here is are the quick-reference comments of the config/deploy.rb file
45
+
46
+ # Quick Reference
47
+ # Configure the essential configurations below and do the following:
48
+ #
49
+ # For more information:
50
+ # http://github.com/meskyanichi/deployer
51
+ #
52
+ # Create Local and Remote Repository:
53
+ # This will create a git repository on the deployment server
54
+ # Will not work when using a remote location such as github.com, trunksapp.com
55
+ # git init
56
+ # cap deploy:repository:create
57
+ #
58
+ # Initial Deployment:
59
+ # git add .
60
+ # git commit -m "Initial commit for deployment"
61
+ # git push origin [:branch]
62
+ # cap deploy:initial
63
+ #
64
+ # Then For Every Update Just Do:
65
+ # git add .
66
+ # git commit -am "some other commit"
67
+ # git push origin [:branch]
68
+ # cap deploy
69
+ #
70
+ # For a Full List of Commands
71
+ # cap -T
72
+
73
+
74
+ There are more tasks, but these will be your main commands. It's pretty straightforward.
75
+
76
+ To list all commands:
77
+
78
+ cap -T
79
+
80
+
81
+ ### Automated Tasks
82
+
83
+ *Deployer* will invoke various built-in tasks to try and deploy your application successfully.
84
+
85
+ On the initial setup *cap deploy:initial* (this procedure only has to be performed once)
86
+
87
+ - It will setup the production environment: releases and shared folder
88
+ - It will populate the shared folder with the folders you specified in the deploy.rb file
89
+ - It will sync your applications *database.yml* file to the shared/config folder
90
+
91
+ And the deployment procedure that follows (*cap deploy*), does the following:
92
+
93
+ - It will create a new folder in the releases folder and deploy your application to it
94
+ - It will ensure that the shared folder has all the folders you specified in the *deploy.rb*
95
+ - It will setup built-in symlink setups for your database.yml, production log
96
+ - It will also setup any additional symlinks you may have specified inside the *deploy.rb* from the release folder to the shared folder
97
+ - It will ensure all gems that are specified inside the Gemfile are installed.
98
+ - It will ensure the database is present and migrated to the latest version
99
+ - It will then perform any *custom* tasks you might have specified inside the *deploy.rb* file within the *after_deploy* method definition
100
+ - It will then restart passenger (your application)
101
+
102
+ So now the application has been deployed. For pushing new versions to the server you do the following:
103
+
104
+ git add .
105
+ git commit -m "new version commit"
106
+ git push origin production # or whatever branch you specified in deploy.rb
107
+ cap deploy
108
+
109
+ ## Additional Configuration
110
+
111
+ *Shared Folders and Symlinks*
112
+
113
+ I wanted to keep this as simple as possible as well. By default, *Deployer* will create folders for storing the production.log in and other necessary stuff. It will properly symlink it from the shared folder to the Rails application. However! You will most likely have some other things you must keep in a shared folder, such as assets or other files. This can be done easily with *Deployer*.
114
+
115
+ Again, inside of config/deploy.rb
116
+
117
+ set :additional_shared_folders,
118
+ %w(public/assets db)
119
+
120
+ In this example two paths will be created.
121
+
122
+ - /var/rails/:appname/shared/public/assets
123
+ - /var/rails/:appname/shared/db
124
+
125
+ *Deployer* will ensure these are available after every deployment. And will append any folders if you change the values here and re-deploy.
126
+
127
+ Now, what use are these folders if you do not have the ability to add symlinks from these folders to the application.
128
+
129
+ set :additional_shared_symlinks,
130
+ %w(public/assets db/production.sqlite3)
131
+
132
+ In this example two symlinks will be created from the shared_path to the current Rails application release.
133
+ As you can see the first symlink is a "path" symlink, which does not point to a direct file, but rather a folder.
134
+
135
+ The second symlink will be a link from the shared/db/production.sqlite3 to the current rails applications' db/production.sqlite3 file.
136
+
137
+ *NOTE*
138
+
139
+ One important thing to note here is that notice how the symlinks are mirrored to the Rails applications folder structure. This will always be the case. If you have some crazy architecture inside your Rails application: *rails_root/my/awesome/folder/structure/is/very/long* then you MUST create the following folder structure for the shared path: *shared/my/awesome/folder/structure/is/very/long*. This is a convention and it saves a lot of overhead in your configuration file by just defining a path once and using that same path for both the current and shared path.
140
+
141
+ *Additional (Optional) (Server) Configuration*
142
+
143
+ Here you can specify that you want to pull/push from/to a git repository that's located on a DIFFERENT server. Leave this commented out or remove it if your git repository resides on the same server as your Rails application. If you choose to store your git repository on a separate server by uncommenting the following line, then you lose the ability to create/reset/destroy/reinitialize it through *Deployer*. This is no big deal though. All you have to do is create the git repository manually on that specific server and then issue the *git remote add origin repository_url* and it will work fine with the rest of *Deployer*.
144
+
145
+ set :repository_url, "deployer@example.com:/path/to/repository.git"
146
+
147
+ And then here is the last bit of server configuration you can specify.
148
+
149
+ ### *Adding Application Specific Deployment Tasks*
150
+
151
+ Inside the *namespace :deploy do* block you can define your own deployment tasks that are specific to your application.
152
+
153
+ ##
154
+ # Application Specific Deployment Tasks
155
+ # In here you may specify any application specific and/or other tasks that are not handled by Deployer
156
+ # These can be invoked by creating a "run_custom_task" method in the "after_deploy" method above
157
+ namespace :deploy do
158
+ desc "Invoke this task manually by running: 'cap deploy:my_custom_task'"
159
+ task :my_custom_task do
160
+ # run "some command"
161
+ end
162
+
163
+ namespace :nested do
164
+ desc "Invoke this task manually by running: 'cap deploy:nested:my_custom_task'"
165
+ task :my_custom_task do
166
+ # system "some command"
167
+ end
168
+ end
169
+ end
170
+
171
+ Again, very straightforward. Just define your tasks as you normally would with Capistrano.
172
+ Then, to invoke them during each deployment you must add them inside the *after_deploy*, method like so:
173
+
174
+ def after_deploy
175
+ run_custom_task "my_custom_task"
176
+ run_custom_task "nested:my_custom_task"
177
+ end
178
+
179
+ This method will be invoked right before *Deployer* sets permissions on, and restarts the your Rails application.
180
+
181
+
182
+ ### Built-in Additional Tasks
183
+
184
+ *Deployer* has some built-in tasks that are often used by developers.
185
+
186
+ *Whenever*, To update the crontab on deployment:
187
+
188
+ def after_deploy
189
+ run_custom_task "whenever:update_crontab"
190
+ end
191
+
192
+ *Delayed Job*, To start/stop daemons
193
+
194
+ def after_deploy
195
+ run_custom_task "delayed_job:start"
196
+ run_custom_task "delayed_job:start n=3" # "n" specifies the amount of daemons that should run
197
+ run_custom_task "delayed_job:stop"
198
+ end
199
+
200
+ ## Assumptions / Conventions
201
+
202
+ - Assumes you are using Phusion Passenger
203
+ - Assumes Git Repository will be located on the same server as where the actual application will be deployed. Unless specified otherwise in the deploy.rb file.
204
+ - The config/database.yml will be transferred to the shared/config/database.yml and symlinked to on the initial deployment. You can re-sync it later with *cap deploy:db:sync_yaml*.
205
+ - Assumes you are using Bundler, it no longer supports config/environment.rb's **gem.config** (You can also use Bundler with Rails 2 apps)
206
+
207
+ ## Suggestions, Requests, Idea's?
208
+
209
+ Tell, Ask, Fork and Help!
210
+
211
+ ## Copyright
212
+
213
+ Copyright (c) 2010 Michael van Rooijen. See LICENSE for details.
@@ -1,27 +1,57 @@
1
- # Creates a tmp directory and writes Apache and NginX configuration files to it
2
- def create_tmp_file(contents)
3
- system 'mkdir tmp'
4
- file = File.new("tmp/#{domain}", "w")
5
- file << contents
6
- file.close
7
- end
8
-
1
+ ##
9
2
  # Alias for initializing custom deployment tasks
10
3
  def run_custom_task(task)
11
4
  system "cap deploy:#{task}"
12
5
  end
13
6
 
14
- # A Helper Method that assists in loading in tasks from the tasks folder
7
+ ##
8
+ # Helper Method that assists in loading in tasks from the tasks folder
15
9
  def load_tasks(tasks)
16
10
  load File.join(File.dirname(__FILE__), '..', 'tasks', "#{tasks}.rb")
17
11
  end
18
12
 
19
- # A Method that logs a message
13
+ ##
14
+ # Method that logs a message
20
15
  def log(message)
21
16
  puts "\n\n[Deployer] => #{message}.. \n\n"
22
17
  end
23
18
 
19
+ ##
24
20
  # Returns the RAILS_ENV=production string to reduce overhead
25
21
  def env
26
22
  "RAILS_ENV=production"
23
+ end
24
+
25
+ ##
26
+ # Returns the path to the 'rake' executable
27
+ def rake_path
28
+ return @rake_path if @rake_path
29
+ Net::SSH.start(ip, user) do |ssh|
30
+ @rake_path = ssh.exec!("which rake").chomp || "rake"
31
+ end
32
+ @rake_path
33
+ end
34
+
35
+ ##
36
+ # Returns the path to Bundler's 'bundle' executable
37
+ def bundle_path
38
+ return @bundle_path if @bundle_path
39
+ Net::SSH.start(ip, user) do |ssh|
40
+ @bundle_path = ssh.exec!("which bundle").chomp || "bundle"
41
+ end
42
+ @bundle_path
43
+ end
44
+
45
+ ##
46
+ # Returns true or false, depending on whether the bundle is satisfied (dependencies are installed)
47
+ def bundle_satisfied?
48
+ return @bundle_satisfied if @bundle_satisfied
49
+ Net::SSH.start(ip, user) do |ssh|
50
+ if ssh.exec!("cd #{current_path}; #{bundle_path} check") =~ /The Gemfile's dependencies are satisfied/
51
+ @bundle_satisfied = true
52
+ else
53
+ @bundle_satisfied = false
54
+ end
55
+ end
56
+ @bundle_satisfied
27
57
  end
@@ -1,5 +1,5 @@
1
- # Returns a path that can be loaded by the "load" method
2
- # inside the Capfile
1
+ ##
2
+ # Returns a path that can be loaded by the "load" method inside the Capfile
3
3
  def deployer
4
4
  File.join(File.dirname(__FILE__), '..', 'deployer.rb')
5
5
  end
data/lib/deployer.rb CHANGED
@@ -1,36 +1,34 @@
1
+ ##
1
2
  # Load Deployer Helpers
2
3
  require File.join(File.dirname(__FILE__), 'deployer', 'helpers')
3
4
 
4
- # This configuration is *conventional*
5
+ ##
6
+ # This Configuration Is *Conventional*
5
7
  set :application, ip
6
- set :deploy_to, "/var/rails/#{domain}"
7
- set :repository_path, "/var/git/#{domain}.git"
8
+ set :deploy_to, "/var/apps/#{appname}"
9
+ set :repository_path, "/var/git/#{appname}.git"
8
10
  set :repository, "#{user}@#{application}:#{repository_path}"
9
11
  set :repository, repository_url if respond_to?(:repository_url)
10
12
 
11
- set :scm, "git"
12
- set :use_sudo, true
13
+ set :scm, 'git'
14
+ set :use_sudo, false
13
15
  role :web, application
14
16
  role :app, application
15
17
  role :db, application
16
18
  default_run_options[:pty] = true
17
19
 
20
+ ##
18
21
  # Default Configuration
19
- set :remote, "origin" unless respond_to?(:remote)
20
- set :branch, "master" unless respond_to?(:branch)
21
- set :apache_initialize_utility_path, "/etc/init.d/apache2" unless respond_to?(:apache_initialize_utility_path)
22
- set :apache_sites_available_path, "/etc/apache2/sites-available" unless respond_to?(:apache_sites_available_path)
23
- set :nginx_initialize_utility_path, "/etc/init.d/nginx" unless respond_to?(:nginx_initialize_utility_path)
24
- set :nginx_sites_enabled_path, "/opt/nginx/conf/sites-enabled" unless respond_to?(:nginx_sites_enabled_path)
22
+ set :remote, 'origin' unless respond_to?(:remote)
23
+ set :branch, 'master' unless respond_to?(:branch)
25
24
 
25
+ ##
26
26
  # Load Deployment Tasks
27
- load_tasks("global")
28
- load_tasks("passenger")
29
- load_tasks("apache")
30
- load_tasks("nginx")
31
- load_tasks("plugin")
32
- load_tasks("db")
33
- load_tasks("gems")
34
- load_tasks("repository")
35
- load_tasks("environment")
36
- load_tasks("commands")
27
+ load_tasks('global')
28
+ load_tasks('passenger')
29
+ load_tasks('plugin')
30
+ load_tasks('db')
31
+ load_tasks('gems')
32
+ load_tasks('repository')
33
+ load_tasks('environment')
34
+ load_tasks('commands')
@@ -3,13 +3,13 @@ namespace :deploy do
3
3
 
4
4
  desc "Run a command from the Rails Root on the remote server. Specify command='my_command'."
5
5
  task :rails_root do
6
- log "Executing \"#{ENV['command']}\" from the Rails Root on the server."
6
+ log "Executing \"#{ENV['command']}\" from the Application's root path."
7
7
  run "cd #{current_path}; #{ENV['command']}"
8
8
  end
9
9
 
10
10
  desc "Run a command on the remote server. Specify command='my_command'."
11
11
  task :default do
12
- log "Executing \"#{ENV['command']}\" on the server."
12
+ log "Executing \"#{ENV['command']}\"."
13
13
  run "#{ENV['command']}"
14
14
  end
15
15
 
data/lib/tasks/db.rb CHANGED
@@ -3,7 +3,7 @@ namespace :deploy do
3
3
 
4
4
  desc "Syncs the database.yml file from the local machine to the remote machine"
5
5
  task :sync_yaml do
6
- log "Syncing database yaml to the production server"
6
+ log "Syncing local database.yml (config/database.yml) to the shared folder (#{appname}/shared/config/database.yml)"
7
7
  unless File.exist?("config/database.yml")
8
8
  puts "There is no config/database.yml.\n "
9
9
  exit
@@ -11,40 +11,38 @@ namespace :deploy do
11
11
  system "rsync -vr --exclude='.DS_Store' config/database.yml #{user}@#{application}:#{shared_path}/config/"
12
12
  end
13
13
 
14
- desc "Create Production Database"
14
+ desc "Create the database"
15
15
  task :create do
16
- log "Creating the Production Database"
17
- run "cd #{current_path}; rake db:create #{env}"
16
+ log "Creating the database"
17
+ run "cd #{current_path}; #{rake_path} db:create #{env}"
18
18
  end
19
19
 
20
20
  namespace :migrate do
21
21
 
22
- desc "Migrate Production Database"
22
+ desc "Migrate the database"
23
23
  task :default do
24
- log "Migrating the Production Database"
25
- run "cd #{current_path}; rake db:migrate #{env}"
24
+ log "Migrating the database"
25
+ run "cd #{current_path}; #{rake_path} db:migrate #{env}"
26
26
  end
27
27
 
28
- desc "Resets the Production Database"
28
+ desc "Reset the database"
29
29
  task :reset do
30
- log "Resetting the Production Database"
31
- run "cd #{current_path}; rake db:migrate:reset #{env}"
32
- system "cap deploy:set_permissions"
30
+ log "Resetting the database"
31
+ run "cd #{current_path}; #{rake_path} db:migrate:reset #{env}"
33
32
  end
34
33
 
35
34
  end
36
35
 
37
- desc "Destroys Production Database"
36
+ desc "Drop the database"
38
37
  task :drop do
39
- log "Destroying the Production Database"
40
- run "cd #{current_path}; rake db:drop #{env}"
38
+ log "Dropping the database"
39
+ run "cd #{current_path}; #{rake_path} db:drop #{env}"
41
40
  end
42
41
 
43
- desc "Populates the Production Database"
42
+ desc "Populate the database"
44
43
  task :seed do
45
- log "Populating the Production Database"
46
- run "cd #{current_path}; rake db:seed #{env}"
47
- system "cap deploy:set_permissions"
44
+ log "Seeding the database"
45
+ run "cd #{current_path}; #{rake_path} db:seed #{env}"
48
46
  end
49
47
 
50
48
  end
data/lib/tasks/gems.rb CHANGED
@@ -1,14 +1,18 @@
1
1
  namespace :deploy do
2
2
  namespace :gems do
3
3
 
4
- desc "Installs any 'not-yet-installed' gems on the production server or a single gem when the gem= is specified."
4
+ desc "Installs dependencies for application, or a single gem when the gem= is specified."
5
5
  task :install do
6
6
  if ENV['gem']
7
7
  log "Installing #{ENV['gem']}"
8
8
  run "gem install #{ENV['gem']}"
9
9
  else
10
10
  log "Installing gem dependencies"
11
- run "cd #{current_path}; rake deployer_gems:install #{env}"
11
+ if bundle_satisfied? and ENV['force'] != "true"
12
+ puts "The Gemfile's dependencies are satisfied"
13
+ else
14
+ run "cd #{current_path}; #{bundle_path} install"
15
+ end
12
16
  end
13
17
  end
14
18
 
data/lib/tasks/global.rb CHANGED
@@ -7,51 +7,35 @@ namespace :deploy do
7
7
  system "cap deploy:gems:install"
8
8
  system "cap deploy:db:create"
9
9
  system "cap deploy:db:migrate"
10
- after_deploy if respond_to?(:after_deploy)
11
- system "cap deploy:set_permissions"
10
+ after_deploy if respond_to?(:after_deploy)
12
11
  system "cap deploy:passenger:restart"
13
12
  end
14
13
 
15
- desc "Executes the initial procedures for deploying a Ruby on Rails Application."
14
+ desc "Executes the initial procedures for deploying a Ruby on Rails application."
16
15
  task :initial do
17
16
  system "cap deploy:setup"
18
17
  system "cap deploy:setup_shared_path"
19
18
  system "cap deploy:db:sync_yaml"
20
- system "cap deploy:sync_tasks"
21
- system "cap deploy"
22
- end
23
-
24
- desc "Sets permissions for Rails Application"
25
- task :set_permissions do
26
- log "Setting Permissions"
27
- run "chown -R www-data:www-data #{deploy_to}"
28
- end
29
-
30
- desc "Creates symbolic links from shared folder"
31
- task :setup_symlinks do
32
- log "Setting up Symbolic Links"
33
- run "mkdir -p #{File.join(current_path, 'lib', 'tasks')}"
34
- shared_symlinks = %w(config/database.yml lib/tasks/deployer.rake)
35
- shared_symlinks += additional_shared_symlinks if respond_to?(:additional_shared_symlinks)
36
- shared_symlinks.each do |symlink|
37
- run "ln -nfs #{File.join(shared_path, symlink)} #{File.join(current_path, symlink)}"
38
- end
39
19
  end
40
20
 
41
21
  desc "Sets up the shared path"
42
22
  task :setup_shared_path do
43
- log "Setting up the shared path"
23
+ log "Setting up the shared folders"
44
24
  shared_folders = %w(config lib/tasks)
45
25
  shared_folders += additional_shared_folders if respond_to?(:additional_shared_folders)
46
26
  shared_folders.each do |folder|
47
27
  run "mkdir -p #{shared_path}/#{folder}"
48
28
  end
49
29
  end
50
-
51
- desc "Syncs the rake tasks for installing gems."
52
- task :sync_tasks do
53
- log "Adding Deployer Rake tasks to shared path."
54
- system "rsync -vr --exclude='.DS_Store' #{File.join(File.dirname(__FILE__), '..', 'deployer', 'tasks', 'deployer.rake')} #{user}@#{application}:#{File.join(shared_path, 'lib', 'tasks')}"
30
+
31
+ desc "Creates symbolic links from the application to the shared folders"
32
+ task :setup_symlinks do
33
+ log "Creating symbolic links from the application to the shared folders"
34
+ shared_symlinks = %w(config/database.yml)
35
+ shared_symlinks += additional_shared_symlinks if respond_to?(:additional_shared_symlinks)
36
+ shared_symlinks.each do |symlink|
37
+ run "ln -nfs #{File.join(shared_path, symlink)} #{File.join(current_path, symlink)}"
38
+ end
55
39
  end
56
40
 
57
41
  end
@@ -3,7 +3,7 @@ namespace :deploy do
3
3
 
4
4
  desc "Restarts Passenger"
5
5
  task :restart do
6
- log "Restarting Passenger"
6
+ log "Restarting #{appname}"
7
7
  run "touch #{current_path}/tmp/restart.txt"
8
8
  end
9
9
 
data/lib/tasks/plugin.rb CHANGED
@@ -1,23 +1,23 @@
1
1
  namespace :deploy do
2
2
  namespace :whenever do
3
3
 
4
- desc "Update the crontab file for the Whenever Gem."
4
+ desc "Update the crontab file for the Whenever gem."
5
5
  task :update_crontab, :roles => :db do
6
- log "Updating the Crontab"
7
- run "cd #{release_path} && whenever --update-crontab #{domain}"
6
+ log "Updating the crontab"
7
+ run "cd #{release_path} && whenever --update-crontab #{appname}"
8
8
  end
9
9
  end
10
10
 
11
11
  namespace :delayed_job do
12
- desc "Starts the Delayed Job Daemon(s)."
12
+ desc "Starts the Delayed Job daemon(s)."
13
13
  task :start do
14
- log "Starting #{(ENV['n'] + ' ') if ENV['n']}Delayed Job Daemon(s)"
14
+ log "Starting #{(ENV['n'] + ' ') if ENV['n']}Delayed Job daemon(s)"
15
15
  run "#{env} #{current_path}/script/delayed_job #{"-n #{ENV['n']} " if ENV['n']}start"
16
16
  end
17
17
 
18
- desc "Stops the Delayed Job Daemon(s)."
18
+ desc "Stops the Delayed Job daemon(s)."
19
19
  task :stop do
20
- log "Stopping Delayed Job Daemon(s)"
20
+ log "Stopping Delayed Job daemon(s)"
21
21
  run "#{env} #{current_path}/script/delayed_job stop"
22
22
  end
23
23
  end