-
-
Save ndbroadbent/3802355 to your computer and use it in GitHub Desktop.
require 'fileutils' | |
# Warning: The following deploy task will completely overwrite whatever is currently deployed to Heroku. | |
# The deploy branch is rebased onto master, so the push needs to be forced. | |
desc "Deploy app to Heroku after precompiling assets" | |
task :deploy do | |
deploy_branch = 'heroku' | |
remote = 'heroku' | |
deploy_repo_dir = "tmp/heroku_deploy" | |
begin | |
# Check branch and working directory. Fail if not on clean master branch. | |
branch = `branch_name=$(git symbolic-ref HEAD 2>/dev/null); branch_name=${branch_name##refs/heads/}; echo ${branch_name:-HEAD}`.strip | |
if branch != 'master' | |
raise "You have checked out the #{branch} branch, please only deploy from the master branch!" | |
end | |
if `git status --porcelain`.present? | |
raise "You have unstaged or uncommitted changes! Please only deploy from a clean working directory!" | |
end | |
unless File.exists? deploy_repo_dir | |
# Copy repo to tmp dir so we can continue working while it deploys | |
@new_repo = true | |
puts "Copying repo to #{deploy_repo_dir}..." | |
# Can't copy into self, so copy to /tmp first | |
FileUtils.cp_r Rails.root.to_s, "/tmp/heroku_deploy" | |
FileUtils.mv "/tmp/heroku_deploy", Rails.root.join('tmp') | |
end | |
# Change working directory to copied repo | |
Dir.chdir(deploy_repo_dir) | |
# Create new deploy branch if starting with a fresh repo | |
if @new_repo | |
# Set remote to parent git dir, so we can fetch updates on future deploys | |
system "git remote set-url origin ../.." | |
system "git checkout -b #{deploy_branch}" | |
# Allow git to see public/assets | |
puts "Removing public/assets from .gitignore..." | |
system 'sed -i '' "/^[\/?]public\/assets/d" .gitignore' | |
system 'git add .gitignore; git commit -m "Allow git to commit public/assets"' | |
else | |
# Otherwise, we're already on the deploy branch, so fetch any new changes from original repo | |
system "git fetch origin" | |
# Rebase onto origin/master. | |
# This step should never fail, because we are rebasing commits for files | |
# that should be ignored by the master repo. | |
unless system "git rebase origin/master" | |
raise "Rebase Failed! Please delete tmp/heroku_deploy and start again." | |
end | |
end | |
# Precompile assets | |
Rake::Task['assets:precompile'].invoke | |
# Add any extra tasks you want to run here, such as compiling static pages, etc. | |
# Add all changes and new files | |
system 'git add -A' | |
commit_message = "Added precompiled assets" | |
if @new_repo | |
# Create new commit for new repo | |
system "git commit -m '#{commit_message}'", :out => "/dev/null" | |
else | |
# If existing repo, amend previous assets commit | |
system "git commit --amend -m '#{commit_message}'", :out => "/dev/null" | |
end | |
puts "Commit: #{commit_message}" | |
# Force push deploy branch to Heroku | |
puts "Pushing #{deploy_branch} branch to master on #{remote}..." | |
IO.popen("git push #{remote} #{deploy_branch}:master -f") do |io| | |
while (line = io.gets) do | |
puts line | |
end | |
end | |
end | |
end |
Hi, thanks very much for the feedback and suggestions! I've changed echo -n ...'
to echo ...'.strip
, and I've replaced the sed command with your suggestion. Please let me know if you run into any more problems.
Cheers!
I used it with a small change. Rather than origin, I used #{remote}
in shell commands because I don't use a separate origin repo, just the Heroku repo.
bash and sh will both use their built-in echo. bash's echo supports the -n flag, but sh does not
➔ sh
sh-3.2$ type cho
sh: type: cho: not found
sh-3.2$ type echo
echo is a shell builtin
sh-3.2$ /bin/echo foo
foo
sh-3.2$ echo foo
foo
sh-3.2$ /bin/echo -n foo
foosh-3.echo -n foo
-n foo
(ignore type cho
)
@ndbroadbent why not make this rake task a part of the turbo-sprockets-rails3 gem?
great work man! I've a bad case of premature heroku deploying without the assets:precompile - this works great. Love the gem also, well done.
Thanks for this! One suggestion, change the FileUtils.cp_r on line 27 to using the system command:
system "cp -r #{Rails.root} /tmp/heroku_deploy"
I had a socket file in my tmp/ and FileUtils.cp_r() failed with the following error. Only cp -r
told me which file.
$ rake deploy
Copying repo to tmp/heroku_deploy...
rake aborted!
cannot handle socket
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1357:in `copy'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:465:in `block in copy_entry'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1433:in `preorder_traverse'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:462:in `copy_entry'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:437:in `block in cp_r'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1515:in `block in fu_each_src_dest'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1531:in `fu_each_src_dest0'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:1513:in `fu_each_src_dest'
/Users/turadg/.rbenv/versions/1.9.3-p327-perf/lib/ruby/1.9.1/fileutils.rb:436:in `cp_r'
👍 @turadg I also had a socket this barfed on.
The sed command didn't work for me, probably because I'm on zsh. Removing the brackets helped: sed -i "" "/^public\/assets/d" .gitignore
Fantastic work on this and the gem! I would like to share issues I had on Mac OSX 10.6.8 with regular bash shell. Maybe i have some customizations but I got '-n' as the contents of branch when the rake task runs, but it works ok from the shell. So I removed -n from the echo line and added .chomp to the end.
Secondly the sed command didn't work for 2 reasons, the -i needs an non-optional extension and in my gitignore it is public/assets
sed -i '' "/^[/?]public/assets/d" .gitignore
I can make a fork, but maybe this is easier?