public
Last active

Rake task for precompiling assets locally before deploying to Heroku

  • Download Gist
deploy.rake
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
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

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?

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'

:+1: @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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.