heroku-headless 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +8 -0
- data/README.md +66 -0
- data/Rakefile +4 -2
- data/heroku-headless.gemspec +1 -0
- data/integration/configuration_spec.rb +10 -0
- data/lib/heroku-headless.rb +13 -5
- data/lib/heroku-headless/creates_uids.rb +10 -0
- data/lib/heroku-headless/deployer.rb +32 -7
- data/lib/heroku-headless/disposable_deployer.rb +4 -4
- data/lib/heroku-headless/documents_actions.rb +2 -1
- data/lib/heroku-headless/version.rb +1 -1
- data/spec/deploy_spec.rb +67 -9
- metadata +28 -4
- data/lib/heroku-headless/creates_uuids.rb +0 -8
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/moredip/heroku-headless.png?branch=master)](http://travis-ci.org/moredip/heroku-headless)
|
2
|
+
[![Dependency Status](https://gemnasium.com/moredip/heroku-headless.png?travis)](https://gemnasium.com/moredip/heroku-headless)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/moredip/heroku-headless.png)](https://codeclimate.com/github/moredip/heroku-headless)
|
4
|
+
|
1
5
|
# HerokuHeadless
|
2
6
|
|
3
7
|
## What?
|
@@ -19,3 +23,65 @@ And then execute:
|
|
19
23
|
Or install it yourself as:
|
20
24
|
|
21
25
|
$ gem install heroku-headless
|
26
|
+
|
27
|
+
## How do I use this?
|
28
|
+
It's as simple as
|
29
|
+
```ruby
|
30
|
+
require 'heroku-headless'
|
31
|
+
HerokuHeadless::Deployer.deploy( 'your-app-name' )
|
32
|
+
```
|
33
|
+
|
34
|
+
### Use it with pre- and post-commands:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
require 'heroku-headless'
|
38
|
+
|
39
|
+
app_name = 'my-heroku-app-name'
|
40
|
+
remote_name = 'herokuheadless'
|
41
|
+
|
42
|
+
puts "deploying to heroku app #{app_name}"
|
43
|
+
remote_name = "headlessheroku"
|
44
|
+
HerokuHeadless.configure do | config |
|
45
|
+
config.post_deploy_commands = ['rake db:migrate']
|
46
|
+
config.pre_deploy_git_commands = [
|
47
|
+
"git remote -v",
|
48
|
+
"git checkout master",
|
49
|
+
"git commit -am \"changes from headless deploy\" ",
|
50
|
+
"git remote add #{remote_name} git@heroku.com:#{app_name}.git",
|
51
|
+
"git fetch #{remote_name}",
|
52
|
+
"git merge -m \"merged by automatic deploy\" #{remote_name}/master"]
|
53
|
+
end
|
54
|
+
|
55
|
+
result = HerokuHeadless::Deployer.deploy( app_name )
|
56
|
+
puts "successfully deployed to #{app_name}" if result
|
57
|
+
exit result ? 0 : 1
|
58
|
+
|
59
|
+
```
|
60
|
+
|
61
|
+
### Restart processes after deployment and post-commands:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
require 'heroku-headless'
|
65
|
+
|
66
|
+
app_name = 'my-heroku-app-name'
|
67
|
+
remote_name = 'herokuheadless'
|
68
|
+
|
69
|
+
puts "deploying to heroku app #{app_name}"
|
70
|
+
remote_name = "headlessheroku"
|
71
|
+
HerokuHeadless.configure do | config |
|
72
|
+
config.post_deploy_commands = ['rake db:migrate']
|
73
|
+
config.restart_processes = true
|
74
|
+
end
|
75
|
+
|
76
|
+
result = HerokuHeadless::Deployer.deploy( app_name )
|
77
|
+
puts "successfully deployed to #{app_name}" if result
|
78
|
+
exit result ? 0 : 1
|
79
|
+
|
80
|
+
```
|
81
|
+
|
82
|
+
|
83
|
+
## Tell me more!
|
84
|
+
|
85
|
+
[Deploying To Heroku From CI](http://blog.thepete.net/blog/2013/01/21/deploying-to-heroku-from-ci)
|
86
|
+
|
87
|
+
[Deploying to Heroku From CI - the Gory Details](http://blog.thepete.net/blog/2013/01/22/deploying-to-heroku-from-ci-the-gory-details/)
|
data/Rakefile
CHANGED
@@ -3,7 +3,9 @@ require "bundler/gem_tasks"
|
|
3
3
|
require 'rspec/core/rake_task'
|
4
4
|
|
5
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
RSpec::Core::RakeTask.new(:integration) do | spec |
|
7
|
+
spec.pattern = 'integration/**/*_spec.rb'
|
8
|
+
end
|
6
9
|
|
10
|
+
task :default => [:spec, :integration]
|
7
11
|
task :build => :spec
|
8
|
-
|
9
|
-
task :default => :spec
|
data/heroku-headless.gemspec
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'heroku-headless'
|
3
|
+
# Do not include spec_helper, because it has a HerokuHeadless.configure block
|
4
|
+
|
5
|
+
describe 'HerokuHeadless' do
|
6
|
+
it "should have a default configuration" do
|
7
|
+
HerokuHeadless.configuration = nil
|
8
|
+
HerokuHeadless.configuration.mock_mode.should == false
|
9
|
+
end
|
10
|
+
end
|
data/lib/heroku-headless.rb
CHANGED
@@ -1,30 +1,38 @@
|
|
1
1
|
require "heroku-headless/version"
|
2
2
|
|
3
3
|
require "heroku-headless/documents_actions"
|
4
|
-
require "heroku-headless/
|
4
|
+
require "heroku-headless/creates_uids"
|
5
5
|
require "heroku-headless/talks_to_heroku"
|
6
6
|
|
7
7
|
require "heroku-headless/deployer"
|
8
8
|
|
9
9
|
module HerokuHeadless
|
10
10
|
class << self
|
11
|
-
|
11
|
+
attr_writer :configuration
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.configure
|
15
|
-
self.configuration ||= Configuration.new
|
16
15
|
yield(configuration)
|
17
16
|
end
|
18
17
|
|
18
|
+
def self.configuration
|
19
|
+
@configuration ||= Configuration.new
|
20
|
+
end
|
21
|
+
|
19
22
|
def self.heroku
|
20
23
|
@@heroku ||= Heroku::API.new(:mock => HerokuHeadless.configuration.mock_mode)
|
21
24
|
end
|
22
25
|
|
23
26
|
class Configuration
|
24
|
-
attr_accessor :mock_mode, :post_deploy_commands
|
27
|
+
attr_accessor :mock_mode, :pre_deploy_git_commands, :post_deploy_commands,
|
28
|
+
:force_push, :restart_processes
|
25
29
|
|
26
30
|
def initialize
|
31
|
+
@pre_deploy_git_commands = []
|
27
32
|
@post_deploy_commands = []
|
33
|
+
@force_push ||= false
|
34
|
+
@mock_mode ||= false
|
35
|
+
@restart_processes ||= false
|
28
36
|
end
|
29
37
|
end
|
30
|
-
end
|
38
|
+
end
|
@@ -8,7 +8,7 @@ module HerokuHeadless
|
|
8
8
|
include TalksToHeroku
|
9
9
|
|
10
10
|
def self.deploy(app_name)
|
11
|
-
new(app_name,
|
11
|
+
new(app_name,CreatesUIDs.generate_uid).deploy
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize( app_name, uid )
|
@@ -19,14 +19,17 @@ module HerokuHeadless
|
|
19
19
|
def deploy
|
20
20
|
prep_temp_dir
|
21
21
|
setup_ssh_key
|
22
|
-
do_action('push git to heroku'){ push_head_to_app }
|
23
|
-
do_action('post_deploy_hooks'){ run_post_deploy_hooks }
|
24
|
-
|
22
|
+
result = do_action('push git to heroku'){ push_head_to_app }
|
23
|
+
result = result && do_action('post_deploy_hooks'){ run_post_deploy_hooks }
|
24
|
+
if HerokuHeadless.configuration.restart_processes
|
25
|
+
result = result && do_action('restart_processes'){ restart_processes }
|
26
|
+
end
|
27
|
+
result
|
25
28
|
ensure
|
26
29
|
cleanup
|
27
30
|
end
|
28
31
|
|
29
|
-
private
|
32
|
+
private
|
30
33
|
|
31
34
|
def prep_temp_dir
|
32
35
|
@tmpdir = Pathname.new( Dir.tmpdir ).join('heroku-deployer').join(@uid)
|
@@ -66,13 +69,14 @@ module HerokuHeadless
|
|
66
69
|
def add_ssh_key
|
67
70
|
heroku.post_key(public_ssh_key)
|
68
71
|
end
|
69
|
-
|
72
|
+
|
70
73
|
def remove_ssh_key
|
71
74
|
heroku.delete_key(ssh_key_name)
|
72
75
|
end
|
73
76
|
|
74
77
|
def push_head_to_app
|
75
78
|
setup_custom_git_ssh
|
79
|
+
run_pre_deploy_git_commands
|
76
80
|
push_git
|
77
81
|
end
|
78
82
|
|
@@ -87,7 +91,23 @@ module HerokuHeadless
|
|
87
91
|
end
|
88
92
|
|
89
93
|
def push_git
|
90
|
-
system( {'GIT_SSH'=>custom_git_ssh_path.to_s},
|
94
|
+
system( {'GIT_SSH'=>custom_git_ssh_path.to_s}, git_push_command )
|
95
|
+
end
|
96
|
+
|
97
|
+
def git_push_command
|
98
|
+
cmd = "git push "
|
99
|
+
cmd << "-f " if HerokuHeadless.configuration.force_push
|
100
|
+
cmd << "git@heroku.com:#{@app_name}.git HEAD:master"
|
101
|
+
end
|
102
|
+
|
103
|
+
def run_pre_deploy_git_commands
|
104
|
+
HerokuHeadless.configuration.pre_deploy_git_commands.each do | command |
|
105
|
+
do_action( command ) { run_git_command(command) }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
def run_git_command(command)
|
109
|
+
result = system( {'GIT_SSH'=>custom_git_ssh_path.to_s}, command )
|
110
|
+
result
|
91
111
|
end
|
92
112
|
|
93
113
|
def run_post_deploy_hooks
|
@@ -96,6 +116,11 @@ module HerokuHeadless
|
|
96
116
|
end
|
97
117
|
end
|
98
118
|
|
119
|
+
def restart_processes
|
120
|
+
response = heroku.post_ps_restart(@app_name)
|
121
|
+
response.body == "ok"
|
122
|
+
end
|
123
|
+
|
99
124
|
def run_command(cmd)
|
100
125
|
data = heroku.post_ps(@app_name, cmd, :attach => true).body
|
101
126
|
rendezvous_url = data['rendezvous_url']
|
@@ -26,13 +26,13 @@ module HerokuHeadless
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def create_app
|
29
|
-
app_name = "disposable-#{
|
29
|
+
app_name = "disposable-#{deploy_uid}"[0,30]
|
30
30
|
heroku.post_app( name: app_name )
|
31
31
|
@app_name = app_name
|
32
32
|
end
|
33
33
|
|
34
34
|
def deploy_app
|
35
|
-
Deployer.new(@app_name,
|
35
|
+
Deployer.new(@app_name,deploy_uid).deploy
|
36
36
|
end
|
37
37
|
|
38
38
|
def cleanup
|
@@ -47,8 +47,8 @@ module HerokuHeadless
|
|
47
47
|
heroku.delete_app( @app_name ) if @app_name
|
48
48
|
end
|
49
49
|
|
50
|
-
def
|
51
|
-
@
|
50
|
+
def deploy_uid
|
51
|
+
@deploy_uid ||= CreatesUIDs.generate_uid
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
data/spec/deploy_spec.rb
CHANGED
@@ -4,16 +4,16 @@ describe 'HerokuHeadless' do
|
|
4
4
|
let(:heroku) { HerokuHeadless.heroku }
|
5
5
|
|
6
6
|
it "should fail to deploy a missing app" do
|
7
|
-
HerokuHeadless::Deployer.deploy('missing_app')
|
8
|
-
|
7
|
+
result = HerokuHeadless::Deployer.deploy('missing_app')
|
8
|
+
result.should be_false
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should successfully deploy an existing app" do
|
12
12
|
heroku.post_app(:name => 'existing_app')
|
13
13
|
# Creating an app on heroku actually isn't enough to make the git push pass!
|
14
|
-
HerokuHeadless::Deployer.any_instance.should_receive(:push_git)
|
15
|
-
HerokuHeadless::Deployer.deploy('existing_app')
|
16
|
-
|
14
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:push_git).and_return(true)
|
15
|
+
result = HerokuHeadless::Deployer.deploy('existing_app')
|
16
|
+
result.should be_true
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should call post-deploy actions" do
|
@@ -26,11 +26,69 @@ describe 'HerokuHeadless' do
|
|
26
26
|
]
|
27
27
|
end
|
28
28
|
|
29
|
-
HerokuHeadless::Deployer.any_instance.should_receive(:push_git)
|
29
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:push_git).and_return(true)
|
30
30
|
HerokuHeadless::Deployer.any_instance.should_receive(:run_command).with('echo hello')
|
31
31
|
HerokuHeadless::Deployer.any_instance.should_receive(:run_command).with('echo success')
|
32
32
|
|
33
|
-
HerokuHeadless::Deployer.deploy('app_with_db')
|
34
|
-
|
33
|
+
result = HerokuHeadless::Deployer.deploy('app_with_db')
|
34
|
+
result.should be_true
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
|
+
it "should restart the app if configured" do
|
38
|
+
heroku.post_app(:name => 'app_with_restart')
|
39
|
+
|
40
|
+
HerokuHeadless.configure do | config |
|
41
|
+
config.restart_processes = true
|
42
|
+
end
|
43
|
+
|
44
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:push_git).and_return(true)
|
45
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:restart_processes).and_call_original
|
46
|
+
|
47
|
+
result = HerokuHeadless::Deployer.deploy('app_with_restart')
|
48
|
+
result.should be_true
|
49
|
+
end
|
50
|
+
|
51
|
+
context "forced pushs" do
|
52
|
+
let(:headless) { HerokuHeadless::Deployer.new("forced_app", HerokuHeadless::CreatesUIDs.generate_uid) }
|
53
|
+
subject { headless.send(:git_push_command) }
|
54
|
+
|
55
|
+
context "enabled forced push" do
|
56
|
+
before do
|
57
|
+
HerokuHeadless.configure do | config |
|
58
|
+
config.force_push = true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
it {should eq "git push -f git@heroku.com:forced_app.git HEAD:master"}
|
62
|
+
end
|
63
|
+
|
64
|
+
context "disabled forced push" do
|
65
|
+
before do
|
66
|
+
HerokuHeadless.configure do | config |
|
67
|
+
config.force_push = false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
it {should eq "git push git@heroku.com:forced_app.git HEAD:master"}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should run the git pre-deploy commands" do
|
75
|
+
@app_name = 'app_with_configuration_changes'
|
76
|
+
heroku.post_app(:name => @app_name)
|
77
|
+
HerokuHeadless.configure do | config |
|
78
|
+
config.pre_deploy_git_commands = [
|
79
|
+
"git checkout master",
|
80
|
+
"git remote add heroku git@heroku.com:#{@app_name}.git"
|
81
|
+
]
|
82
|
+
end
|
83
|
+
|
84
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:push_git).and_return(true)
|
85
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:run_git_command).with("git checkout master")
|
86
|
+
HerokuHeadless::Deployer.any_instance.should_receive(:run_git_command).with("git remote add heroku git@heroku.com:#{@app_name}.git")
|
87
|
+
|
88
|
+
result = HerokuHeadless::Deployer.deploy(@app_name)
|
89
|
+
result.should be_true
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heroku-headless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-06-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: heroku-api
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: rspec
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -83,13 +99,15 @@ extensions: []
|
|
83
99
|
extra_rdoc_files: []
|
84
100
|
files:
|
85
101
|
- .gitignore
|
102
|
+
- .travis.yml
|
86
103
|
- Gemfile
|
87
104
|
- LICENSE
|
88
105
|
- README.md
|
89
106
|
- Rakefile
|
90
107
|
- heroku-headless.gemspec
|
108
|
+
- integration/configuration_spec.rb
|
91
109
|
- lib/heroku-headless.rb
|
92
|
-
- lib/heroku-headless/
|
110
|
+
- lib/heroku-headless/creates_uids.rb
|
93
111
|
- lib/heroku-headless/deployer.rb
|
94
112
|
- lib/heroku-headless/disposable_app_deleter.rb
|
95
113
|
- lib/heroku-headless/disposable_deployer.rb
|
@@ -110,15 +128,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
128
|
- - ! '>='
|
111
129
|
- !ruby/object:Gem::Version
|
112
130
|
version: '0'
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
hash: 3232932552037509403
|
113
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
135
|
none: false
|
115
136
|
requirements:
|
116
137
|
- - ! '>='
|
117
138
|
- !ruby/object:Gem::Version
|
118
139
|
version: '0'
|
140
|
+
segments:
|
141
|
+
- 0
|
142
|
+
hash: 3232932552037509403
|
119
143
|
requirements: []
|
120
144
|
rubyforge_project:
|
121
|
-
rubygems_version: 1.8.
|
145
|
+
rubygems_version: 1.8.25
|
122
146
|
signing_key:
|
123
147
|
specification_version: 3
|
124
148
|
summary: Heroku's workflow is geared towards pushing to a heroku app from a dev workstation.
|