heroku_san 1.3.0 → 2.0.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/.rvmrc +1 -1
- data/README.rdoc +2 -1
- data/Rakefile +10 -2
- data/autotest/discover.rb +1 -0
- data/cucumber.yml +2 -0
- data/examples/auto_tagger.rake +62 -0
- data/features/{command_line.feature → config.feature} +34 -10
- data/features/extended-config.feature +5 -18
- data/features/remote.feature +57 -0
- data/features/support/env.rb +9 -0
- data/heroku_san.gemspec +8 -6
- data/lib/git.rb +39 -0
- data/lib/heroku_san/project.rb +111 -0
- data/lib/heroku_san/stage.rb +78 -0
- data/lib/heroku_san/version.rb +3 -0
- data/lib/heroku_san.rb +9 -1
- data/lib/{heroku_san/railtie.rb → railtie.rb} +1 -1
- data/lib/tasks/heroku.rake +1 -1
- data/lib/tasks.rb +284 -0
- data/lib/templates/heroku.example.yml +4 -1
- data/spec/fixtures/example.yml +26 -0
- data/spec/fixtures/extended_config.yml +7 -0
- data/spec/fixtures/old_format.yml +10 -0
- data/spec/fixtures/single_app.yml +6 -0
- data/spec/git_spec.rb +55 -0
- data/spec/heroku_san/project_spec.rb +107 -0
- data/spec/heroku_san/stage_spec.rb +138 -0
- data/spec/spec_helper.rb +21 -0
- metadata +69 -24
- data/lib/heroku_san/tasks.rb +0 -419
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm
|
1
|
+
rvm gemset use heroku_san --create
|
data/README.rdoc
CHANGED
@@ -121,7 +121,8 @@ Issue Tracker:: http://github.com/fastestforward/heroku_san/issues
|
|
121
121
|
* Jon Wood (jon@blankpad.net)
|
122
122
|
* Mat Schaffer (mat@schaffer.me)
|
123
123
|
* Jonathan Hironaga (jonathan.hironaga@halogennetwork.com)
|
124
|
+
* Ken Mayer (ken@bitwrangler.com)
|
124
125
|
|
125
126
|
== License
|
126
127
|
|
127
|
-
License:: Copyright (c) 2009 Elijah Miller <mailto:elijah.miller@gmail.com>, released under the MIT license.
|
128
|
+
License:: Copyright (c) 2009-2012 Elijah Miller <mailto:elijah.miller@gmail.com>, released under the MIT license.
|
data/Rakefile
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
require 'bundler'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
2
4
|
Bundler::GemHelper.install_tasks
|
3
5
|
|
4
|
-
desc 'Default:
|
5
|
-
task :default => :
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
desc "Run all specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.pattern = 'spec/**/*_spec.rb'
|
12
|
+
t.rspec_opts = ["-c", "-f progress"]
|
13
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/cucumber.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Support for auto_tagger (0.2.6) (http://github.com/zilkey/auto_tagger)
|
2
|
+
|
3
|
+
# Add the following to your ci build script
|
4
|
+
# this will create a tag if the build is successful
|
5
|
+
# rake ci-test-target autotag:create[ci]
|
6
|
+
|
7
|
+
# Add the following to your heroku.yml file:
|
8
|
+
# staging:
|
9
|
+
# tag: ci/*
|
10
|
+
#
|
11
|
+
# production:
|
12
|
+
# tag: staging/*
|
13
|
+
|
14
|
+
# Builds will be deployed in the following sequence:
|
15
|
+
# 1. ci passes, creates ci tag from HEAD
|
16
|
+
# 2. deploy latest ci tag to staging
|
17
|
+
# 3. deploy latest staging tag to production
|
18
|
+
|
19
|
+
STAGES = %w[ci staging production]
|
20
|
+
|
21
|
+
def create_and_push(stage)
|
22
|
+
auto_tag = AutoTagger::Base.new(stages: STAGES, stage: stage, verbose: true, push_refs: false, refs_to_keep: 100)
|
23
|
+
tag = auto_tag.create_ref(auto_tag.last_ref_from_previous_stage.try(:sha))
|
24
|
+
sh "git push origin #{tag.name}"
|
25
|
+
auto_tag.delete_locally
|
26
|
+
auto_tag.delete_on_remote
|
27
|
+
end
|
28
|
+
|
29
|
+
task :before_deploy do
|
30
|
+
sh "git fetch --tags"
|
31
|
+
end
|
32
|
+
|
33
|
+
task :after_deploy do
|
34
|
+
each_heroku_app do |stage|
|
35
|
+
create_and_push(stage.name)
|
36
|
+
end
|
37
|
+
Rake::Task['autotag:list'].invoke
|
38
|
+
end
|
39
|
+
|
40
|
+
namespace :autotag do
|
41
|
+
desc "Create an autotag for stage, default: #{STAGES.first}"
|
42
|
+
task :create, :stage do |t, args|
|
43
|
+
create_and_push(args[:stage] || STAGES.first)
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Show auto tagger history"
|
47
|
+
task :list do
|
48
|
+
puts "** AUTO TAGGER: release tag history:"
|
49
|
+
auto_tag = AutoTagger::Base.new(stages: STAGES, offline: true)
|
50
|
+
STAGES.each do |stage|
|
51
|
+
ref = auto_tag.refs_for_stage(stage).last
|
52
|
+
if ref
|
53
|
+
log = %x{git log -1 --format=oneline #{ref.sha}}.chomp
|
54
|
+
log = log[0..5] + log[40..-1]
|
55
|
+
else
|
56
|
+
log = "none"
|
57
|
+
end
|
58
|
+
puts " ** %-12s %s" % [stage, log]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Feature: Command Line
|
2
2
|
|
3
|
-
|
3
|
+
Background:
|
4
4
|
Given I run `rails new heroku_san_test -O`
|
5
5
|
And I cd to "heroku_san_test"
|
6
6
|
And I overwrite "Gemfile" with:
|
@@ -8,6 +8,8 @@ Feature: Command Line
|
|
8
8
|
source :rubygems
|
9
9
|
gem 'heroku_san', :path => '../../../.'
|
10
10
|
"""
|
11
|
+
|
12
|
+
Scenario: Config file can be formatted like Rails' database.yml
|
11
13
|
Given a file named "config/heroku.yml" with:
|
12
14
|
"""
|
13
15
|
production:
|
@@ -18,20 +20,13 @@ Feature: Command Line
|
|
18
20
|
app: awesomeapp-demo
|
19
21
|
"""
|
20
22
|
|
21
|
-
When I run `rake heroku:apps:local`
|
23
|
+
When I run `rake --trace heroku:apps:local`
|
22
24
|
|
23
25
|
Then the output should contain "production is shorthand for the Heroku app awesomeapp"
|
24
26
|
And the output should contain "staging is shorthand for the Heroku app awesomeapp-staging"
|
25
27
|
And the output should contain "demo is shorthand for the Heroku app awesomeapp-demo"
|
26
28
|
|
27
29
|
Scenario: Config file still accepts the heroku_san format
|
28
|
-
Given I run `rails new heroku_san_test -O`
|
29
|
-
And I cd to "heroku_san_test"
|
30
|
-
And I overwrite "Gemfile" with:
|
31
|
-
"""
|
32
|
-
source :rubygems
|
33
|
-
gem 'heroku_san', :path => '../../../.'
|
34
|
-
"""
|
35
30
|
Given a file named "config/heroku.yml" with:
|
36
31
|
"""
|
37
32
|
apps:
|
@@ -40,8 +35,37 @@ Feature: Command Line
|
|
40
35
|
demo: awesomeapp-demo
|
41
36
|
"""
|
42
37
|
|
43
|
-
When I run `rake heroku:apps:local`
|
38
|
+
When I run `rake --trace heroku:apps:local`
|
44
39
|
|
45
40
|
Then the output should contain "production is shorthand for the Heroku app awesomeapp"
|
46
41
|
And the output should contain "staging is shorthand for the Heroku app awesomeapp-staging"
|
47
42
|
And the output should contain "demo is shorthand for the Heroku app awesomeapp-demo"
|
43
|
+
|
44
|
+
Scenario: Tag information can be listed
|
45
|
+
Given a file named "config/heroku.yml" with:
|
46
|
+
"""
|
47
|
+
production:
|
48
|
+
app: awesomeapp
|
49
|
+
tag: ci/*
|
50
|
+
staging:
|
51
|
+
app: awesomeapp-staging
|
52
|
+
tag: staging/*
|
53
|
+
demo:
|
54
|
+
app: awesomeapp-demo
|
55
|
+
"""
|
56
|
+
|
57
|
+
When I run `rake --trace all heroku:apps:local`
|
58
|
+
|
59
|
+
Then the output should contain "the production TAG is 'ci/*'"
|
60
|
+
And the output should contain "the staging TAG is 'staging/*'"
|
61
|
+
|
62
|
+
Scenario: heroku:create_config
|
63
|
+
When I run `rake --trace heroku:create_config`
|
64
|
+
Then a file named "config/heroku.yml" should exist
|
65
|
+
And the output should match /Copied example config to ".*.config.heroku.yml"/
|
66
|
+
And the output should match /Please edit ".*.config.heroku.yml" with your application's settings./
|
67
|
+
|
68
|
+
Scenario: heroku:create_config with an EDITOR set in the environment
|
69
|
+
When I run `rake EDITOR=echo --trace heroku:create_config`
|
70
|
+
And the output should match /Copied example config to ".*.config.heroku.yml"/
|
71
|
+
And the output should match /^echo .*.config.heroku.yml$/
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Feature: Extended config
|
2
2
|
|
3
|
-
|
3
|
+
Background:
|
4
4
|
Given I run `rails new heroku_san_test -O`
|
5
5
|
And I cd to "heroku_san_test"
|
6
6
|
And I overwrite "Gemfile" with:
|
@@ -8,6 +8,7 @@ Feature: Extended config
|
|
8
8
|
source :rubygems
|
9
9
|
gem 'heroku_san', :path => '../../../.'
|
10
10
|
"""
|
11
|
+
Scenario: Config information can be pulled from a separate git repository
|
11
12
|
Given a file named "config/heroku.yml" with:
|
12
13
|
"""
|
13
14
|
config_repo: 'file:///<%= File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', 'features', 'data', 'test-config') %>'
|
@@ -19,19 +20,12 @@ Feature: Extended config
|
|
19
20
|
app: awesomeapp-demo
|
20
21
|
"""
|
21
22
|
|
22
|
-
When I run `rake all heroku:config:list:local`
|
23
|
+
When I run `rake --trace all heroku:config:list:local`
|
23
24
|
|
24
25
|
Then the output should contain "production TEST_REMOTE: 'hello_world'"
|
25
26
|
And the output should contain "staging TEST_REMOTE: 'goodbye_world'"
|
26
27
|
|
27
28
|
Scenario: Config information can be listed
|
28
|
-
Given I run `rails new heroku_san_test -O`
|
29
|
-
And I cd to "heroku_san_test"
|
30
|
-
And I overwrite "Gemfile" with:
|
31
|
-
"""
|
32
|
-
source :rubygems
|
33
|
-
gem 'heroku_san', :path => '../../../.'
|
34
|
-
"""
|
35
29
|
Given a file named "config/heroku.yml" with:
|
36
30
|
"""
|
37
31
|
production:
|
@@ -46,19 +40,12 @@ Feature: Extended config
|
|
46
40
|
app: awesomeapp-demo
|
47
41
|
"""
|
48
42
|
|
49
|
-
When I run `rake all heroku:config:list:local`
|
43
|
+
When I run `rake --trace all heroku:config:list:local`
|
50
44
|
|
51
45
|
Then the output should contain "production TEST_LOCAL: 'hello_world'"
|
52
46
|
And the output should contain "staging TEST_LOCAL: 'goodbye_world'"
|
53
47
|
|
54
48
|
Scenario: Config information can be merged between local and remote
|
55
|
-
Given I run `rails new heroku_san_test -O`
|
56
|
-
And I cd to "heroku_san_test"
|
57
|
-
And I overwrite "Gemfile" with:
|
58
|
-
"""
|
59
|
-
source :rubygems
|
60
|
-
gem 'heroku_san', :path => '../../../.'
|
61
|
-
"""
|
62
49
|
Given a file named "config/heroku.yml" with:
|
63
50
|
"""
|
64
51
|
config_repo: 'file:///<%= File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', 'features', 'data', 'test-config') %>'
|
@@ -73,7 +60,7 @@ Feature: Extended config
|
|
73
60
|
TEST_REMOTE: 'overridden_by_remote'
|
74
61
|
"""
|
75
62
|
|
76
|
-
When I run `rake all heroku:config:list:local`
|
63
|
+
When I run `rake --trace all heroku:config:list:local`
|
77
64
|
|
78
65
|
Then the output should contain "production TEST_LOCAL: 'hello_world'"
|
79
66
|
And the output should contain "production TEST_REMOTE: 'hello_world'"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
@announce @slow_process
|
2
|
+
Feature: Works with Heroku
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given I run `git clone git://github.com/kmayer/heroku_san_demo.git`
|
6
|
+
And I cd to "heroku_san_demo"
|
7
|
+
And I run `bundle install`
|
8
|
+
|
9
|
+
Scenario: Remote commands
|
10
|
+
When I run `rake demo deploy`
|
11
|
+
Then the output should match /(http:.*-demo.heroku.com deployed to Heroku)|(Everything up-to-date)/
|
12
|
+
|
13
|
+
When I run `rake demo heroku:maintenance_on`
|
14
|
+
Then the output should contain "Maintenance mode enabled."
|
15
|
+
|
16
|
+
When I run `rake demo restart`
|
17
|
+
Then the output should contain "Restarting processes... done"
|
18
|
+
|
19
|
+
When I run `rake demo heroku:maintenance_off`
|
20
|
+
Then the output should contain "Maintenance mode disabled."
|
21
|
+
|
22
|
+
When I run `rake demo heroku:rake[db:seed]`
|
23
|
+
Then I run `curl -s http://heroku-san-demo-demo.heroku.com/droids.text`
|
24
|
+
And the output should contain "C3PO, Marvin, R2D2, Robby"
|
25
|
+
|
26
|
+
When I run `rake demo logs`
|
27
|
+
Then the output should contain "Starting process with command `rake db:seed`"
|
28
|
+
|
29
|
+
When I run `git co staging`
|
30
|
+
And I run `rake deploy`
|
31
|
+
Then the output should contain "Defaulting to 'staging' as it matches the current branch"
|
32
|
+
Then the output should match /(http:.*-staging.heroku.com deployed to Heroku)|(Everything up-to-date)/
|
33
|
+
When I run `curl -s http://heroku-san-demo-staging.heroku.com`
|
34
|
+
And the output should contain "Ruby on Rails: Welcome aboard"
|
35
|
+
|
36
|
+
When I run `rake production deploy:force`
|
37
|
+
Then the output should match /^git update-ref refs.heroku_san.deploy \w{40}$/
|
38
|
+
# Runs a before_deploy
|
39
|
+
# Runs an after_deploy
|
40
|
+
# Adds a collaborator
|
41
|
+
|
42
|
+
# Given I run `rake heroku:create_config`
|
43
|
+
|
44
|
+
# When I run `rake demo heroku:create`
|
45
|
+
# Then the output should contain "somthing about the created app"
|
46
|
+
# $ rake all heroku:create
|
47
|
+
# heroku create heroku-san-demo-demo
|
48
|
+
# Creating heroku-san-demo-demo.... done, stack is bamboo-mri-1.9.2
|
49
|
+
# http://heroku-san-demo-demo.heroku.com/ | git@heroku.com:heroku-san-demo-demo.git
|
50
|
+
# Git remote heroku added
|
51
|
+
# heroku create heroku-san-demo-production
|
52
|
+
# Creating heroku-san-demo-production... done, stack is bamboo-mri-1.9.2
|
53
|
+
# http://heroku-san-demo-production.heroku.com/ | git@heroku.com:heroku-san-demo-production.git
|
54
|
+
# heroku create heroku-san-demo-staging
|
55
|
+
# Creating heroku-san-demo-staging... done, stack is bamboo-mri-1.9.2
|
56
|
+
# http://heroku-san-demo-staging.heroku.com/ | git@heroku.com:heroku-san-demo-staging.git
|
57
|
+
|
data/features/support/env.rb
CHANGED
@@ -6,3 +6,12 @@ require 'aruba/cucumber'
|
|
6
6
|
unless File.readable? File.join(File.dirname(__FILE__), '..', 'data', 'test-config', 'config.yml')
|
7
7
|
`git submodule init && git submodule update`
|
8
8
|
end
|
9
|
+
|
10
|
+
Before do
|
11
|
+
@aruba_timeout_seconds = 15
|
12
|
+
end
|
13
|
+
|
14
|
+
Before('@slow_process') do
|
15
|
+
@aruba_timeout_seconds = 60
|
16
|
+
# @aruba_io_wait_seconds = 15
|
17
|
+
end
|
data/heroku_san.gemspec
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
require File.join(File.dirname(__FILE__), 'lib/heroku_san/version')
|
2
3
|
|
3
4
|
Gem::Specification.new do |s|
|
4
5
|
s.name = %q{heroku_san}
|
5
|
-
|
6
|
-
s.version = "1.3.0"
|
7
|
-
s.date = %q{2011-11-07}
|
6
|
+
s.version = HerokuSan::VERSION
|
8
7
|
|
9
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
|
-
|
9
|
+
|
10
|
+
s.authors = ["Elijah Miller", "Glenn Roberts", "Ryan Ahearn", "Ken Mayer"]
|
11
11
|
s.description = %q{Manage multiple Heroku instances/apps for a single Rails app using Rake}
|
12
12
|
s.email = %q{elijah.miller@gmail.com}
|
13
|
-
s.homepage = %q{http://github.com/
|
13
|
+
s.homepage = %q{http://github.com/fastestforward/heroku_san}
|
14
14
|
s.files = `git ls-files`.split("\n")
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
16
|
s.require_paths = ["lib"]
|
@@ -24,9 +24,11 @@ Gem::Specification.new do |s|
|
|
24
24
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
25
|
s.add_runtime_dependency(%q<rails>, ['>= 2'])
|
26
26
|
s.add_runtime_dependency(%q<heroku>, ['>= 2'])
|
27
|
-
s.
|
27
|
+
s.add_runtime_dependency(%q<rake>)
|
28
28
|
s.add_development_dependency(%q<aruba>)
|
29
29
|
s.add_development_dependency(%q<cucumber>)
|
30
|
+
s.add_development_dependency(%q<rake>)
|
31
|
+
s.add_development_dependency(%q<bundler>, ['~> 1.0'])
|
30
32
|
else
|
31
33
|
s.add_dependency(%q<rails>, ['>= 2'])
|
32
34
|
s.add_dependency(%q<heroku>, ['>= 2'])
|
data/lib/git.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/dsl_definition'
|
3
|
+
|
4
|
+
module Git
|
5
|
+
include Rake::DSL
|
6
|
+
|
7
|
+
def git_clone(repos, dir)
|
8
|
+
sh "git clone #{repos} #{dir}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def git_active_branch
|
12
|
+
%x{git branch}.split("\n").select { |b| b =~ /^\*/ }.first.split(" ").last.strip
|
13
|
+
end
|
14
|
+
|
15
|
+
def git_push(commit, repo, options = [])
|
16
|
+
commit ||= "HEAD"
|
17
|
+
options ||= []
|
18
|
+
begin
|
19
|
+
sh "git update-ref refs/heroku_san/deploy #{commit}"
|
20
|
+
sh "git push #{repo} #{options.join(' ')} refs/heroku_san/deploy:refs/heads/master"
|
21
|
+
ensure
|
22
|
+
sh "git update-ref -d refs/heroku_san/deploy"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def git_tag(glob)
|
27
|
+
return nil if glob.nil?
|
28
|
+
%x{git tag -l '#{glob}'}.split("\n").last
|
29
|
+
end
|
30
|
+
|
31
|
+
def git_rev_parse(ref)
|
32
|
+
return nil if ref.nil?
|
33
|
+
%x{git rev-parse #{ref}}.split("\n").first
|
34
|
+
end
|
35
|
+
|
36
|
+
def git_parsed_tag(tag)
|
37
|
+
git_rev_parse(git_tag(tag))
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module HerokuSan
|
2
|
+
class Project
|
3
|
+
attr_reader :config_file
|
4
|
+
|
5
|
+
include Git
|
6
|
+
|
7
|
+
def initialize(config_file)
|
8
|
+
@apps = []
|
9
|
+
@config_file = config_file
|
10
|
+
@app_settings = {}
|
11
|
+
config = parse(@config_file)
|
12
|
+
config.each do |stage, settings|
|
13
|
+
@app_settings[stage] = HerokuSan::Stage.new(stage, settings)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_config
|
18
|
+
template = File.expand_path(File.join(File.dirname(__FILE__), '../templates', 'heroku.example.yml'))
|
19
|
+
if File.exists?(@config_file)
|
20
|
+
false
|
21
|
+
else
|
22
|
+
FileUtils.cp(template, @config_file)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def all
|
28
|
+
@app_settings.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](stage)
|
32
|
+
@app_settings[stage]
|
33
|
+
end
|
34
|
+
|
35
|
+
def <<(*app)
|
36
|
+
app.flatten.each do |a|
|
37
|
+
@apps << a if all.include?(a)
|
38
|
+
end
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def apps
|
43
|
+
if !@apps.empty?
|
44
|
+
@apps
|
45
|
+
else
|
46
|
+
case all.size
|
47
|
+
when 1
|
48
|
+
$stdout.puts "Defaulting to #{all.first.inspect} since only one app is defined"
|
49
|
+
all
|
50
|
+
else
|
51
|
+
active_branch = self.git_active_branch
|
52
|
+
all.select do |app|
|
53
|
+
app == active_branch and ($stdout.puts("Defaulting to '#{app}' as it matches the current branch") || true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def each_app
|
60
|
+
raise NoApps if apps.empty?
|
61
|
+
apps.each do |stage|
|
62
|
+
yield(self[stage])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def parse_yaml(config_file)
|
69
|
+
if File.exists?(config_file)
|
70
|
+
if defined?(ERB)
|
71
|
+
YAML.load(ERB.new(File.read(config_file)).result)
|
72
|
+
else
|
73
|
+
YAML.load_file(config_file)
|
74
|
+
end
|
75
|
+
else
|
76
|
+
{}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse(config_file)
|
81
|
+
app_settings = parse_yaml(config_file)
|
82
|
+
|
83
|
+
# support heroku_san format
|
84
|
+
if app_settings.has_key? 'apps'
|
85
|
+
app_settings = app_settings['apps']
|
86
|
+
app_settings.each_pair do |stage, app_name|
|
87
|
+
app_settings[stage] = {'app' => app_name}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# load external config
|
92
|
+
if (config_repo = app_settings.delete('config_repo'))
|
93
|
+
require 'tmpdir'
|
94
|
+
tmp_config_dir = Dir.mktmpdir
|
95
|
+
tmp_config_file = File.join tmp_config_dir, 'config.yml'
|
96
|
+
git_clone(config_repo, tmp_config_dir)
|
97
|
+
extra_config = parse_yaml(tmp_config_file)
|
98
|
+
else
|
99
|
+
extra_config = {}
|
100
|
+
end
|
101
|
+
|
102
|
+
# make sure each app has a 'config' section & merge w/extra
|
103
|
+
app_settings.keys.each do |name|
|
104
|
+
app_settings[name]['config'] ||= {}
|
105
|
+
app_settings[name]['config'].merge!(extra_config[name]) if extra_config[name]
|
106
|
+
end
|
107
|
+
|
108
|
+
app_settings
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module HerokuSan
|
2
|
+
class Stage
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(stage, options = {})
|
6
|
+
@name = stage
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def app
|
11
|
+
@options['app']
|
12
|
+
end
|
13
|
+
|
14
|
+
def repo
|
15
|
+
@options['repo'] ||= "git@heroku.com:#{app}.git"
|
16
|
+
end
|
17
|
+
|
18
|
+
def stack
|
19
|
+
@options['stack'] ||= %x"heroku stack --app #{app}".split("\n").select { |b| b =~ /^\* / }.first.gsub(/^\* /, '')
|
20
|
+
end
|
21
|
+
|
22
|
+
def tag
|
23
|
+
@options['tag']
|
24
|
+
end
|
25
|
+
|
26
|
+
def config
|
27
|
+
@options['config'] ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def run(command, args = nil)
|
31
|
+
if stack =~ /cedar/
|
32
|
+
sh_heroku "run #{command} #{args}"
|
33
|
+
else
|
34
|
+
sh_heroku "run:#{command} #{args}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def migrate
|
39
|
+
run 'rake', 'db:migrate'
|
40
|
+
sh_heroku "restart"
|
41
|
+
end
|
42
|
+
|
43
|
+
def maintenance(action)
|
44
|
+
raise ArgumentError, "Action #{action.inspect} must be one of (:on, :off)", caller if ![:on, :off].include?(action)
|
45
|
+
sh_heroku "maintenance:#{action}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def create
|
49
|
+
sh "heroku apps:create #{app}" + (@options['stack'] ? " --stack #{@options['stack']}" : '')
|
50
|
+
end
|
51
|
+
|
52
|
+
def sharing_add(email)
|
53
|
+
sh_heroku "sharing:add #{email.chomp}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def sharing_remove(email)
|
57
|
+
sh_heroku "sharing:remove #{email.chomp}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def long_config
|
61
|
+
sh_heroku 'config --long'
|
62
|
+
end
|
63
|
+
|
64
|
+
def restart
|
65
|
+
sh_heroku 'restart'
|
66
|
+
end
|
67
|
+
|
68
|
+
def logs
|
69
|
+
sh_heroku 'logs'
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def sh_heroku command
|
75
|
+
sh "heroku #{command} --app #{app}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/heroku_san.rb
CHANGED
@@ -1 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'railtie' if defined?(Rails) && Rails::VERSION::MAJOR == 3
|
2
|
+
require 'git'
|
3
|
+
require 'heroku_san/stage'
|
4
|
+
require 'heroku_san/project'
|
5
|
+
|
6
|
+
module HerokuSan
|
7
|
+
class NoApps < StandardError; end
|
8
|
+
class Deprecated < StandardError; end
|
9
|
+
end
|
data/lib/tasks/heroku.rake
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', '
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'tasks'))
|