kumade 0.3.0 → 0.4.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.
- 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 熊手 [](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
|