Skip to content
Browse files

Refactored each_app, added heroku methods

  • Loading branch information...
1 parent b1271e7 commit 20be7f353bd4f093265a9fd9401836d1f37b364f @kmayer kmayer committed Aug 1, 2011
Showing with 193 additions and 111 deletions.
  1. +1 −1 .rvmrc
  2. +60 −25 lib/heroku_san.rb
  3. +53 −72 lib/heroku_san/tasks.rb
  4. +79 −13 spec/heroku_san_spec.rb
View
2 .rvmrc
@@ -1 +1 @@
-rvm ruby-1.8.7-head@heroku_san --create
+rvm gemset use heroku_san --create
View
85 lib/heroku_san.rb
@@ -40,6 +40,20 @@ def initialize(config_file)
end
end
+ def create_config
+ template = File.join(File.dirname(__FILE__), 'templates', 'heroku.example.yml')
+ if File.exists?(@config_file)
+ false
+ else
+ FileUtils.cp(template, @config_file)
+ true
+ end
+ end
+
+ def [](stage)
+ @app_settings[stage]
+ end
+
def all
@app_settings.keys
end
@@ -70,47 +84,68 @@ def apps
def each_app
raise NoApps if apps.empty?
- apps.each do |name|
- app = @app_settings[name]['app']
- yield(name, app, "git@heroku.com:#{app}.git", @app_settings[name]['config'])
+ apps.each do |stage|
+ yield(stage, "git@heroku.com:#{self[stage]['app']}.git", self[stage]['config'])
end
end
- def migrate(app)
- run(app, 'rake', 'db:migrate')
- sh "heroku restart --app #{app}"
+ def stack(stage)
+ self[stage]['stack'] ||= %x"heroku stack --app #{self[stage]['app']}".split("\n").select { |b| b =~ /^\* / }.first.gsub(/^\* /, '')
+ end
+
+ def run(stage, command, args = nil)
+ if stack(stage) =~ /cedar/
+ sh_heroku stage, "run #{command} #{args}"
+ else
+ sh_heroku stage, "run:#{command} #{args}"
+ end
+ end
+
+ def create(stage)
+ sh "heroku apps:create #{self[stage]['app']}"
+ end
+
+ def migrate(stage)
+ run(stage, 'rake', 'db:migrate')
+ sh_heroku stage, "restart"
end
- def maintenance(app, action)
+ def maintenance(stage, action)
raise ArgumentError, "Action #{action.inspect} must be one of (:on, :off)", caller if ![:on, :off].include?(action)
- sh "heroku maintenance:#{action} --app #{app}"
+
+ sh_heroku stage, "maintenance:#{action}"
end
- def create_config
- template = File.join(File.dirname(__FILE__), 'templates', 'heroku.example.yml')
- if File.exists?(@config_file)
- false
- else
- FileUtils.cp(template, @config_file)
- true
- end
+ def sharing_add(stage, email)
+ sh_heroku stage, "sharing:add #{email}"
end
- def stack(app)
- stage, config = @app_settings.find{|stage, settings| settings['app'] == app}
- config['stack'] || %x"heroku stack --app #{app}".split("\n").select { |b| b =~ /^\* / }.first.gsub(/^\* /, '')
+ def sharing_remove(stage, email)
+ sh_heroku stage, "sharing:remove #{email}"
end
- def run(app, command, args = nil)
- if stack(app) =~ /cedar/
- sh "heroku run #{command} #{args} --app #{app}"
- else
- sh "heroku run:#{command} #{args} --app #{app}"
- end
+ def long_config(stage)
+ sh_heroku stage, 'config --long'
+ end
+
+ def capture(stage)
+ sh_heroku stage, 'bundles:capture'
+ end
+
+ def restart(stage)
+ sh_heroku stage, 'restart'
+ end
+
+ def logs(stage)
+ sh_heroku stage, 'logs'
end
private
+ def sh_heroku stage, command
+ sh "heroku #{command} --app #{self[stage]['app']}"
+ end
+
def parse_yaml(config_file)
if File.exists?(config_file)
if defined?(ERB)
View
125 lib/heroku_san/tasks.rb
@@ -18,32 +18,19 @@
namespace :heroku do
desc "Creates the Heroku app"
task :create do
- each_heroku_app do |stage, app, repo|
- sh "heroku create #{app}"
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.create(stage)
end
end
desc "Generate the Heroku gems manifest from gem dependencies"
task :gems => 'gems:base' do
raise HerokuSan::Deprecated
- # RAILS_ENV='production'
- # Rake::Task[:environment].invoke
- # gems = Rails.configuration.gems.reject { |g| g.frozen? && !g.framework_gem? }
- # list = gems.collect do |g|
- # command, *options = g.send(:install_command)
- # options.join(" ")
- # end
- #
- # list.unshift(%Q{rails --version "= #{Rails.version}"})
- #
- # File.open(Rails.root.join('.gems'), 'w') do |f|
- # f.write(list.join("\n"))
- # end
end
desc 'Add git remotes for all apps in this project'
task :remotes do
- each_heroku_app do |stage, app, repo|
+ each_heroku_app do |stage, repo, config|
sh "git remote add #{stage} #{repo}"
end
end
@@ -53,8 +40,8 @@
print "Email address of collaborator to add: "
$stdout.flush
email = $stdin.gets
- each_heroku_app do |stage, app, repo|
- sh "heroku sharing:add --app #{app} #{email}"
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.sharing_add(stage, email)
end
end
@@ -63,15 +50,15 @@
print "Email address of collaborator to remove: "
$stdout.flush
email = $stdin.gets
- each_heroku_app do |stage, app, repo|
- sh "heroku sharing:remove --app #{app} #{email}"
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.sharing_remove(stage, email)
end
end
desc 'Lists configured apps'
task :apps => :all do
- each_heroku_app do |stage, app, repo|
- puts "#{stage} is shorthand for the Heroku app #{app} located at:"
+ each_heroku_app do |stage, repo, config|
+ puts "#{stage} is shorthand for the Heroku app #{@heroku_san[stage]['app']} located at:"
puts " #{repo}"
print " @ "
rev = `git ls-remote -h #{repo}`.split(' ').first
@@ -87,10 +74,10 @@
namespace :apps do
desc 'Lists configured apps without hitting heroku'
task :local => :all do
- each_heroku_app do |stage, app, repo|
- puts "#{stage} is shorthand for the Heroku app #{app} located at:"
+ each_heroku_app do |stage, repo, config|
+ puts "#{stage} is shorthand for the Heroku app #{@heroku_san[stage]['app']} located at:"
puts " #{repo}"
- tag = tag(stage)
+ tag = @heroku_san[stage]['tag']
puts " the #{stage} TAG is '#{tag}'" if tag
puts
end
@@ -99,12 +86,12 @@
desc 'Add proper RACK_ENV to each application'
task :rack_env => :all do
- each_heroku_app do |stage, app, repo|
- command = "heroku config --app #{app}"
+ each_heroku_app do |stage, repo, config|
+ command = "heroku config --app #{@heroku_san[stage]['app']}"
puts command
config = Hash[`#{command}`.scan(/^(.+?)\s*=>\s*(.+)$/)]
if config['RACK_ENV'] != stage
- sh "heroku config:add --app #{app} RACK_ENV=#{stage}"
+ sh "heroku config:add --app #{@heroku_san[stage]['app']} RACK_ENV=#{stage}"
end
end
end
@@ -126,8 +113,8 @@
desc 'Add config:vars to each application.'
task :config do
- each_heroku_app do |stage, app, repo, config|
- command = "heroku config:add --app #{app}"
+ each_heroku_app do |stage, repo, config|
+ command = "heroku config:add --app #{@heroku_san[stage]['app']}"
config.each do |var, value|
command += " #{var}=#{value}"
end
@@ -138,16 +125,16 @@
namespace :config do
desc "Lists config variables as set on Heroku"
task :list do
- each_heroku_app do |stage, app|
+ each_heroku_app do |stage, repo, config|
puts "#{stage}:"
- sh "heroku config --app #{app} --long"
+ @heroku_san.long_config(stage)
end
end
namespace :list do
desc "Lists local config variables without setting them"
task :local do
- each_heroku_app do |stage, app, repo, config|
+ each_heroku_app do |stage, repo, config|
(config).each do |var, value|
puts "#{stage} #{var}: '#{value}'"
end
@@ -158,73 +145,71 @@
desc 'Runs a rake task remotely'
task :rake, [:task] do |t, args|
- each_heroku_app do |stage, app, repo|
- @heroku_san.run(app, 'rake', args.task)
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.run(stage, 'rake', args.task)
end
end
desc "Pushes the given commit (default: HEAD)"
task :push, :commit do |t, args|
- each_heroku_app do |stage, app, repo|
- git_push(args[:commit] || git_parsed_tag(tag(stage)), repo)
+ each_heroku_app do |stage, repo, config|
+ git_push(args[:commit] || git_parsed_tag(@heroku_san[stage]['tag']), repo)
end
end
namespace :push do
desc "Force-pushes the given commit (default: HEAD)"
task :force, :commit do |t, args|
- each_heroku_app do |stage, app, repo|
- git_push(args[:commit] || git_parsed_tag(tag(stage)), repo, %w[--force])
+ each_heroku_app do |stage, repo, config|
+ git_push(args[:commit] || git_parsed_tag(@heroku_san[stage]['tag']), repo, %w[--force])
end
end
end
desc "Enable maintenance mode"
task :maintenance do
- each_heroku_app do |stage, app|
- @heroku_san.maintenance(app, :on)
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.maintenance(stage, :on)
end
end
desc "Enable maintenance mode"
task :maintenance_on do
- each_heroku_app do |stage, app|
- @heroku_san.maintenance(app, :on)
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.maintenance(stage, :on)
end
end
desc "Disable maintenance mode"
task :maintenance_off do
- each_heroku_app do |stage, app|
- @heroku_san.maintenance(app, :off)
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.maintenance(stage, :off)
end
end
end
desc "Pushes the given commit, migrates and restarts (default: HEAD)"
task :deploy, [:commit] => [:before_deploy] do |t, args|
- each_heroku_app do |stage, app, repo|
- git_push(args[:commit] || git_parsed_tag(tag(stage)), repo)
- @heroku_san.migrate(app)
+ each_heroku_app do |stage, repo, config|
+ git_push(args[:commit] || git_parsed_tag(@heroku_san[stage]['tag']), repo)
+ @heroku_san.migrate(stage)
end
Rake::Task[:after_deploy].execute
end
namespace :deploy do
desc "Force-pushes the given commit, migrates and restarts (default: HEAD)"
task :force, [:commit] => [:before_deploy] do |t, args|
- each_heroku_app do |stage, app, repo|
- git_push(args[:commit] || git_parsed_tag(tag(stage)), repo, %w[--force])
- @heroku_san.migrate(app)
+ each_heroku_app do |stage, repo, config|
+ git_push(args[:commit] || git_parsed_tag(@heroku_san[stage]['tag']), repo, %w[--force])
+ @heroku_san.migrate(stage)
end
Rake::Task[:after_deploy].execute
end
end
-# Deprecated.
task :force_deploy do
raise Deprecated
- Rake::Task[:'deploy:force'].invoke
end
desc "Callback before deploys"
@@ -237,47 +222,47 @@
desc "Captures a bundle on Heroku"
task :capture do
- each_heroku_app do |stage, app, repo|
- sh "heroku bundles:capture --app #{app}"
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.capture(stage)
end
end
desc "Opens a remote console"
task :console do
- each_heroku_app do |stage, app, repo|
- @heroku_san.run(app, 'console')
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.run(stage, 'console')
end
end
desc "Restarts remote servers"
task :restart do
- each_heroku_app do |stage, app, repo|
- sh "heroku restart --app #{app}"
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.restart(stage)
end
end
desc "Migrates and restarts remote servers"
task :migrate do
- each_heroku_app do |stage, app, repo|
- @heroku_san.migrate(app)
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.migrate(stage)
end
end
desc "Shows the Heroku logs"
task :logs do
- each_heroku_app do |stage, app, repo|
- sh "heroku logs --app #{app}"
+ each_heroku_app do |stage, repo, config|
+ @heroku_san.logs(stage)
end
end
namespace :db do
task :pull do
- each_heroku_app do |stage, app, repo|
- sh "heroku pgdumps:capture --app #{app}"
- dump = `heroku pgdumps --app #{app}`.split("\n").last.split(" ").first
+ each_heroku_app do |stage, repo, config|
+ sh "heroku pgdumps:capture --app #{@heroku_san[stage]['app']}"
+ dump = `heroku pgdumps --app #{@heroku_san[stage]['app']}`.split("\n").last.split(" ").first
sh "mkdir -p #{Rails.root}/db/dumps"
file = "#{Rails.root}/db/dumps/#{dump}.sql.gz"
- url = `heroku pgdumps:url --app #{app} #{dump}`.chomp
+ url = `heroku pgdumps:url --app #{@heroku_san[stage]['app']} #{dump}`.chomp
sh "wget", url, "-O", file
sh "rake db:drop db:create"
sh "gunzip -c #{file} | #{Rails.root}/script/dbconsole"
@@ -299,8 +284,4 @@ def each_heroku_app(&block)
rake all heroku:share"
exit(1)
-end
-
-def tag(app)
- tag = @heroku_san.app_settings[app]['tag']
-end
+end
View
92 spec/heroku_san_spec.rb
@@ -10,7 +10,10 @@
context "using the example config file" do
let(:heroku_config_file) { File.join(SPEC_ROOT, "fixtures", "example.yml") }
- let(:template_config_file) { File.join(SPEC_ROOT, "..", "lib/templates", "heroku.example.yml")}
+ let(:template_config_file) {
+ path = File.join(SPEC_ROOT, "..", "lib/templates", "heroku.example.yml")
+ (File.respond_to? :realpath) ? File.realpath(path) : path
+ }
let(:heroku_san) { HerokuSan.new(heroku_config_file) }
it "#all" do
@@ -74,39 +77,44 @@
expect { heroku_san.each_app do |w,x,y,z| true; end }.to raise_error HerokuSan::NoApps
end
- it "yields to a block with four args" do
+ it "yields to a block with args" do
heroku_san << 'production'
block = double('block')
block.should_receive(:action).with('production',
- 'awesomeapp',
'git@heroku.com:awesomeapp.git',
heroku_san.app_settings['production']['config'])
- heroku_san.each_app do |name, app, repos, config|
- block.action(name, app, repos, config)
+ heroku_san.each_app do |stage, repos, config|
+ block.action(stage, repos, config)
end
end
end
+
+ describe "#[]" do
+ it "returns a config section" do
+ heroku_san['production'].should == heroku_san.app_settings['production']
+ end
+ end
it "#migrate" do
heroku_san.should_receive(:sh).with("heroku run:rake db:migrate --app awesomeapp-staging")
heroku_san.should_receive(:sh).with("heroku restart --app awesomeapp-staging")
- heroku_san.migrate('awesomeapp-staging')
+ heroku_san.migrate('staging')
end
describe "#maintenance" do
it ":on" do
heroku_san.should_receive(:sh).with("heroku maintenance:on --app awesomeapp")
- heroku_san.maintenance('awesomeapp', :on)
+ heroku_san.maintenance('production', :on)
end
it ":off" do
heroku_san.should_receive(:sh).with("heroku maintenance:off --app awesomeapp")
- heroku_san.maintenance('awesomeapp', :off)
+ heroku_san.maintenance('production', :off)
end
it ":busy raises an ArgumentError" do
expect do
- heroku_san.maintenance('awesomeapp', :busy)
+ heroku_san.maintenance('production', :busy)
end.to raise_error ArgumentError, "Action #{:busy.inspect} must be one of (:on, :off)"
end
end
@@ -122,26 +130,33 @@
cedar (beta)
EOT
}
- heroku_san.stack('awesomeapp').should == 'bamboo-mri-1.9.2'
+ heroku_san.stack('production').should == 'bamboo-mri-1.9.2'
end
it "returns the stack name from the config if it is set there" do
heroku_san.should_not_receive("`")
- heroku_san.stack('awesomeapp-staging').should == 'bamboo-ree-1.8.7'
+ heroku_san.stack('staging').should == 'bamboo-ree-1.8.7'
end
end
describe "#run" do
it "runs commands using the pre-cedar format" do
heroku_san.should_receive(:sh).with("heroku run:rake foo bar bleh --app awesomeapp-staging")
- heroku_san.run('awesomeapp-staging', 'rake', 'foo bar bleh')
+ heroku_san.run('staging', 'rake', 'foo bar bleh')
end
it "runs commands using the new cedar format" do
heroku_san.should_receive(:sh).with("heroku run worker foo bar bleh --app awesomeapp-demo")
- heroku_san.run('awesomeapp-demo', 'worker', 'foo bar bleh')
+ heroku_san.run('demo', 'worker', 'foo bar bleh')
end
end
end
+
+ describe "#create" do
+ it "creates an app on heroku" do
+ heroku_san.should_receive(:sh).with("heroku apps:create awesomeapp")
+ heroku_san.create('production')
+ end
+ end
describe "#create_config" do
it "creates a new file using the example file" do
@@ -158,5 +173,56 @@
heroku_san.create_config.should be_false
end
end
+
+ describe "#sharing_add" do
+ it "add collaborators" do
+ heroku_san.should_receive(:sh).with("heroku sharing:add email@example.com --app awesomeapp")
+ heroku_san.sharing_add('production', 'email@example.com')
+ end
+ end
+
+ describe "#sharing_remove" do
+ it "removes collaborators" do
+ heroku_san.should_receive(:sh).with("heroku sharing:remove email@example.com --app awesomeapp")
+ heroku_san.sharing_remove('production', 'email@example.com')
+ end
+ end
+
+ describe "#long_config" do
+ it "prints out the remote config" do
+ heroku_san.should_receive(:sh).with("heroku config --long --app awesomeapp") {
+<<EOT
+BUNDLE_WITHOUT => development:test
+DATABASE_URL => postgres://thnodhxrzn:T0-UwxLyFgXcnBSHmyhv@ec2-50-19-216-194.compute-1.amazonaws.com/thnodhxrzn
+LANG => en_US.UTF-8
+RACK_ENV => production
+SHARED_DATABASE_URL => postgres://thnodhxrzn:T0-UwxLyFgXcnBSHmyhv@ec2-50-19-216-194.compute-1.amazonaws.com/thnodhxrzn
+EOT
+ }
+ heroku_san.long_config('production')
+ end
+ end
+
+ describe "#capture" do
+ it "captures a bundle" do
+ heroku_san.should_receive(:sh).with("heroku bundles:capture --app awesomeapp")
+ heroku_san.capture('production')
+ end
+ end
+
+ describe "#restart" do
+ it "restarts an app" do
+ heroku_san.should_receive(:sh).with("heroku restart --app awesomeapp")
+ heroku_san.restart('production')
+ end
+ end
+
+ describe "#logs" do
+ it "returns log files" do
+ heroku_san.should_receive(:sh).with("heroku logs --app awesomeapp")
+ heroku_san.logs('production')
+ end
+ end
+
end
end

0 comments on commit 20be7f3

Please sign in to comment.
Something went wrong with that request. Please try again.