kumade 0.2.2 → 0.3.0

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.
@@ -2,6 +2,7 @@ rvm:
2
2
  - 1.9.2
3
3
  - 1.8.7
4
4
  - ree-1.8.7
5
+ - 1.8.7-p249
5
6
  # branches:
6
7
  # only:
7
8
  # - master
data/README.md CHANGED
@@ -3,6 +3,11 @@ 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.
5
5
 
6
+ ## Development
7
+ Development is happening very fast, and the internals are in constant flux. The
8
+ public API is constant (e.g. `kumade production` will work), but you may have to
9
+ rebase against master a couple times before your pull request can be merged.
10
+
6
11
  ## What does Kumade do?
7
12
  Before deploying, Kumade ensures the git repo is clean and that all tests pass.
8
13
  After that, it packages assets using
@@ -28,6 +33,14 @@ For example, if you have a remote named "bamboo":
28
33
 
29
34
  $ bundle exec kumade bamboo
30
35
 
36
+ or
37
+
38
+ # in your Rakefile:
39
+ require 'kumade'
40
+
41
+ # kumade auto-generates a deploy:ENV task for every Heroku environment
42
+ $ rake deploy:bamboo
43
+
31
44
  which will autodetect the name of the Heroku app that the bamboo remote points
32
45
  to and deploy to it.
33
46
 
@@ -40,93 +53,13 @@ The default is to deploy to staging:
40
53
 
41
54
  $ bundle exec kumade # equivalent to "bundle exec kumade staging"
42
55
 
56
+
43
57
  ## Does it support the Cedar stack?
44
58
 
45
59
  Yes. To indicate that a particular app is using Cedar, run with the -c flag:
46
60
 
47
61
  bundle exec kumade bamboo -c
48
62
 
49
- ## Sample Output
50
-
51
- ### Normal mode
52
-
53
- $ kumade heroku-staging
54
- ==> Deploying to: heroku-staging
55
- ==> heroku-staging is a Heroku remote
56
- ==> Git repo is clean
57
- /Users/gabe/.rvm/rubies/ree-1.8.7-2011.03/bin/ruby -S bundle exec rspec [blah blah]
58
- ....
59
- rake output removed
60
- ...
61
- ==> Rake passed
62
- ==> Packaged assets with Jammit
63
- ==> + git add /Users/gabe/thoughtbot/sushi/public/assets && git commit -m 'Assets'
64
- [master bc8932b] Assets
65
- 4 files changed, 0 insertions(+), 0 deletions(-)
66
- ==> - true
67
- ==> Added and committed all assets
68
- ==> + git push origin master
69
- Counting objects: 15, done.
70
- Delta compression using up to 2 threads.
71
- Compressing objects: 100% (8/8), done.
72
- Writing objects: 100% (8/8), 639 bytes, done.
73
- Total 8 (delta 7), reused 0 (delta 0)
74
- To git@github.com:sushi/sushi.git
75
- a465afd..bc8932b master -> master
76
- ==> - true
77
- ==> Pushed master -> origin
78
- ==> + git push -f heroku-staging master
79
- Counting objects: 15, done.
80
- Delta compression using up to 2 threads.
81
- Compressing objects: 100% (8/8), done.
82
- Writing objects: 100% (8/8), 639 bytes, done.
83
- Total 8 (delta 7), reused 0 (delta 0)
84
-
85
- -----> Heroku receiving push
86
- -----> Rails app detected
87
- -----> Detected Rails is not set to serve static_assets
88
- Installing rails3_serve_static_assets... done
89
- -----> Configure Rails 3 to disable x-sendfile
90
- Installing rails3_disable_x_sendfile... done
91
- -----> Configure Rails to log to stdout
92
- Installing rails_log_stdout... done
93
- -----> Gemfile detected, running Bundler version 1.0.7
94
- All dependencies are satisfied
95
- -----> Compiled slug size is 65.5MB
96
- -----> Launching... done, v172
97
- http://staging-sushi.heroku.com deployed to Heroku
98
-
99
- To git@heroku.com:staging-sushi.git
100
- a465afd..bc8932b master -> master
101
- ==> - true
102
- ==> Force pushed master -> heroku-staging
103
- ==> + bundle exec heroku rake db:migrate --app staging-sushi
104
- ... Postgres output removed ...
105
- ==> - false
106
- ==> Migrated staging-sushi
107
- ==> Deployed to: heroku-staging
108
-
109
- ### Pretend mode
110
-
111
- $ kumade heroku-staging -p
112
- ==> In Pretend Mode
113
- ==> Deploying to: heroku-staging
114
- ==> heroku-staging is a Heroku remote
115
- ==> Git repo is clean
116
- ==> Rake passed
117
- ==> Packaged assets with Jammit
118
- ==> Pushed master -> origin
119
- ==> Force pushed master -> heroku-staging
120
- ==> Migrated staging-sushi
121
- ==> Deployed to: heroku-staging
122
-
123
- ### Pretend Mode with a non-Heroku remote
124
-
125
- $ kumade origin -p
126
- ==> In Pretend Mode
127
- ==> Deploying to: origin
128
- ==> ! Cannot deploy: "origin" remote does not point to Heroku
129
-
130
63
  ## Compatibility
131
64
 
132
65
  Tested against:
@@ -137,7 +70,7 @@ Tested against:
137
70
 
138
71
  ## Misc Features
139
72
 
140
- Want to run a task before bundling your assets on deploy? In your rails app's rake tasks, drop in:
73
+ Want to run a task before bundling your assets on deploy? In your Rails app's rake tasks, drop in:
141
74
 
142
75
  ``` ruby
143
76
  namespace :kumade do
@@ -26,8 +26,8 @@ Feature: Kumade executable
26
26
  ==> Pushed master -> origin
27
27
  run git branch deploy
28
28
  run git push -f pretend-staging deploy:master
29
- ==> Force pushed master -> pretend-staging
30
- ==> Migrated pretend-staging-app
29
+ ==> Pushed deploy:master -> pretend-staging
30
+ ==> Migrated pretend-staging
31
31
  run git checkout master && git branch -D deploy
32
32
  ==> Deployed to: pretend-staging
33
33
  """
@@ -57,8 +57,8 @@ Feature: Kumade executable
57
57
  ==> Pushed new_branch -> origin
58
58
  run git branch deploy
59
59
  run git push -f pretend-staging deploy:master
60
- ==> Force pushed new_branch -> pretend-staging
61
- ==> Migrated pretend-staging-app
60
+ ==> Pushed deploy:master -> pretend-staging
61
+ ==> Migrated pretend-staging
62
62
  run git checkout new_branch && git branch -D deploy
63
63
  ==> Deployed to: pretend-staging
64
64
  """
@@ -7,8 +7,8 @@ Gem::Specification.new do |s|
7
7
  s.version = Kumade::VERSION
8
8
  s.authors = ["Gabe Berke-Williams", "thoughtbot"]
9
9
  s.email = ["gabe@thoughtbot.com", "support@thoughtbot.com"]
10
- s.homepage = ""
11
- s.summary = %q{Simple rake tasks for deploying to Heroku}
10
+ s.homepage = "http://thoughtbot.com/community/"
11
+ s.summary = %q{A well-tested script for easy deploying to Heroku}
12
12
  s.description = s.summary
13
13
 
14
14
  s.files = `git ls-files`.split("\n")
@@ -18,8 +18,9 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.add_dependency('heroku', '~> 2.0')
20
20
  s.add_dependency('thor', '~> 0.14')
21
+ s.add_dependency('rake', '>= 0.8.7')
21
22
 
22
- s.add_development_dependency('rake', '~> 0.8.7')
23
+ s.add_development_dependency('rake', '>= 0.8.7')
23
24
  s.add_development_dependency('rspec', '~> 2.6.0')
24
25
  s.add_development_dependency('cucumber', '~> 1.0.2')
25
26
  s.add_development_dependency('aruba', '~> 0.4.3')
@@ -1,29 +1,13 @@
1
1
  require 'rake'
2
2
  require 'thor'
3
+ require 'stringio'
3
4
 
5
+ require 'kumade/base'
6
+ require 'kumade/git'
4
7
  require 'kumade/deployer'
5
8
  require 'kumade/runner'
6
9
  require 'kumade/railtie'
10
+ require 'kumade/deployment_error'
7
11
 
8
12
  module Kumade
9
- def self.app_for(environment)
10
- heroku_git_url = `git config --get remote.#{environment}.url`.strip
11
- if heroku_git_url =~ /^git@heroku\.com:(.+)\.git$/
12
- $1
13
- else
14
- nil
15
- end
16
- end
17
- def self.environments
18
- url_remotes = `git remote`.strip.split("\n").map{|remote| [remote, `git config --get remote.#{remote}.url`.strip] }.select{|remote| remote.last =~ /^git@heroku\.com:(.+)\.git$/}.map{|remote| remote.first}
19
- end
20
-
21
- def self.on_cedar!(app)
22
- @cedar_apps ||= []
23
- @cedar_apps << app
24
- end
25
-
26
- def self.cedar?(app)
27
- @cedar_apps.include?(app)
28
- end
29
13
  end
@@ -0,0 +1,30 @@
1
+ module Kumade
2
+ class Base < Thor::Shell::Color
3
+ def initialize
4
+ super()
5
+ end
6
+
7
+ def run_or_error(commands, error_message)
8
+ all_commands = [commands].flatten.join(' && ')
9
+ if @pretending
10
+ say_status(:run, all_commands)
11
+ else
12
+ error(error_message) unless run(all_commands)
13
+ end
14
+ end
15
+
16
+ def run(command, config = {})
17
+ say_status :run, command
18
+ config[:capture] ? `#{command}` : system("#{command}")
19
+ end
20
+
21
+ def error(message)
22
+ say("==> ! #{message}", :red)
23
+ raise Kumade::DeploymentError.new(message)
24
+ end
25
+
26
+ def success(message)
27
+ say("==> #{message}", :green)
28
+ end
29
+ end
30
+ end
@@ -1,14 +1,14 @@
1
1
  module Kumade
2
- class Deployer < Thor::Shell::Color
2
+ class Deployer < Base
3
3
  DEPLOY_BRANCH = "deploy"
4
- attr_reader :environment, :pretending
4
+ attr_reader :environment, :pretending, :git
5
5
 
6
- def initialize(environment = 'staging', pretending = false, cedar = false)
6
+ def initialize(environment = 'staging', pretending = false)
7
7
  super()
8
8
  @environment = environment
9
9
  @pretending = pretending
10
- @branch = current_branch
11
- @cedar = cedar
10
+ @git = Git.new(pretending, environment)
11
+ @branch = @git.current_branch
12
12
  end
13
13
 
14
14
  def deploy
@@ -26,50 +26,44 @@ module Kumade
26
26
  end
27
27
 
28
28
  def sync_github
29
- run_or_error("git push origin #{@branch}",
30
- "Failed to push #{@branch} -> origin")
31
- success("Pushed #{@branch} -> origin")
29
+ git.push(@branch)
32
30
  end
33
31
 
34
32
  def sync_heroku
35
- unless branch_exist?(DEPLOY_BRANCH)
36
- run_or_error("git branch deploy", "Failed to create #{DEPLOY_BRANCH}")
37
- end
38
- run_or_error("git push -f #{environment} #{DEPLOY_BRANCH}:master",
39
- "Failed to force push #{DEPLOY_BRANCH} -> #{environment}/master")
40
- success("Force pushed #{@branch} -> #{environment}")
33
+ git.create(DEPLOY_BRANCH)
34
+ git.push("#{DEPLOY_BRANCH}:master", environment, true)
41
35
  end
42
36
 
43
37
  def heroku_migrate
44
- app = Kumade.app_for(environment)
45
-
46
- heroku("rake db:migrate", app) unless pretending
47
- success("Migrated #{app}")
38
+ heroku("rake db:migrate") unless pretending
39
+ success("Migrated #{environment}")
48
40
  end
49
41
 
50
42
  def post_deploy
51
- run_or_error(["git checkout #{@branch}", "git branch -D #{DEPLOY_BRANCH}"],
52
- "Failed to clean up #{DEPLOY_BRANCH} branch")
43
+ git.delete(DEPLOY_BRANCH, @branch)
53
44
  end
54
45
 
55
- def heroku(command, app)
56
- heroku_command = if @cedar
46
+ def heroku(command)
47
+ heroku_command = if cedar?
57
48
  "bundle exec heroku run"
58
49
  else
59
50
  "bundle exec heroku"
60
51
  end
61
- run_or_error("#{heroku_command} #{command} --app #{app}",
52
+ run_or_error("#{heroku_command} #{command} --remote #{environment}",
62
53
  "Failed to run #{command} on Heroku")
63
54
  end
64
55
 
65
- def ensure_clean_git
66
- if ! pretending && git_dirty?
67
- error("Cannot deploy: repo is not clean.")
68
- else
69
- success("Git repo is clean")
56
+ def cedar?
57
+ return @cedar unless @cedar.nil?
58
+ @cedar = heroku("stack").split("\n").grep(/\*/).any? do |line|
59
+ line.include?("cedar")
70
60
  end
71
61
  end
72
62
 
63
+ def ensure_clean_git
64
+ git.ensure_clean_git
65
+ end
66
+
73
67
  def package_assets
74
68
  invoke_custom_task if custom_task?
75
69
  package_with_jammit if jammit_installed?
@@ -100,7 +94,7 @@ module Kumade
100
94
  else
101
95
  begin
102
96
  run "bundle exec rake more:generate"
103
- if git_dirty?
97
+ if git.dirty?
104
98
  success(success_message)
105
99
  git_add_and_commit_all_assets_in(more_assets_path)
106
100
  end
@@ -116,10 +110,7 @@ module Kumade
116
110
  end
117
111
 
118
112
  def git_add_and_commit_all_assets_in(dir)
119
- run_or_error ["git checkout -b #{DEPLOY_BRANCH}", "git add -f #{dir}", "git commit -m 'Compiled assets'"],
120
- "Cannot deploy: couldn't commit assets"
121
-
122
- success "Added and committed all assets"
113
+ git.add_and_commit_all_in(dir, DEPLOY_BRANCH, 'Compiled assets', "Added and committed all assets", "couldn't commit assets")
123
114
  end
124
115
 
125
116
  def jammit_assets_path
@@ -157,44 +148,9 @@ module Kumade
157
148
  Rake::Task.task_defined?("kumade:before_asset_compilation")
158
149
  end
159
150
 
160
- def git_dirty?
161
- `git diff --exit-code`
162
- !$?.success?
163
- end
164
-
165
- def run_or_error(commands, error_message)
166
- all_commands = [commands].flatten.join(' && ')
167
- if pretending
168
- say_status(:run, all_commands)
169
- else
170
- error(error_message) unless run(all_commands)
171
- end
172
- end
173
-
174
- def run(command, config = {})
175
- say_status :run, command
176
- config[:capture] ? `#{command}` : system("#{command}")
177
- end
178
-
179
- def branch_exist?(branch)
180
- branches = `git branch`
181
- regex = Regexp.new('[\\n\\s\\*]+' + Regexp.escape(branch.to_s) + '\\n')
182
- result = ((branches =~ regex) ? true : false)
183
- return result
184
- end
185
-
186
- def error(message)
187
- say("==> ! #{message}", :red)
188
- exit 1
189
- end
190
-
191
- def success(message)
192
- say("==> #{message}", :green)
193
- end
194
-
195
151
  def ensure_heroku_remote_exists
196
- if remote_exists?(environment)
197
- if app_name = Kumade.app_for(environment)
152
+ if git.remote_exists?(environment)
153
+ if git.heroku_remote?
198
154
  success("#{environment} is a Heroku remote")
199
155
  else
200
156
  error(%{Cannot deploy: "#{environment}" remote does not point to Heroku})
@@ -203,17 +159,5 @@ module Kumade
203
159
  error(%{Cannot deploy: "#{environment}" remote does not exist})
204
160
  end
205
161
  end
206
-
207
- def remote_exists?(remote_name)
208
- if pretending
209
- true
210
- else
211
- `git remote` =~ /^#{remote_name}$/
212
- end
213
- end
214
-
215
- def current_branch
216
- `git symbolic-ref HEAD`.sub("refs/heads/", "").strip
217
- end
218
162
  end
219
163
  end
@@ -0,0 +1,4 @@
1
+ module Kumade
2
+ class DeploymentError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,73 @@
1
+ module Kumade
2
+ class Git < Base
3
+ attr_reader :environment
4
+ def initialize(pretending, environment)
5
+ super()
6
+ @pretending = pretending
7
+ @environment = environment
8
+ end
9
+
10
+ def heroku_remote?
11
+ `git config --get remote.#{environment}.url`.strip =~ /^git@heroku\..+:(.+)\.git$/
12
+ end
13
+
14
+ def self.environments
15
+ url_remotes = `git remote`.strip.split("\n").map{|remote| [remote, `git config --get remote.#{remote}.url`.strip] }.select{|remote| remote.last =~ /^git@heroku\.com:(.+)\.git$/}.map{|remote| remote.first}
16
+ end
17
+
18
+ def push(branch, remote = 'origin', force = false)
19
+ command = ["git push"]
20
+ command << "-f" if force
21
+ command << remote
22
+ command << branch
23
+ command = command.join(" ")
24
+ run_or_error([command], "Failed to push #{branch} -> #{remote}")
25
+ success("Pushed #{branch} -> #{remote}")
26
+ end
27
+
28
+ def create(branch)
29
+ unless branch_exist?(branch)
30
+ run_or_error("git branch #{branch}", "Failed to create #{branch}")
31
+ end
32
+ end
33
+
34
+ def delete(branch_to_delete, branch_to_checkout)
35
+ run_or_error(["git checkout #{branch_to_checkout}", "git branch -D #{branch_to_delete}"],
36
+ "Failed to clean up #{branch_to_delete} branch")
37
+ end
38
+
39
+ def add_and_commit_all_in(dir, branch, commit_message, success_output, error_output)
40
+ run_or_error ["git checkout -b #{branch}", "git add -f #{dir}", "git commit -m '#{commit_message}'"],
41
+ "Cannot deploy: #{error_output}"
42
+ success success_output
43
+ end
44
+
45
+ def current_branch
46
+ `git symbolic-ref HEAD`.sub("refs/heads/", "").strip
47
+ end
48
+
49
+ def remote_exists?(remote_name)
50
+ if @pretending
51
+ true
52
+ else
53
+ `git remote` =~ /^#{remote_name}$/
54
+ end
55
+ end
56
+
57
+ def dirty?
58
+ ! system("git diff --exit-code")
59
+ end
60
+
61
+ def ensure_clean_git
62
+ if ! @pretending && dirty?
63
+ error("Cannot deploy: repo is not clean.")
64
+ else
65
+ success("Git repo is clean")
66
+ end
67
+ end
68
+
69
+ def branch_exist?(branch)
70
+ system("git show-ref #{branch}")
71
+ end
72
+ end
73
+ end