kumade 0.0.2 → 0.0.3

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.
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.8.7
4
+ - ree-1.8.7
5
+ # branches:
6
+ # only:
7
+ # - master
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Kumade
1
+ # Kumade [![Build Status](https://secure.travis-ci.org/gabebw/kumade.png)](http://travis-ci.org/gabebw/kumade)
2
2
  Kumade is a set of basic Rake tasks for deploying to Heroku. It aims to
3
3
  provide most of what you want. Unlike other Heroku deploy gems, it is
4
4
  well-tested.
@@ -7,11 +7,11 @@ well-tested.
7
7
  Before deploying, Kumade ensures the git repo is clean and that all tests pass.
8
8
  After that, it packages assets using
9
9
  [Jammit](http://documentcloud.github.com/jammit/) and/or
10
- [More](https://github.com/cloudhead/more), commits them, and pushes to
11
- origin. Then it force pushes to the staging or production remote as
12
- appropriate and runs `rake db:migrate` on the Heroku app.
10
+ [More](https://github.com/cloudhead/more), commits them, and pushes to origin.
11
+ Then it force pushes to the correct remote and runs `rake db:migrate` on the
12
+ Heroku app.
13
13
 
14
- If any step fails, it immediately raises an error and stops the deploy
14
+ If any step fails, it immediately prints an error and stops the deploy
15
15
  process.
16
16
 
17
17
  ## Install
@@ -22,50 +22,109 @@ gem 'kumade'
22
22
  ```
23
23
 
24
24
  ## Usage
25
- In your Rakefile:
25
+ kumade will deploy to any remote in the repo.
26
+ For example, if you have a remote named "bamboo":
27
+
28
+ $ kumade deploy bamboo
29
+
30
+ which will autodetect the name of the Heroku app that the bamboo remote points
31
+ to, and deploy to it.
32
+
33
+ To run in pretend mode, which just prints what would be done:
34
+
35
+ $ kumade deploy bamboo -p
36
+
37
+ The default task is to deploy to staging:
38
+
39
+ $ kumade # equivalent to "kumade deploy staging"
40
+
41
+ ## Sample Output
42
+
43
+ ### Normal mode
44
+
45
+ $ kumade deploy heroku-staging
46
+ ==> Deploying to: heroku-staging
47
+ ==> heroku-staging is a Heroku remote
48
+ ==> Git repo is clean
49
+ /Users/gabe/.rvm/rubies/ree-1.8.7-2011.03/bin/ruby -S bundle exec rspec [blah blah]
50
+ ....
51
+ rake output removed
52
+ ...
53
+ ==> Rake passed
54
+ ==> Packaged assets with Jammit
55
+ ==> + git add /Users/gabe/thoughtbot/sushi/public/assets && git commit -m 'Assets'
56
+ [master bc8932b] Assets
57
+ 4 files changed, 0 insertions(+), 0 deletions(-)
58
+ ==> - true
59
+ ==> Added and committed all assets
60
+ ==> + git push origin master
61
+ Counting objects: 15, done.
62
+ Delta compression using up to 2 threads.
63
+ Compressing objects: 100% (8/8), done.
64
+ Writing objects: 100% (8/8), 639 bytes, done.
65
+ Total 8 (delta 7), reused 0 (delta 0)
66
+ To git@github.com:sushi/sushi.git
67
+ a465afd..bc8932b master -> master
68
+ ==> - true
69
+ ==> Pushed master -> origin
70
+ ==> + git push -f heroku-staging master
71
+ Counting objects: 15, done.
72
+ Delta compression using up to 2 threads.
73
+ Compressing objects: 100% (8/8), done.
74
+ Writing objects: 100% (8/8), 639 bytes, done.
75
+ Total 8 (delta 7), reused 0 (delta 0)
76
+
77
+ -----> Heroku receiving push
78
+ -----> Rails app detected
79
+ -----> Detected Rails is not set to serve static_assets
80
+ Installing rails3_serve_static_assets... done
81
+ -----> Configure Rails 3 to disable x-sendfile
82
+ Installing rails3_disable_x_sendfile... done
83
+ -----> Configure Rails to log to stdout
84
+ Installing rails_log_stdout... done
85
+ -----> Gemfile detected, running Bundler version 1.0.7
86
+ All dependencies are satisfied
87
+ -----> Compiled slug size is 65.5MB
88
+ -----> Launching... done, v172
89
+ http://staging-sushi.heroku.com deployed to Heroku
90
+
91
+ To git@heroku.com:staging-sushi.git
92
+ a465afd..bc8932b master -> master
93
+ ==> - true
94
+ ==> Force pushed master -> heroku-staging
95
+ ==> + bundle exec heroku rake db:migrate --app staging-sushi
96
+ ... Postgres output removed ...
97
+ ==> - false
98
+ ==> Migrated staging-sushi
99
+ ==> Deployed to: heroku-staging
100
+
101
+ ### Pretend mode
102
+
103
+ $ kumade deploy heroku-staging -p
104
+ ==> In Pretend Mode
105
+ ==> Deploying to: heroku-staging
106
+ ==> heroku-staging is a Heroku remote
107
+ ==> Git repo is clean
108
+ ==> Rake passed
109
+ ==> Packaged assets with Jammit
110
+ ==> Pushed master -> origin
111
+ ==> Force pushed master -> heroku-staging
112
+ ==> Migrated staging-sushi
113
+ ==> Deployed to: heroku-staging
114
+
115
+ ### Pretend Mode with a non-Heroku remote
116
+
117
+ $ kumade deploy origin -p
118
+ ==> In Pretend Mode
119
+ ==> Deploying to: origin
120
+ ==> ! Cannot deploy: "origin" remote does not point to Heroku
26
121
 
27
- ```ruby
28
- Kumade.load_tasks
29
- ## Set the name of the staging remote (autodetected by default)
30
- # Kumade.staging_remote = 'staging'
31
- ## Set the name of the production remote (autodetected by default)
32
- # Kumade.production_remote = 'production'
33
-
34
- # Set the name of the staging app on Heroku (required)
35
- Kumade.staging_app = 'my-staging-app'
36
- # Set the name of the production app on Heroku (required)
37
- Kumade.production_app = 'my-production-app'
38
- ```
39
-
40
- Now running `rake -T` shows the new tasks:
41
-
42
- ```bash
43
- rake deploy # Alias for kumade:deploy
44
- rake deploy:production # Alias for kumade:deploy:production
45
- rake deploy:staging # Alias for kumade:deploy:staging
46
-
47
- rake kumade:deploy # Alias for kumade:deploy:staging
48
- rake kumade:deploy:production # Deploy to Heroku production
49
- rake kumade:deploy:staging # Deploy to Heroku staging
50
- ```
51
-
52
- If you only want the namespaced tasks (the ones with "kumade:" in front), do
53
- this in your Rakefile:
54
-
55
- ```ruby
56
- Kumade.load_namespaced_tasks
57
- ```
58
-
59
- Now `rake -T` will only show this:
60
-
61
- ```bash
62
- rake kumade:deploy # Alias for kumade:deploy:staging
63
- rake kumade:deploy:production # Deploy to Heroku production
64
- rake kumade:deploy:staging # Deploy to Heroku staging
65
- ```
66
122
 
67
123
  ## Compatibility
68
- Tested on MRI 1.8.7 and 1.9.2.
124
+ Tested against:
125
+ * MRI 1.8.7
126
+ * MRI 1.9.2
127
+ * REE 1.8.7
69
128
 
70
129
  ## What's with the name?
71
130
  Kumade ([pronunciation here](http://translate.google.com/#ja|en|熊手)) means
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'kumade'
4
+
5
+ Kumade::ThorTask.start
@@ -0,0 +1,35 @@
1
+ @creates-remote
2
+ Feature: Kumade executable
3
+ As a user
4
+ I want to be able to use the kumade executable
5
+ So I can have a better experience than Rake provides
6
+
7
+ Background:
8
+ Given a directory named "executable"
9
+ And I cd to "executable"
10
+ When I create a Heroku remote for "pretend-staging-app" named "pretend-staging"
11
+ And I create a Heroku remote for "app-two" named "staging"
12
+
13
+ Scenario: Pretend mode with a Heroku remote
14
+ When I run `kumade deploy pretend-staging -p`
15
+ Then the output should contain "In Pretend Mode"
16
+ And the output should contain:
17
+ """
18
+ ==> Git repo is clean
19
+ ==> Rake passed
20
+ ==> Packaged assets with Jammit
21
+ ==> Pushed master -> origin
22
+ ==> Force pushed master -> pretend-staging
23
+ ==> Migrated pretend-staging-app
24
+ ==> Deployed to: pretend-staging
25
+ """
26
+ But the output should not contain "==> Packaged assets with More"
27
+
28
+ Scenario: Default environment is staging
29
+ When I run `kumade -p`
30
+ Then the output should contain "==> Deployed to: staging"
31
+
32
+ Scenario: Can deploy to arbitrary environment
33
+ When I run `kumade deploy bamboo`
34
+ Then the output should contain "==> Deploying to: bamboo"
35
+ Then the output should match /Cannot deploy: /
@@ -0,0 +1,3 @@
1
+ When /^I add "([^"]*)" from this project as a dependency$/ do |gem_name|
2
+ append_to_file('Gemfile', %{\ngem "#{gem_name}", :path => "#{PROJECT_ROOT}"})
3
+ end
@@ -0,0 +1,9 @@
1
+ When /^I create a Heroku remote for "([^"]*)" named "([^"]*)"$/ do |app_name, remote_name|
2
+ `git remote add #{remote_name} git@heroku.com:#{app_name}.git`
3
+
4
+ end
5
+
6
+ After("@creates-remote") do
7
+ heroku_remotes = `git remote -v show | grep heroku | grep fetch | cut -f1`.strip.split
8
+ heroku_remotes.each { |remote| `git remote rm #{remote} 2> /dev/null` }
9
+ end
@@ -1,5 +1,2 @@
1
1
  require 'aruba/cucumber'
2
2
  require 'kumade'
3
- require 'cucumber/rspec/doubles'
4
-
5
- PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.require_paths = ["lib"]
19
19
 
20
20
  s.add_dependency('heroku')
21
+ s.add_dependency('thor', '~> 0.14')
21
22
 
22
23
  s.add_development_dependency('rake', '~> 0.8.7')
23
24
  s.add_development_dependency('rspec', '~> 2.6.0')
@@ -1,45 +1,14 @@
1
1
  require 'kumade/deployer'
2
-
3
- class Kumade
4
- def self.load_tasks
5
- deployer.load_tasks
6
- end
7
-
8
- def self.load_namespaced_tasks
9
- deployer.load_namespaced_tasks
10
- end
11
-
12
- def self.deployer
13
- @deployer ||= Deployer.new
14
- end
15
-
16
- class << self
17
- attr_writer :staging_remote, :production_remote
18
- attr_accessor :staging_app, :production_app
19
-
20
- def reset!
21
- @staging_remote = nil
22
- @production_remote = nil
23
-
24
- @staging_app = nil
25
- @production_app = nil
26
- end
27
-
28
- def staging_remote
29
- @staging_remote ||= local_remote_for_app(Kumade.staging_app)
30
- end
31
-
32
- def production_remote
33
- @production_remote ||= local_remote_for_app(Kumade.production_app)
34
- end
35
-
36
- def local_remote_for_app(app_name)
37
- heroku_remote_url = heroku_remote_url_for_app(app_name)
38
- `git remote -v | grep push | grep '#{heroku_remote_url}' | cut -f1`.strip
39
- end
40
-
41
- def heroku_remote_url_for_app(app_name)
42
- "git@heroku.com:#{app_name}.git"
2
+ require 'kumade/thor_task'
3
+
4
+ module Kumade
5
+ def self.app_for(environment)
6
+ heroku_git_url = `git remote show -n #{environment} | grep 'Push URL' | cut -d' ' -f6`.strip
7
+ match = heroku_git_url.match(/^git@heroku\.com:(.+)\.git$/)
8
+ if match
9
+ match[1]
10
+ else
11
+ ""
43
12
  end
44
13
  end
45
14
  end
@@ -1,12 +1,13 @@
1
- class Kumade
2
- class Deployer
3
- def load_tasks
4
- load_namespaced_tasks
5
- load 'kumade/tasks/deploy.rake'
6
- end
1
+ require 'thor/shell'
2
+ require 'rake'
3
+
4
+ module Kumade
5
+ class Deployer < Thor::Shell::Color
6
+ attr_reader :pretending
7
7
 
8
- def load_namespaced_tasks
9
- load 'kumade/tasks/namespaced_deploy.rake'
8
+ def initialize(pretending = false)
9
+ super()
10
+ @pretending = !!pretending
10
11
  end
11
12
 
12
13
  def pre_deploy
@@ -16,51 +17,54 @@ class Kumade
16
17
  git_push('origin')
17
18
  end
18
19
 
19
- def deploy_to_staging
20
- ensure_staging_app_is_present
21
- pre_deploy
22
- git_force_push(Kumade.staging_remote)
23
- heroku_migrate(:staging)
24
- end
25
-
26
- def deploy_to_production
27
- ensure_production_app_is_present
20
+ def deploy_to(environment)
21
+ string_environment = environment.to_s
22
+ ensure_heroku_remote_exists_for(string_environment)
28
23
  pre_deploy
29
- git_force_push(Kumade.production_remote)
30
- heroku_migrate(:production)
24
+ git_force_push(string_environment)
25
+ heroku_migrate(string_environment)
31
26
  end
32
27
 
33
28
  def git_push(remote)
34
- run_or_raise("git push #{remote} master",
35
- "Failed to push master -> #{remote}")
36
- announce "Pushed master -> #{remote}"
29
+ unless pretending
30
+ run_or_error("git push #{remote} master",
31
+ "Failed to push master -> #{remote}")
32
+ end
33
+ success("Pushed master -> #{remote}")
37
34
  end
38
35
 
39
36
  def git_force_push(remote)
40
- run_or_raise("git push -f #{remote} master",
41
- "Failed to force push master -> #{remote}")
42
- announce "Force pushed master -> #{remote}"
37
+ unless pretending
38
+ run_or_error("git push -f #{remote} master",
39
+ "Failed to force push master -> #{remote}")
40
+ end
41
+ success("Force pushed master -> #{remote}")
43
42
  end
44
43
 
45
44
  def heroku_migrate(environment)
46
- app = if environment == :staging
47
- Kumade.staging_app
48
- elsif environment == :production
49
- Kumade.production_app
50
- end
45
+ app = Kumade.app_for(environment)
51
46
 
52
- run("bundle exec heroku rake db:migrate --app #{app}")
47
+ unless pretending
48
+ run("bundle exec heroku rake db:migrate --app #{app}")
49
+ end
50
+ success("Migrated #{app}")
53
51
  end
54
52
 
55
53
  def ensure_clean_git
56
- if git_dirty?
57
- raise "Cannot deploy: repo is not clean."
54
+ if git_dirty? && ! pretending
55
+ error("Cannot deploy: repo is not clean.")
56
+ else
57
+ success("Git repo is clean")
58
58
  end
59
59
  end
60
60
 
61
61
  def ensure_rake_passes
62
62
  if default_task_exists?
63
- raise "Cannot deploy: tests did not pass" unless rake_succeeded?
63
+ if pretending || rake_succeeded?
64
+ success("Rake passed")
65
+ else
66
+ error("Cannot deploy: tests did not pass")
67
+ end
64
68
  end
65
69
  end
66
70
 
@@ -70,35 +74,45 @@ class Kumade
70
74
  end
71
75
 
72
76
  def package_with_jammit
73
- Jammit.package!
74
- announce("Successfully packaged with Jammit")
75
- if git_dirty?
76
- git_add_and_commit_all_assets_in(absolute_assets_path)
77
+ begin
78
+ success_message = "Packaged assets with Jammit"
79
+
80
+ if pretending
81
+ success(success_message)
82
+ else
83
+ Jammit.package!
84
+
85
+ if git_dirty?
86
+ success(success_message)
87
+ git_add_and_commit_all_assets_in(jammit_assets_path)
88
+ end
89
+ end
90
+ rescue => jammit_error
91
+ error("Error: #{jammit_error.class}: #{jammit_error.message}")
77
92
  end
78
93
  end
79
94
 
80
95
  def package_with_more
81
- Rake::Task['more:generate'].invoke
82
- if git_dirty?
83
- announce("Successfully packaged with More")
84
-
85
- git_add_and_commit_all_assets_in(more_assets_path)
96
+ begin
97
+ system "bundle exec rake more:generate"
98
+ if git_dirty?
99
+ success("Packaged assets with More")
100
+
101
+ git_add_and_commit_all_assets_in(more_assets_path)
102
+ end
103
+ rescue => more_error
104
+ error("Error: #{more_error.class}: #{more_error.message}")
86
105
  end
87
106
  end
88
107
 
89
108
  def git_add_and_commit_all_assets_in(dir)
90
- announce "Committing assets"
91
- run_or_raise("git add #{dir} && git commit -m 'Assets'",
109
+ run_or_error("git add #{dir} && git commit -m 'Assets'",
92
110
  "Cannot deploy: couldn't commit assets")
93
- end
94
111
 
95
- def git_add_and_commit_all_more_assets
96
- announce "Committing assets"
97
- run_or_raise("git add #{more_assets_path} && git commit -m 'Assets'",
98
- "Cannot deploy: couldn't commit assets")
112
+ success("Added and committed all assets")
99
113
  end
100
114
 
101
- def absolute_assets_path
115
+ def jammit_assets_path
102
116
  File.join(Jammit::PUBLIC_ROOT, Jammit.package_path)
103
117
  end
104
118
 
@@ -127,12 +141,12 @@ class Kumade
127
141
  end
128
142
 
129
143
  def default_task_exists?
130
- Rake::Task.task_defined?('default')
144
+ `rake -s -P | grep 'rake default'`.strip.size > 0
131
145
  end
132
146
 
133
147
  def rake_succeeded?
134
148
  begin
135
- Rake::Task[:default].invoke
149
+ system "bundle exec rake"
136
150
  rescue
137
151
  false
138
152
  end
@@ -149,27 +163,58 @@ class Kumade
149
163
  $?.success?
150
164
  end
151
165
 
152
- def run_or_raise(command, error_message)
153
- raise(error_message) unless run(command)
166
+ def run_or_error(command, error_message)
167
+ if ! pretending
168
+ unless run(command)
169
+ error(error_message)
170
+ end
171
+ end
154
172
  end
155
173
 
156
174
  def announce(message)
157
- puts message
175
+ say "==> #{message}"
176
+ end
177
+
178
+ def error(message)
179
+ say("==> ! #{message}", :red)
180
+ exit 1
181
+ end
182
+
183
+ def success(message)
184
+ say("==> #{message}", :green)
158
185
  end
159
186
 
160
187
  def string_present?(maybe_string)
161
188
  maybe_string.is_a?(String) && maybe_string.size > 0
162
189
  end
163
190
 
164
- def ensure_staging_app_is_present
165
- unless string_present?(Kumade.staging_app)
166
- raise "Cannot deploy: Kumade.staging_app is not present"
191
+ def ensure_heroku_remote_exists_for(environment)
192
+ if remote_exists?(environment)
193
+ if Kumade.app_for(environment)
194
+ app_name = Kumade.app_for(environment)
195
+ if string_present?(app_name)
196
+ success("#{environment} is a Heroku remote")
197
+ else
198
+ error(%{Cannot deploy: "#{environment}" remote does not point to Heroku})
199
+ end
200
+ end
201
+ else
202
+ error(%{Cannot deploy: "#{environment}" remote does not exist})
203
+ end
204
+ end
205
+
206
+ def remote_exists?(remote_name)
207
+ if pretending
208
+ true
209
+ else
210
+ `git remote`.split("\n").include?(remote_name)
167
211
  end
168
212
  end
169
213
 
170
- def ensure_production_app_is_present
171
- unless string_present?(Kumade.production_app)
172
- raise "Cannot deploy: Kumade.production_app is not present"
214
+ def initialize_rake
215
+ if Rake.application.tasks.empty?
216
+ Rake.application.options.rakelib = ['rakelib']
217
+ Rake.application.load_rakefile
173
218
  end
174
219
  end
175
220
  end