heroku_san 1.3.0 → 2.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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'))
|