Hi,
Since the API for accessing heroku application has come out earlier
this week, I have written a rake task that helps me deploy my
applications to heroku. My situation are as follows:
1) I already have an external code repository (svn) that I use to
develop my application.
2) I want to deploy my application to heroku automatically when I
commit to trunk (or create a tag) on the svn tree.
3) I also have an instance of cruisecontrol.rb setup on another
server.
To achieve (1), I was trying to use git-svnimport, but I just couldn't
figure it out how it works (I just learned about git when the heroku
API came out.) To that end, I decided to just write something that
will compare the current directory structure against the cloned app.
This method also has the advantage that it works fine with
svn:external (that I like to use for plugins), and would probably work
for projects that use any other repositories, as long as it can be
checked out / updated to the local filesystem.
First, I put the following in lib/tasks/heroku_sync.rake in my project
(the HerokuAppName is hard-coded and needs to be changed):
------
# Synchronizes current filesystem back to heroku
namespace :heroku do
desc "Synchronizes a repository to a heroku instance"
task :sync => ['heroku:sync:clone', 'heroku:sync:files',
'heroku:sync:commit', 'heroku:sync:push']
namespace :sync do
# The application name. Hard coded for now..
HerokuAppName = 'my_heroku_app_name'
# Temporary heroku clone directory
HerokuDir = 'tmp/heroku'
# Heroku host
HerokuHost = 'heroku.com'
desc "Clones (or pulls) heroku application repository to tmp/
heroku"
task :clone do
if FileTest.exist? HerokuDir
Dir.chdir HerokuDir do
raise "Could not pull #{HerokuDir}" unless system "git
pull ."
end
else
raise "Could not clone #{HerokuAppName}" unless
system "git clone [EMAIL PROTECTED]:#{HerokuAppName}.git
#{HerokuDir}"
end
end
desc "Synchronizes difference between the current filesystem and
the heroku clone"
task :files do
require 'find'
require 'fileutils'
require 'ftools'
def for_difference_between src_dir, dest_dir
Dir.chdir(dest_dir) do
Find.find(src_dir) do |src_path|
path = src_path.sub(src_dir, '')
next if path.empty?
fdir, base = File.split(path)
if base[0] == ?. or
base =~ /^(?:CVS|bak)/i or
fdir =~ /^(?:log|db|tmp)/i
Find.prune
next
end
case
when !FileTest.exist?(path)
yield :added, path
when File.stat(src_path).ctime > File.stat(dest_dir + '/'
+ path).ctime
yield :modified, path unless FileTest.directory? path #
Don't fire dir modification events
end
end
end
end
from_dir = File.expand_path('.') + "/"
to_dir = File.expand_path(HerokuDir) + "/"
# Add / copy files and dirs that exist in source but not in
target
for_difference_between from_dir, to_dir do |event, path|
from_path = from_dir + '/' + path
to_path = to_dir + '/' + path
if FileTest.directory? from_path
File.makedirs to_path
else
File.copy from_path, to_path
end
STDERR.puts "Adding #{path}"
Dir.chdir(to_dir) do
case event
when :added
system "git add #{path}"
when :modified
system "git add #{path}" # Seems like git wants 'add'
issued even for modifications
end
end
end
# Remove files / dirs that exist in taget but not in source
for_difference_between to_dir, from_dir do |event, path|
Dir.chdir(to_dir) do
case event
when :added
if FileTest.directory?(to_dir + '/' + path)
system "git rm -r #{path}"
else
system "git rm #{path}"
end
end
end
end
end
desc "Commits the changes"
task :commit do
Dir.chdir HerokuDir do
raise "Could not commit #{HerokuDir}" unless
system "git commit -m 'heroku:sync:files at #{Time.now}'"
end
end
desc "Pushes the changes back to heroku repository"
task :push do
Dir.chdir HerokuDir do
raise "Could not push #{HerokuAppName}" unless
system "git push"
end
end
end
end
------
... Once this file is in place, 'rake heroku:sync' will (a) pull the
project git on tmp/heroku, (b) compare the current project structure
against the one just pulled, (c) issues 'git add' / 'git remove' then
commit, and (d) pushes the changes back to heroku. (Note: for all
this to work, you would need to have the project checked out under the
same user at least once using 'heroku clone [myapp]', since it would
need to upload ssh key and save username.)
Although the task above can be run manually, I wanted cruisecontrol.rb
to run it for me. So I added the following to my Rakefile:
------
desc "Cruise task with automatic heroku deployment"
task :deploy_heroku => ['db:test:purge', 'db:migrate', 'test',
'heroku:sync']
------
and added the following to my cruisecontrol project setting:
------
"project.rake_task = 'deploy_heroku'"
------
Now, when I commit to trunk (or tag or whereever cruisecontrol.rb is
watching,) it gets automatically deployed to heroku (only if it passes
'test' task.) I'm sure it can be improved / done in simpler ways, but
hope it helps someone...
Tomoki
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Heroku" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/heroku?hl=en
-~----------~----~----~----~------~----~------~--~---