kumade 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +0 -1
- data/README.md +19 -21
- data/bin/kumade +1 -1
- data/kumade.gemspec +2 -0
- data/lib/kumade.rb +16 -10
- data/lib/kumade/base.rb +14 -9
- data/lib/kumade/cli.rb +86 -0
- data/lib/kumade/configuration.rb +14 -0
- data/lib/kumade/deployer.rb +27 -128
- data/lib/kumade/git.rb +11 -12
- data/lib/kumade/heroku.rb +46 -0
- data/lib/kumade/packager.rb +94 -0
- data/lib/kumade/version.rb +1 -1
- data/lib/tasks/deploy.rake +1 -1
- data/spec/kumade/base_spec.rb +89 -8
- data/spec/kumade/cli_spec.rb +109 -0
- data/spec/kumade/configuration_spec.rb +36 -0
- data/spec/kumade/deployer_spec.rb +45 -415
- data/spec/kumade/git_spec.rb +88 -21
- data/spec/kumade/heroku_spec.rb +121 -0
- data/spec/kumade/packager_spec.rb +318 -0
- data/spec/kumade_spec.rb +18 -0
- data/spec/spec_helper.rb +19 -3
- data/spec/support/heroku.rb +33 -0
- metadata +63 -22
- data/lib/kumade/runner.rb +0 -70
- data/spec/kumade/runner_spec.rb +0 -66
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Kumade 熊手 [![Build Status](https://secure.travis-ci.org/thoughtbot/kumade.png)](http://travis-ci.org/thoughtbot/kumade)
|
2
|
-
Kumade is a
|
2
|
+
Kumade is a command-line program 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
|
|
@@ -9,11 +9,11 @@ public API is constant (e.g. `kumade production` will work), but you may have to
|
|
9
9
|
rebase against master a couple times before your pull request can be merged.
|
10
10
|
|
11
11
|
## What does Kumade do?
|
12
|
-
Before deploying, Kumade ensures the git repo is clean
|
12
|
+
Before deploying, Kumade ensures the git repo is clean.
|
13
13
|
After that, it packages assets using
|
14
14
|
[Jammit](http://documentcloud.github.com/jammit/) and/or
|
15
15
|
[More](https://github.com/cloudhead/more), commits them, and pushes to origin.
|
16
|
-
Then it force pushes to the correct remote and runs `rake db:migrate` on the
|
16
|
+
Then it force pushes to the correct Heroku remote and runs `rake db:migrate` on the
|
17
17
|
Heroku app.
|
18
18
|
|
19
19
|
If any step fails, it immediately prints an error and stops the deploy
|
@@ -29,36 +29,34 @@ gem 'kumade'
|
|
29
29
|
## Usage
|
30
30
|
|
31
31
|
kumade will deploy to any Heroku remote in the repo.
|
32
|
-
For example, if you have a remote named "
|
32
|
+
For example, if you have a remote named "staging":
|
33
33
|
|
34
|
-
$ bundle exec kumade
|
34
|
+
$ bundle exec kumade staging
|
35
35
|
|
36
|
-
|
36
|
+
To run in pretend mode, which prints what would be done without actually doing
|
37
|
+
any of it:
|
37
38
|
|
38
|
-
|
39
|
-
require 'kumade'
|
39
|
+
$ bundle exec kumade staging -p
|
40
40
|
|
41
|
-
|
42
|
-
$ rake deploy:bamboo
|
41
|
+
The default is to deploy to staging:
|
43
42
|
|
44
|
-
|
45
|
-
|
43
|
+
# equivalent to "bundle exec kumade staging"
|
44
|
+
$ bundle exec kumade
|
46
45
|
|
47
|
-
|
48
|
-
any of it:
|
46
|
+
## Rake
|
49
47
|
|
50
|
-
|
48
|
+
Kumade auto-generates a deploy:ENV task for every Heroku environment.
|
51
49
|
|
52
|
-
|
50
|
+
# in your Rakefile:
|
51
|
+
require 'kumade'
|
53
52
|
|
54
|
-
$
|
53
|
+
$ rake deploy:staging
|
55
54
|
|
55
|
+
If you use rake tasks, you can't pass in options (like -p/--pretend).
|
56
56
|
|
57
57
|
## Does it support the Cedar stack?
|
58
58
|
|
59
|
-
Yes.
|
60
|
-
|
61
|
-
bundle exec kumade bamboo -c
|
59
|
+
Yes. Kumade will automatically detect if your app is running on Cedar.
|
62
60
|
|
63
61
|
## Compatibility
|
64
62
|
|
@@ -68,7 +66,7 @@ Tested against:
|
|
68
66
|
* MRI 1.9.2
|
69
67
|
* REE 1.8.7
|
70
68
|
|
71
|
-
##
|
69
|
+
## Miscellaneous Features
|
72
70
|
|
73
71
|
Want to run a task before bundling your assets on deploy? In your Rails app's rake tasks, drop in:
|
74
72
|
|
data/bin/kumade
CHANGED
data/kumade.gemspec
CHANGED
@@ -19,10 +19,12 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_dependency('heroku', '~> 2.0')
|
20
20
|
s.add_dependency('thor', '~> 0.14')
|
21
21
|
s.add_dependency('rake', '>= 0.8.7')
|
22
|
+
s.add_dependency('cocaine', '>= 0.2.0')
|
22
23
|
|
23
24
|
s.add_development_dependency('rake', '>= 0.8.7')
|
24
25
|
s.add_development_dependency('rspec', '~> 2.6.0')
|
25
26
|
s.add_development_dependency('cucumber', '~> 1.0.2')
|
26
27
|
s.add_development_dependency('aruba', '~> 0.4.3')
|
27
28
|
s.add_development_dependency('jammit', '~> 0.6.3')
|
29
|
+
s.add_development_dependency('bourne')
|
28
30
|
end
|
data/lib/kumade.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module Kumade
|
2
|
+
autoload :Base, "kumade/base"
|
3
|
+
autoload :Git, "kumade/git"
|
4
|
+
autoload :Deployer, "kumade/deployer"
|
5
|
+
autoload :CLI, "kumade/cli"
|
6
|
+
autoload :Railtie, "kumade/railtie"
|
7
|
+
autoload :DeploymentError, "kumade/deployment_error"
|
8
|
+
autoload :Configuration, "kumade/configuration"
|
9
|
+
autoload :Heroku, "kumade/heroku"
|
10
|
+
autoload :Packager, "kumade/packager"
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
require 'kumade/runner'
|
9
|
-
require 'kumade/railtie'
|
10
|
-
require 'kumade/deployment_error'
|
12
|
+
def self.configuration
|
13
|
+
@@configuration ||= Configuration.new
|
14
|
+
end
|
11
15
|
|
12
|
-
|
16
|
+
def self.configuration=(new_configuration)
|
17
|
+
@@configuration = new_configuration
|
18
|
+
end
|
13
19
|
end
|
data/lib/kumade/base.rb
CHANGED
@@ -1,21 +1,26 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
1
3
|
module Kumade
|
2
4
|
class Base < Thor::Shell::Color
|
3
5
|
def initialize
|
4
6
|
super()
|
5
7
|
end
|
6
8
|
|
7
|
-
def run_or_error(
|
8
|
-
|
9
|
-
if
|
10
|
-
|
11
|
-
else
|
12
|
-
error(error_message) unless run(all_commands)
|
9
|
+
def run_or_error(command, error_message)
|
10
|
+
say_status(:run, command)
|
11
|
+
if ! Kumade.configuration.pretending?
|
12
|
+
error(error_message) unless run(command)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def run(command
|
17
|
-
|
18
|
-
|
16
|
+
def run(command)
|
17
|
+
line = Cocaine::CommandLine.new(command)
|
18
|
+
begin
|
19
|
+
line.run
|
20
|
+
true
|
21
|
+
rescue Cocaine::ExitStatusError => e
|
22
|
+
false
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
26
|
def error(message)
|
data/lib/kumade/cli.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Kumade
|
5
|
+
class CLI
|
6
|
+
class << self
|
7
|
+
attr_writer :deployer
|
8
|
+
|
9
|
+
def deployer
|
10
|
+
@deployer || Kumade::Deployer
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(args = ARGV, out = StringIO.new)
|
15
|
+
@options = {}
|
16
|
+
parse_arguments!(args)
|
17
|
+
|
18
|
+
Kumade.configuration.pretending = !!@options[:pretend]
|
19
|
+
Kumade.configuration.environment = args.shift || 'staging'
|
20
|
+
|
21
|
+
self.class.swapping_stdout_for(out, print_output?) do
|
22
|
+
deploy
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.swapping_stdout_for(io, print_output = false)
|
27
|
+
if print_output
|
28
|
+
yield
|
29
|
+
else
|
30
|
+
begin
|
31
|
+
real_stdout = $stdout
|
32
|
+
$stdout = io
|
33
|
+
yield
|
34
|
+
rescue Kumade::DeploymentError
|
35
|
+
io.rewind
|
36
|
+
real_stdout.print(io.read)
|
37
|
+
ensure
|
38
|
+
$stdout = real_stdout
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def deploy
|
46
|
+
if Kumade.configuration.pretending?
|
47
|
+
puts "==> In Pretend Mode"
|
48
|
+
end
|
49
|
+
puts "==> Deploying to: #{Kumade.configuration.environment}"
|
50
|
+
self.class.deployer.new.deploy
|
51
|
+
puts "==> Deployed to: #{Kumade.configuration.environment}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_arguments!(args)
|
55
|
+
OptionParser.new do |opts|
|
56
|
+
opts.banner = "Usage: kumade <environment> [options]"
|
57
|
+
|
58
|
+
opts.on("-p", "--pretend", "Pretend mode: print what kumade would do") do |p|
|
59
|
+
@options[:pretend] = true
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on_tail("-v", "--verbose", "Print what kumade is doing") do
|
63
|
+
@options[:verbose] = true
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.on_tail('--version', 'Show version') do
|
67
|
+
puts "kumade #{Kumade::VERSION}"
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
72
|
+
puts opts
|
73
|
+
exit
|
74
|
+
end
|
75
|
+
end.parse!(args)
|
76
|
+
end
|
77
|
+
|
78
|
+
def verbose?
|
79
|
+
@options[:verbose]
|
80
|
+
end
|
81
|
+
|
82
|
+
def print_output?
|
83
|
+
Kumade.configuration.pretending? || verbose?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Kumade
|
2
|
+
class Configuration
|
3
|
+
def initialize(environment = 'staging', pretending = false )
|
4
|
+
@environment = environment
|
5
|
+
@pretending = pretending
|
6
|
+
end
|
7
|
+
|
8
|
+
def pretending?
|
9
|
+
@pretending
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :pretending, :environment
|
13
|
+
end
|
14
|
+
end
|
data/lib/kumade/deployer.rb
CHANGED
@@ -1,22 +1,28 @@
|
|
1
|
+
require "rake"
|
2
|
+
require 'cocaine'
|
3
|
+
|
1
4
|
module Kumade
|
2
5
|
class Deployer < Base
|
3
|
-
|
4
|
-
attr_reader :environment, :pretending, :git
|
6
|
+
attr_reader :git, :heroku, :packager
|
5
7
|
|
6
|
-
def initialize
|
8
|
+
def initialize
|
7
9
|
super()
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@git = Git.new
|
11
|
+
@heroku = Heroku.new
|
12
|
+
@branch = @git.current_branch
|
13
|
+
@packager = Packager.new(@git)
|
12
14
|
end
|
13
15
|
|
14
16
|
def deploy
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
begin
|
18
|
+
ensure_heroku_remote_exists
|
19
|
+
pre_deploy
|
20
|
+
heroku.sync
|
21
|
+
heroku.migrate_database
|
22
|
+
rescue
|
23
|
+
ensure
|
24
|
+
post_deploy
|
25
|
+
end
|
20
26
|
end
|
21
27
|
|
22
28
|
def pre_deploy
|
@@ -25,138 +31,31 @@ module Kumade
|
|
25
31
|
sync_github
|
26
32
|
end
|
27
33
|
|
28
|
-
def
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
def sync_heroku
|
33
|
-
git.create(DEPLOY_BRANCH)
|
34
|
-
git.push("#{DEPLOY_BRANCH}:master", environment, true)
|
34
|
+
def package_assets
|
35
|
+
packager.run
|
35
36
|
end
|
36
37
|
|
37
|
-
def
|
38
|
-
|
39
|
-
success("Migrated #{environment}")
|
38
|
+
def sync_github
|
39
|
+
git.push(@branch)
|
40
40
|
end
|
41
41
|
|
42
42
|
def post_deploy
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
def heroku(command)
|
47
|
-
heroku_command = if cedar?
|
48
|
-
"bundle exec heroku run"
|
49
|
-
else
|
50
|
-
"bundle exec heroku"
|
51
|
-
end
|
52
|
-
run_or_error("#{heroku_command} #{command} --remote #{environment}",
|
53
|
-
"Failed to run #{command} on Heroku")
|
54
|
-
end
|
55
|
-
|
56
|
-
def cedar?
|
57
|
-
return @cedar unless @cedar.nil?
|
58
|
-
@cedar = heroku("stack").split("\n").grep(/\*/).any? do |line|
|
59
|
-
line.include?("cedar")
|
60
|
-
end
|
43
|
+
heroku.delete_deploy_branch
|
61
44
|
end
|
62
45
|
|
63
46
|
def ensure_clean_git
|
64
47
|
git.ensure_clean_git
|
65
48
|
end
|
66
49
|
|
67
|
-
def package_assets
|
68
|
-
invoke_custom_task if custom_task?
|
69
|
-
package_with_jammit if jammit_installed?
|
70
|
-
package_with_more if more_installed?
|
71
|
-
end
|
72
|
-
|
73
|
-
def package_with_jammit
|
74
|
-
begin
|
75
|
-
success_message = "Packaged assets with Jammit"
|
76
|
-
|
77
|
-
if pretending
|
78
|
-
success(success_message)
|
79
|
-
else
|
80
|
-
Jammit.package!
|
81
|
-
|
82
|
-
success(success_message)
|
83
|
-
git_add_and_commit_all_assets_in(jammit_assets_path)
|
84
|
-
end
|
85
|
-
rescue => jammit_error
|
86
|
-
error("Error: #{jammit_error.class}: #{jammit_error.message}")
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def package_with_more
|
91
|
-
success_message = "Packaged assets with More"
|
92
|
-
if pretending
|
93
|
-
success(success_message)
|
94
|
-
else
|
95
|
-
begin
|
96
|
-
run "bundle exec rake more:generate"
|
97
|
-
if git.dirty?
|
98
|
-
success(success_message)
|
99
|
-
git_add_and_commit_all_assets_in(more_assets_path)
|
100
|
-
end
|
101
|
-
rescue => more_error
|
102
|
-
error("Error: #{more_error.class}: #{more_error.message}")
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def invoke_custom_task
|
108
|
-
success "Running kumade:before_asset_compilation task"
|
109
|
-
Rake::Task["kumade:before_asset_compilation"].invoke unless pretending
|
110
|
-
end
|
111
|
-
|
112
|
-
def git_add_and_commit_all_assets_in(dir)
|
113
|
-
git.add_and_commit_all_in(dir, DEPLOY_BRANCH, 'Compiled assets', "Added and committed all assets", "couldn't commit assets")
|
114
|
-
end
|
115
|
-
|
116
|
-
def jammit_assets_path
|
117
|
-
File.join(Jammit::PUBLIC_ROOT, Jammit.package_path)
|
118
|
-
end
|
119
|
-
|
120
|
-
def more_assets_path
|
121
|
-
File.join('public', ::Less::More.destination_path)
|
122
|
-
end
|
123
|
-
|
124
|
-
def jammit_installed?
|
125
|
-
@jammit_installed ||=
|
126
|
-
(defined?(Jammit) ||
|
127
|
-
begin
|
128
|
-
require 'jammit'
|
129
|
-
true
|
130
|
-
rescue LoadError
|
131
|
-
false
|
132
|
-
end)
|
133
|
-
end
|
134
|
-
|
135
|
-
def more_installed?
|
136
|
-
@more_installed ||=
|
137
|
-
(defined?(Less::More) ||
|
138
|
-
begin
|
139
|
-
require 'less/more'
|
140
|
-
true
|
141
|
-
rescue LoadError
|
142
|
-
false
|
143
|
-
end)
|
144
|
-
end
|
145
|
-
|
146
|
-
def custom_task?
|
147
|
-
load("Rakefile") if File.exist?("Rakefile")
|
148
|
-
Rake::Task.task_defined?("kumade:before_asset_compilation")
|
149
|
-
end
|
150
|
-
|
151
50
|
def ensure_heroku_remote_exists
|
152
|
-
if git.remote_exists?(environment)
|
51
|
+
if git.remote_exists?(Kumade.configuration.environment)
|
153
52
|
if git.heroku_remote?
|
154
|
-
success("#{environment} is a Heroku remote")
|
53
|
+
success("#{Kumade.configuration.environment} is a Heroku remote")
|
155
54
|
else
|
156
|
-
error(%{Cannot deploy: "#{environment}" remote does not point to Heroku})
|
55
|
+
error(%{Cannot deploy: "#{Kumade.configuration.environment}" remote does not point to Heroku})
|
157
56
|
end
|
158
57
|
else
|
159
|
-
error(%{Cannot deploy: "#{environment}" remote does not exist})
|
58
|
+
error(%{Cannot deploy: "#{Kumade.configuration.environment}" remote does not exist})
|
160
59
|
end
|
161
60
|
end
|
162
61
|
end
|