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.
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-head
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - jruby-head
7
+ - jruby-19mode
8
+
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
@@ -17,6 +17,7 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_runtime_dependency "heroku-api"
19
19
  gem.add_runtime_dependency "rendezvous"
20
+ gem.add_development_dependency "rake"
20
21
  gem.add_development_dependency "rspec"
21
22
  gem.add_development_dependency "pry"
22
23
  end
@@ -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
@@ -1,30 +1,38 @@
1
1
  require "heroku-headless/version"
2
2
 
3
3
  require "heroku-headless/documents_actions"
4
- require "heroku-headless/creates_uuids"
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
- attr_accessor :configuration
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
@@ -0,0 +1,10 @@
1
+ require 'securerandom'
2
+
3
+ module HerokuHeadless
4
+ module CreatesUIDs
5
+ def generate_uid
6
+ SecureRandom.hex(16).downcase
7
+ end
8
+ module_function :generate_uid
9
+ end
10
+ end
@@ -8,7 +8,7 @@ module HerokuHeadless
8
8
  include TalksToHeroku
9
9
 
10
10
  def self.deploy(app_name)
11
- new(app_name,CreatesUUIDs.generate_lowercase_uuid).deploy
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}, "git push git@heroku.com:#{@app_name}.git HEAD:master" )
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-#{deploy_uuid}"[0,30]
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,deploy_uuid).deploy
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 deploy_uuid
51
- @deploy_uuid ||= CreatesUUIDs.generate_lowercase_uuid
50
+ def deploy_uid
51
+ @deploy_uid ||= CreatesUIDs.generate_uid
52
52
  end
53
53
  end
54
54
  end
@@ -2,8 +2,9 @@ module HerokuHeadless
2
2
  module DocumentsActions
3
3
  def do_action(description)
4
4
  print " " + description + " ..."
5
- yield
5
+ result = yield
6
6
  puts " DONE"
7
+ result
7
8
  end
8
9
  end
9
10
  end
@@ -1,3 +1,3 @@
1
1
  module HerokuHeadless
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -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
- $?.exitstatus.should_not eq 0
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
- $?.exitstatus.should eq 0
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
- $?.exitstatus.should eq 0
33
+ result = HerokuHeadless::Deployer.deploy('app_with_db')
34
+ result.should be_true
35
35
  end
36
- end
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.0
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-04-10 00:00:00.000000000 Z
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/creates_uuids.rb
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.24
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.
@@ -1,8 +0,0 @@
1
- module HerokuHeadless
2
- module CreatesUUIDs
3
- def generate_lowercase_uuid
4
- `uuidgen`.chomp.downcase
5
- end
6
- module_function :generate_lowercase_uuid
7
- end
8
- end