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/lib/kumade/git.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
+
require 'cocaine'
|
1
2
|
module Kumade
|
2
3
|
class Git < Base
|
3
|
-
|
4
|
-
def initialize(pretending, environment)
|
4
|
+
def initialize
|
5
5
|
super()
|
6
|
-
@pretending = pretending
|
7
|
-
@environment = environment
|
8
6
|
end
|
9
7
|
|
10
8
|
def heroku_remote?
|
11
|
-
`git config --get remote.#{environment}.url`.strip
|
9
|
+
remote_url = `git config --get remote.#{Kumade.configuration.environment}.url`.strip
|
10
|
+
!! remote_url.strip.match(/^git@heroku\..+:(.+)\.git$/)
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.environments
|
@@ -21,7 +20,7 @@ module Kumade
|
|
21
20
|
command << remote
|
22
21
|
command << branch
|
23
22
|
command = command.join(" ")
|
24
|
-
run_or_error(
|
23
|
+
run_or_error(command, "Failed to push #{branch} -> #{remote}")
|
25
24
|
success("Pushed #{branch} -> #{remote}")
|
26
25
|
end
|
27
26
|
|
@@ -32,12 +31,12 @@ module Kumade
|
|
32
31
|
end
|
33
32
|
|
34
33
|
def delete(branch_to_delete, branch_to_checkout)
|
35
|
-
run_or_error(
|
34
|
+
run_or_error("git checkout #{branch_to_checkout} && git branch -D #{branch_to_delete}",
|
36
35
|
"Failed to clean up #{branch_to_delete} branch")
|
37
36
|
end
|
38
37
|
|
39
38
|
def add_and_commit_all_in(dir, branch, commit_message, success_output, error_output)
|
40
|
-
run_or_error
|
39
|
+
run_or_error "git checkout -b #{branch} && git add -f #{dir} && git commit -m '#{commit_message}'",
|
41
40
|
"Cannot deploy: #{error_output}"
|
42
41
|
success success_output
|
43
42
|
end
|
@@ -47,7 +46,7 @@ module Kumade
|
|
47
46
|
end
|
48
47
|
|
49
48
|
def remote_exists?(remote_name)
|
50
|
-
if
|
49
|
+
if Kumade.configuration.pretending?
|
51
50
|
true
|
52
51
|
else
|
53
52
|
`git remote` =~ /^#{remote_name}$/
|
@@ -55,11 +54,11 @@ module Kumade
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def dirty?
|
58
|
-
!
|
57
|
+
!run("git diff --exit-code")
|
59
58
|
end
|
60
59
|
|
61
60
|
def ensure_clean_git
|
62
|
-
if !
|
61
|
+
if ! Kumade.configuration.pretending? && dirty?
|
63
62
|
error("Cannot deploy: repo is not clean.")
|
64
63
|
else
|
65
64
|
success("Git repo is clean")
|
@@ -67,7 +66,7 @@ module Kumade
|
|
67
66
|
end
|
68
67
|
|
69
68
|
def branch_exist?(branch)
|
70
|
-
|
69
|
+
run("git show-ref #{branch}")
|
71
70
|
end
|
72
71
|
end
|
73
72
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'cocaine'
|
2
|
+
|
3
|
+
module Kumade
|
4
|
+
class Heroku < Base
|
5
|
+
DEPLOY_BRANCH = "deploy"
|
6
|
+
attr_reader :git
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
super()
|
10
|
+
@git = Git.new
|
11
|
+
@branch = @git.current_branch
|
12
|
+
end
|
13
|
+
|
14
|
+
def sync
|
15
|
+
git.create(DEPLOY_BRANCH)
|
16
|
+
git.push("#{DEPLOY_BRANCH}:master", Kumade.configuration.environment, true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def migrate_database
|
20
|
+
heroku("rake db:migrate") unless Kumade.configuration.pretending?
|
21
|
+
success("Migrated #{Kumade.configuration.environment}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete_deploy_branch
|
25
|
+
git.delete(DEPLOY_BRANCH, @branch)
|
26
|
+
end
|
27
|
+
|
28
|
+
def heroku(command)
|
29
|
+
heroku_command = if cedar?
|
30
|
+
"bundle exec heroku run"
|
31
|
+
else
|
32
|
+
"bundle exec heroku"
|
33
|
+
end
|
34
|
+
run_or_error("#{heroku_command} #{command} --remote #{Kumade.configuration.environment}",
|
35
|
+
"Failed to run #{command} on Heroku")
|
36
|
+
end
|
37
|
+
|
38
|
+
def cedar?
|
39
|
+
return @cedar unless @cedar.nil?
|
40
|
+
|
41
|
+
@cedar = Cocaine::CommandLine.new("bundle exec heroku stack --remote #{Kumade.configuration.environment}").run.split("\n").grep(/\*/).any? do |line|
|
42
|
+
line.include?("cedar")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Kumade
|
2
|
+
class Packager < Base
|
3
|
+
attr_reader :git
|
4
|
+
|
5
|
+
def initialize(git)
|
6
|
+
super()
|
7
|
+
@git = git
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
invoke_custom_task if custom_task?
|
12
|
+
package_with_jammit if jammit_installed?
|
13
|
+
package_with_more if more_installed?
|
14
|
+
end
|
15
|
+
|
16
|
+
def invoke_custom_task
|
17
|
+
success "Running kumade:before_asset_compilation task"
|
18
|
+
Rake::Task["kumade:before_asset_compilation"].invoke unless Kumade.configuration.pretending?
|
19
|
+
end
|
20
|
+
|
21
|
+
def custom_task?
|
22
|
+
load("Rakefile") if File.exist?("Rakefile")
|
23
|
+
Rake::Task.task_defined?("kumade:before_asset_compilation")
|
24
|
+
end
|
25
|
+
|
26
|
+
def package_with_jammit
|
27
|
+
begin
|
28
|
+
success_message = "Packaged assets with Jammit"
|
29
|
+
|
30
|
+
if Kumade.configuration.pretending?
|
31
|
+
success(success_message)
|
32
|
+
else
|
33
|
+
Jammit.package!
|
34
|
+
|
35
|
+
success(success_message)
|
36
|
+
git_add_and_commit_all_assets_in(jammit_assets_path)
|
37
|
+
end
|
38
|
+
rescue => jammit_error
|
39
|
+
error("Error: #{jammit_error.class}: #{jammit_error.message}")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def package_with_more
|
44
|
+
success_message = "Packaged assets with More"
|
45
|
+
if Kumade.configuration.pretending?
|
46
|
+
success(success_message)
|
47
|
+
else
|
48
|
+
begin
|
49
|
+
run "bundle exec rake more:generate"
|
50
|
+
if git.dirty?
|
51
|
+
success(success_message)
|
52
|
+
git_add_and_commit_all_assets_in(more_assets_path)
|
53
|
+
end
|
54
|
+
rescue => more_error
|
55
|
+
error("Error: #{more_error.class}: #{more_error.message}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def git_add_and_commit_all_assets_in(dir)
|
61
|
+
git.add_and_commit_all_in(dir, Kumade::Heroku::DEPLOY_BRANCH, 'Compiled assets', "Added and committed all assets", "couldn't commit assets")
|
62
|
+
end
|
63
|
+
|
64
|
+
def jammit_assets_path
|
65
|
+
File.join(Jammit::PUBLIC_ROOT, Jammit.package_path)
|
66
|
+
end
|
67
|
+
|
68
|
+
def more_assets_path
|
69
|
+
File.join('public', ::Less::More.destination_path)
|
70
|
+
end
|
71
|
+
|
72
|
+
def jammit_installed?
|
73
|
+
@jammit_installed ||=
|
74
|
+
(defined?(Jammit) ||
|
75
|
+
begin
|
76
|
+
require 'jammit'
|
77
|
+
true
|
78
|
+
rescue LoadError
|
79
|
+
false
|
80
|
+
end)
|
81
|
+
end
|
82
|
+
|
83
|
+
def more_installed?
|
84
|
+
@more_installed ||=
|
85
|
+
(defined?(Less::More) ||
|
86
|
+
begin
|
87
|
+
require 'less/more'
|
88
|
+
true
|
89
|
+
rescue LoadError
|
90
|
+
false
|
91
|
+
end)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/kumade/version.rb
CHANGED
data/lib/tasks/deploy.rake
CHANGED
data/spec/kumade/base_spec.rb
CHANGED
@@ -1,18 +1,99 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Kumade::Base, "#success" do
|
4
|
-
it
|
5
|
-
subject.should respond_to(:success)
|
6
|
-
end
|
4
|
+
it { should respond_to(:success) }
|
7
5
|
end
|
8
6
|
|
9
7
|
describe Kumade::Base, "#error" do
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
before { STDOUT.stubs(:puts) }
|
9
|
+
|
10
|
+
it { should respond_to(:error) }
|
13
11
|
|
14
12
|
it "prints its message and raises its message" do
|
15
|
-
subject.
|
16
|
-
|
13
|
+
lambda { subject.error("I'm an error!") }.should raise_error(Kumade::DeploymentError)
|
14
|
+
|
15
|
+
STDOUT.should have_received(:puts).with(regexp_matches(/I'm an error!/))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Kumade::Base, "#run_or_error" do
|
20
|
+
let(:command) { "dummy command" }
|
21
|
+
let(:error_message) { "dummy error message" }
|
22
|
+
|
23
|
+
before do
|
24
|
+
STDOUT.stubs(:puts)
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when pretending" do
|
28
|
+
before do
|
29
|
+
Kumade.configuration.pretending = true
|
30
|
+
subject.stubs(:run)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "does not run the command" do
|
34
|
+
subject.run_or_error("dummy command", "dummy error message")
|
35
|
+
|
36
|
+
subject.should_not have_received(:run)
|
37
|
+
STDOUT.should have_received(:puts).with(regexp_matches(/#{command}/))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when not pretending" do
|
42
|
+
context "when it runs successfully" do
|
43
|
+
before do
|
44
|
+
Cocaine::CommandLine.stubs(:new).returns(stub(:run))
|
45
|
+
end
|
46
|
+
|
47
|
+
it "does not print an error" do
|
48
|
+
subject.run_or_error(command, error_message)
|
49
|
+
|
50
|
+
STDOUT.should_not have_received(:puts).with(regexp_matches(/#{error_message}/))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when it does not run successfully " do
|
55
|
+
let(:failing_command_line) { stub("Failing Cocaine::CommandLine") }
|
56
|
+
|
57
|
+
before do
|
58
|
+
subject.stubs(:error)
|
59
|
+
failing_command_line.stubs(:run).raises(Cocaine::ExitStatusError)
|
60
|
+
Cocaine::CommandLine.stubs(:new).returns(failing_command_line)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "prints an error message" do
|
64
|
+
subject.run_or_error(command, error_message)
|
65
|
+
|
66
|
+
subject.should have_received(:error).with(error_message)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe Kumade::Base, "#run" do
|
73
|
+
let(:command_line) { stub("Cocaine::CommandLine") }
|
74
|
+
let(:command) { "command" }
|
75
|
+
|
76
|
+
before do
|
77
|
+
Cocaine::CommandLine.stubs(:new).with(command).returns(command_line)
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when not successful" do
|
81
|
+
before do
|
82
|
+
command_line.stubs(:run)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "returns true" do
|
86
|
+
subject.run(command).should == true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when successful" do
|
91
|
+
before do
|
92
|
+
command_line.stubs(:run).raises(Cocaine::ExitStatusError)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns false" do
|
96
|
+
subject.run(command).should == false
|
97
|
+
end
|
17
98
|
end
|
18
99
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kumade::CLI do
|
4
|
+
let(:out) { StringIO.new }
|
5
|
+
let(:environment) { 'my-environment' }
|
6
|
+
let(:deployer) { stub("Deployer", :new => deployer_instance) }
|
7
|
+
let(:deployer_instance) { stub("DeployerInstance", :deploy => nil) }
|
8
|
+
|
9
|
+
before { Kumade::CLI.deployer = deployer }
|
10
|
+
after { Kumade::CLI.deployer = nil }
|
11
|
+
|
12
|
+
context "when pretending" do
|
13
|
+
%w(-p --pretend).each do |pretend_flag|
|
14
|
+
subject { Kumade::CLI.new([pretend_flag, environment], out) }
|
15
|
+
|
16
|
+
context pretend_flag do
|
17
|
+
it "sets pretending to true" do
|
18
|
+
subject
|
19
|
+
Kumade.configuration.pretending.should == true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "deploys" do
|
23
|
+
subject
|
24
|
+
|
25
|
+
deployer_instance.should have_received(:deploy)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with no command-line arguments" do
|
32
|
+
subject { Kumade::CLI.new([], out) }
|
33
|
+
|
34
|
+
it "sets the environment to staging" do
|
35
|
+
Kumade.configuration.environment.should == 'staging'
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets pretending to false" do
|
39
|
+
Kumade.configuration.pretending.should == false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "running normally" do
|
44
|
+
subject { Kumade::CLI.new([environment], out) }
|
45
|
+
|
46
|
+
it "sets pretending to false" do
|
47
|
+
subject
|
48
|
+
Kumade.configuration.pretending.should == false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "deploys" do
|
52
|
+
subject
|
53
|
+
|
54
|
+
deployer_instance.should have_received(:deploy)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe Kumade::CLI, ".deployer" do
|
60
|
+
after { Kumade::CLI.deployer = nil }
|
61
|
+
|
62
|
+
it "sets the deployer to the Deployer class by default" do
|
63
|
+
Kumade::CLI.deployer.should == Kumade::Deployer
|
64
|
+
end
|
65
|
+
|
66
|
+
it "can override deployer" do
|
67
|
+
Kumade::CLI.deployer = "deployer!"
|
68
|
+
Kumade::CLI.deployer.should == "deployer!"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe Kumade::CLI, ".swapping_stdout_for" do
|
73
|
+
let(:stdout) { $stdout }
|
74
|
+
let(:output) { StringIO.new }
|
75
|
+
|
76
|
+
before do
|
77
|
+
stdout.stubs(:print => nil, :puts => nil)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'does not let anything get printed' do
|
81
|
+
Kumade::CLI.swapping_stdout_for(output) do
|
82
|
+
$stdout.puts "Hello, you can't see me."
|
83
|
+
end
|
84
|
+
|
85
|
+
stdout.should_not have_received(:print)
|
86
|
+
|
87
|
+
output.rewind
|
88
|
+
output.read.should == "Hello, you can't see me.\n"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'dumps the output stash to real stdout when an error happens' do
|
92
|
+
Kumade::CLI.swapping_stdout_for(output) do
|
93
|
+
$stdout.puts "Hello, you can see me!"
|
94
|
+
raise Kumade::DeploymentError.new("error")
|
95
|
+
end
|
96
|
+
|
97
|
+
stdout.should have_received(:print)
|
98
|
+
end
|
99
|
+
|
100
|
+
context "in print output mode" do
|
101
|
+
it 'prints everything' do
|
102
|
+
Kumade::CLI.swapping_stdout_for(output, true) do
|
103
|
+
$stdout.puts "Hello, you can see me!"
|
104
|
+
end
|
105
|
+
|
106
|
+
stdout.should have_received(:puts)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kumade::Configuration, "by default" do
|
4
|
+
its(:environment) { should == 'staging' }
|
5
|
+
it { should_not be_pretending }
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Kumade::Configuration, "#pretending" do
|
9
|
+
it "has read/write access for the pretending attribute" do
|
10
|
+
subject.pretending = true
|
11
|
+
subject.pretending.should == true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Kumade::Configuration, "#pretending?" do
|
16
|
+
it "returns false when not pretending" do
|
17
|
+
subject.pretending = false
|
18
|
+
subject.should_not be_pretending
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns true when pretending" do
|
22
|
+
subject.pretending = true
|
23
|
+
subject.should be_pretending
|
24
|
+
end
|
25
|
+
|
26
|
+
it "defaults to false" do
|
27
|
+
subject.pretending.should == false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Kumade::Configuration, "#environment" do
|
32
|
+
it "has read/write access for the environment attribute" do
|
33
|
+
subject.environment = 'new-environment'
|
34
|
+
subject.environment.should == 'new-environment'
|
35
|
+
end
|
36
|
+
end
|