webbynode 1.0.5.beta5 → 1.0.5.beta6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of webbynode might be problematic. Click here for more details.
- data/Gemfile +1 -1
- data/Gemfile.lock +9 -9
- data/Rakefile +19 -1
- data/lib/webbynode/commands/change_dns.rb +4 -1
- data/lib/webbynode/commands/database.rb +34 -7
- data/lib/webbynode/commands/init.rb +10 -8
- data/lib/webbynode/io.rb +2 -0
- data/lib/webbynode/push_and.rb +4 -0
- data/lib/webbynode/remote_executor.rb +12 -0
- data/lib/webbynode/ssh.rb +3 -2
- data/lib/webbynode/taps.rb +31 -4
- data/lib/webbynode.rb +9 -1
- data/spec/webbynode/commands/change_dns_spec.rb +15 -3
- data/spec/webbynode/commands/console_spec.rb +2 -0
- data/spec/webbynode/commands/database_spec.rb +82 -4
- data/spec/webbynode/commands/init_spec.rb +31 -5
- data/spec/webbynode/commands/logs_spec.rb +3 -1
- data/spec/webbynode/commands/push_spec.rb +15 -1
- data/spec/webbynode/commands/tasks_spec.rb +2 -0
- data/spec/webbynode/commands/webbies_spec.rb +2 -1
- data/spec/webbynode/io_spec.rb +12 -1
- data/spec/webbynode/push_and_spec.rb +8 -0
- data/spec/webbynode/remote_executor_spec.rb +29 -0
- data/spec/webbynode/taps_spec.rb +32 -0
- data/webbynode.gemspec +10 -26
- metadata +82 -155
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -12,12 +12,12 @@ GEM
|
|
12
12
|
diff-lcs (1.1.2)
|
13
13
|
domainatrix (0.0.7)
|
14
14
|
addressable
|
15
|
-
echoe (4.5.
|
15
|
+
echoe (4.5.6)
|
16
16
|
allison
|
17
17
|
gemcutter
|
18
18
|
rubyforge
|
19
19
|
fakeweb (1.3.0)
|
20
|
-
gemcutter (0.
|
20
|
+
gemcutter (0.7.0)
|
21
21
|
growl (1.0.3)
|
22
22
|
guard (0.3.0)
|
23
23
|
open_gem (~> 1.4.2)
|
@@ -27,7 +27,7 @@ GEM
|
|
27
27
|
highline (1.6.1)
|
28
28
|
httparty (0.7.4)
|
29
29
|
crack (= 0.1.8)
|
30
|
-
json_pure (1.5.
|
30
|
+
json_pure (1.5.3)
|
31
31
|
launchy (0.3.7)
|
32
32
|
configuration (>= 0.0.5)
|
33
33
|
rake (>= 0.8.1)
|
@@ -35,12 +35,12 @@ GEM
|
|
35
35
|
net-ssh (2.1.0)
|
36
36
|
open_gem (1.4.2)
|
37
37
|
launchy (~> 0.3.5)
|
38
|
-
rack (1.2
|
38
|
+
rack (1.3.2)
|
39
39
|
rainbow (1.1.1)
|
40
40
|
rake (0.8.7)
|
41
41
|
rb-fsevent (0.4.0)
|
42
42
|
rcov (0.9.9)
|
43
|
-
rest-client (1.6.
|
43
|
+
rest-client (1.6.3)
|
44
44
|
mime-types (>= 1.16)
|
45
45
|
rspec (2.5.0)
|
46
46
|
rspec-core (~> 2.5.0)
|
@@ -55,12 +55,12 @@ GEM
|
|
55
55
|
sequel (3.20.0)
|
56
56
|
sinatra (1.0)
|
57
57
|
rack (>= 1.0)
|
58
|
-
sqlite3 (1.3.
|
58
|
+
sqlite3 (1.3.4)
|
59
59
|
sqlite3-ruby (1.3.3)
|
60
60
|
sqlite3 (>= 1.3.3)
|
61
|
-
taps (0.3.
|
61
|
+
taps (0.3.23)
|
62
62
|
rack (>= 1.0.1)
|
63
|
-
rest-client (
|
63
|
+
rest-client (>= 1.4.0, < 1.7.0)
|
64
64
|
sequel (~> 3.20.0)
|
65
65
|
sinatra (~> 1.0.0)
|
66
66
|
sqlite3-ruby (~> 1.2)
|
@@ -87,4 +87,4 @@ DEPENDENCIES
|
|
87
87
|
rb-fsevent
|
88
88
|
rcov
|
89
89
|
rspec
|
90
|
-
taps
|
90
|
+
taps (= 0.3.23)
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'rake/testtask'
|
|
4
4
|
|
5
5
|
require 'echoe'
|
6
6
|
|
7
|
-
Echoe.new('webbynode', '1.0.5.
|
7
|
+
Echoe.new('webbynode', '1.0.5.beta6') do |p|
|
8
8
|
p.description = "Webbynode Deployment Gem"
|
9
9
|
p.url = "http://webbynode.com"
|
10
10
|
p.author = "Felipe Coury"
|
@@ -46,6 +46,24 @@ wn guides
|
|
46
46
|
"
|
47
47
|
end
|
48
48
|
|
49
|
+
require 'rspec/core/rake_task'
|
50
|
+
|
51
|
+
desc 'Default: run specs.'
|
52
|
+
task :default => :spec
|
53
|
+
|
54
|
+
desc "Run specs"
|
55
|
+
RSpec::Core::RakeTask.new do |t|
|
56
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
57
|
+
# Put spec opts in a file named .rspec in root
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Generate code coverage"
|
61
|
+
RSpec::Core::RakeTask.new(:coverage) do |t|
|
62
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
63
|
+
t.rcov = true
|
64
|
+
t.rcov_opts = ['--exclude', 'spec']
|
65
|
+
end
|
66
|
+
|
49
67
|
require 'rcov/rcovtask'
|
50
68
|
desc 'Measures test coverage using rcov'
|
51
69
|
namespace :rcov do
|
@@ -17,7 +17,7 @@ module Webbynode::Commands
|
|
17
17
|
handle_dns param(:dns_entry)
|
18
18
|
|
19
19
|
app_name = io.app_name
|
20
|
-
|
20
|
+
pushand.create!(app_name, param(:dns_entry))
|
21
21
|
|
22
22
|
git.add ".pushand"
|
23
23
|
git.add ".webbynode/settings" if io.file_exists?(".webbynode/settings")
|
@@ -29,6 +29,9 @@ module Webbynode::Commands
|
|
29
29
|
end
|
30
30
|
|
31
31
|
io.log "Your application will start responding to #{param(:dns_entry)} after next deployment."
|
32
|
+
rescue Webbynode::ApiClient::InactiveZone
|
33
|
+
io.log "Domain #{$!.message.color(:yellow)} already setup on Webbynode DNS, but it's inactive."
|
34
|
+
io.log "Please reactivate it and try again."
|
32
35
|
end
|
33
36
|
end
|
34
37
|
end
|
@@ -3,13 +3,17 @@ module Webbynode::Commands
|
|
3
3
|
summary "Manages your application database"
|
4
4
|
|
5
5
|
add_alias "db"
|
6
|
-
allowed_actions %w(pull push)
|
6
|
+
allowed_actions %w(pull push config)
|
7
7
|
|
8
8
|
option :debug, "Show server communication steps"
|
9
9
|
|
10
10
|
requires_initialization!
|
11
11
|
attr_reader :db
|
12
12
|
|
13
|
+
def default
|
14
|
+
io.log "Missing action: use #{"pull".color(:yellow)}, #{"push".color(:yellow)} or #{"config".color(:yellow)}. For more help use #{"#{File.basename $0} help database".color(:yellow)}."
|
15
|
+
end
|
16
|
+
|
13
17
|
def pull
|
14
18
|
go :pull
|
15
19
|
end
|
@@ -18,6 +22,10 @@ module Webbynode::Commands
|
|
18
22
|
go :push
|
19
23
|
end
|
20
24
|
|
25
|
+
def config
|
26
|
+
ask_db_credentials(true)
|
27
|
+
end
|
28
|
+
|
21
29
|
def go(action)
|
22
30
|
ask_db_credentials
|
23
31
|
|
@@ -31,19 +39,38 @@ module Webbynode::Commands
|
|
31
39
|
io.log ""
|
32
40
|
io.log "Retrieving contents from #{db_name} database in #{ip}..."
|
33
41
|
end
|
34
|
-
|
42
|
+
|
35
43
|
taps = Webbynode::Taps.new(db_name, password, io, remote_executor)
|
36
44
|
taps.debug = option(:debug)
|
37
45
|
begin
|
46
|
+
io.log "Checking for dependencies..." if option(:debug)
|
47
|
+
taps.ensure_gems!
|
48
|
+
|
38
49
|
io.log "Starting taps in server mode..." if option(:debug)
|
39
50
|
taps.start
|
51
|
+
|
40
52
|
io.log "Waiting for taps to start..." if option(:debug)
|
41
53
|
sleep 4
|
54
|
+
|
42
55
|
io.log "Sending action #{action} with db #{db[:name]}..." if option(:debug)
|
43
56
|
taps.send(action, :user => db[:user],
|
44
57
|
:password => db[:password],
|
45
58
|
:database => db[:name],
|
46
59
|
:remote_ip => ip)
|
60
|
+
rescue TapsError
|
61
|
+
if $!.message =~ /LoadError: no such file to load -- (.*)/
|
62
|
+
io.log "#{"ERROR:".color(:red)} Missing database adapter. You need to install #{$1.color(:yellow)} gem to handle your database."
|
63
|
+
elsif $!.message =~ /Mysql::Error: Unknown database '(.*)'/
|
64
|
+
io.log "#{"ERROR:".color(:red)} Unknown database #{$1.color(:yellow)}. Create the local database and try again."
|
65
|
+
elsif $!.message =~ /Sequel::DatabaseConnectionError -\> Mysql::Error: (.*)/
|
66
|
+
io.log "#{"ERROR:".color(:red)} Invalid MySQL credentials for your local database (#{$1})"
|
67
|
+
else
|
68
|
+
if $!.message =~ /(.*) -\> (.*)/
|
69
|
+
io.log "#{"ERROR:".color(:red)} Unexpected error - #{$2}"
|
70
|
+
else
|
71
|
+
io.log "#{"ERROR:".color(:red)} Unexpected error - #{$!.message}"
|
72
|
+
end
|
73
|
+
end
|
47
74
|
ensure
|
48
75
|
io.log "Stopping taps server..."
|
49
76
|
taps.finish
|
@@ -64,16 +91,16 @@ module Webbynode::Commands
|
|
64
91
|
}
|
65
92
|
end
|
66
93
|
|
67
|
-
def ask_db_credentials
|
94
|
+
def ask_db_credentials(force=false)
|
68
95
|
retrieve_db_credentials
|
69
96
|
|
70
|
-
|
71
|
-
db[:name] = query("Database name", io.db_name)
|
72
|
-
db[:user] = query(" User name", io.db_name)
|
97
|
+
if force || db[:name].nil?
|
98
|
+
db[:name] = query("Database name", db[:name] || io.db_name)
|
99
|
+
db[:user] = query(" User name", db[:user] || io.db_name)
|
73
100
|
end
|
74
101
|
|
75
102
|
save_password = false
|
76
|
-
|
103
|
+
if force || db[:password].nil?
|
77
104
|
db[:password] = query(" Password", "")
|
78
105
|
save_password = ask("Save password (y/n)? ").downcase == 'y'
|
79
106
|
end
|
@@ -5,7 +5,9 @@ module Webbynode::Commands
|
|
5
5
|
option :dns, String, "The DNS used for this application"
|
6
6
|
option :adddns, "Creates the DNS entries for the domain"
|
7
7
|
option :port, "Specifies an alternate SSH port to connect to Webby", :validate => :integer
|
8
|
-
option :engine, "Sets the application engine for the app", :validate => {
|
8
|
+
option :engine, "Sets the application engine for the app", :validate => {
|
9
|
+
:in => ['php', 'rack', 'rails', 'rails3', 'html', 'wsgi', 'django', 'nodejs']
|
10
|
+
}
|
9
11
|
option :trial, "Initializes this app for Rapp Trial"
|
10
12
|
|
11
13
|
def execute
|
@@ -69,6 +71,13 @@ module Webbynode::Commands
|
|
69
71
|
io.log "Application already initialized.".color(:red)
|
70
72
|
end
|
71
73
|
|
74
|
+
def create_pushand
|
75
|
+
return if pushand_exists? && !@overwrite
|
76
|
+
|
77
|
+
io.log ""
|
78
|
+
pushand.create!(@app_name, @dns_entry)
|
79
|
+
end
|
80
|
+
|
72
81
|
private
|
73
82
|
|
74
83
|
def check_git_clean
|
@@ -114,13 +123,6 @@ module Webbynode::Commands
|
|
114
123
|
io.file_exists?(".pushand")
|
115
124
|
end
|
116
125
|
|
117
|
-
def create_pushand
|
118
|
-
return if pushand_exists? && !@overwrite
|
119
|
-
|
120
|
-
io.log ""
|
121
|
-
io.create_file(".pushand", "#! /bin/bash\nphd $0 #{@app_name} #{@dns_entry}\n", true)
|
122
|
-
end
|
123
|
-
|
124
126
|
def create_git_commit
|
125
127
|
io.log "Initializing git and applying initial commit..."
|
126
128
|
git.init
|
data/lib/webbynode/io.rb
CHANGED
@@ -70,6 +70,7 @@ module Webbynode
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def mkdir(path)
|
73
|
+
raise "Tried to create real directory: #{path}" if $testing
|
73
74
|
# TODO: raise "Tried to create real folder: #{path}" if $testing
|
74
75
|
FileUtils.mkdir_p(path)
|
75
76
|
end
|
@@ -190,6 +191,7 @@ module Webbynode
|
|
190
191
|
end
|
191
192
|
|
192
193
|
def create_file(file_name, contents, executable=nil)
|
194
|
+
raise "Tried to create real file: #{file_name}" if $testing and !$testing_io
|
193
195
|
File.open(file_name, "w") do |file|
|
194
196
|
file.write(contents)
|
195
197
|
end
|
data/lib/webbynode/push_and.rb
CHANGED
@@ -16,6 +16,18 @@ module Webbynode
|
|
16
16
|
ssh.execute "mkdir -p #{folder}"
|
17
17
|
end
|
18
18
|
|
19
|
+
def version(v)
|
20
|
+
v ? "-v=#{v} " : ""
|
21
|
+
end
|
22
|
+
|
23
|
+
def gem_installed?(gem_name, version=nil)
|
24
|
+
exec("gem list -i #{version(version)}#{gem_name}") == 'true'
|
25
|
+
end
|
26
|
+
|
27
|
+
def install_gem(gem_name, version=nil)
|
28
|
+
exec("sudo gem install #{version(version)}#{gem_name} > /dev/null 2>1; echo $?") == '0'
|
29
|
+
end
|
30
|
+
|
19
31
|
def remote_home
|
20
32
|
exec('pwd').strip
|
21
33
|
end
|
data/lib/webbynode/ssh.rb
CHANGED
@@ -68,14 +68,14 @@ module Webbynode
|
|
68
68
|
end
|
69
69
|
|
70
70
|
ch.env "PATH", "/usr/bin:/usr/local/bin:/opt/ruby-enterprise/bin"
|
71
|
-
ch.exec "cd #{app_name}
|
71
|
+
ch.exec "cd #{app_name} && rails console production" do |ch, success|
|
72
72
|
abort "Could not connect to rails console" unless success
|
73
73
|
|
74
74
|
ch.on_data do |ch, data|
|
75
75
|
next if data.chomp == input.chomp || data.chomp == ''
|
76
76
|
if data =~ /^irb(.*)[\>|\*] /
|
77
77
|
prompt = ''
|
78
|
-
data.each_with_index do |s, i|
|
78
|
+
data.chars.each_with_index do |s, i|
|
79
79
|
if s =~ /^irb(.*)[\>|\*] /
|
80
80
|
prompt = s
|
81
81
|
else
|
@@ -108,6 +108,7 @@ module Webbynode
|
|
108
108
|
puts ""
|
109
109
|
puts "Console done."
|
110
110
|
rescue Exception => e
|
111
|
+
puts "Error: #{$!.message}"
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
data/lib/webbynode/taps.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'taps/operation'
|
2
2
|
require 'taps/cli'
|
3
|
+
require 'cgi'
|
3
4
|
|
4
5
|
module Webbynode
|
5
6
|
class Taps
|
@@ -17,6 +18,22 @@ module Webbynode
|
|
17
18
|
@remote_executor = remote_executor
|
18
19
|
end
|
19
20
|
|
21
|
+
def ensure_gems!
|
22
|
+
check_and_install ['taps', '0.3.23'], 'mysql'
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_and_install(*gems)
|
26
|
+
gems.each do |g|
|
27
|
+
if g.is_a?(Array)
|
28
|
+
gemd = *g
|
29
|
+
else
|
30
|
+
gemd = [g]
|
31
|
+
end
|
32
|
+
|
33
|
+
remote_executor.install_gem *gemd unless remote_executor.gem_installed?(*gemd)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
20
37
|
def start
|
21
38
|
@user = io.random_password
|
22
39
|
@password = io.random_password
|
@@ -61,14 +78,24 @@ module Webbynode
|
|
61
78
|
def execute(action, options)
|
62
79
|
raise "Taps server was not started" unless user
|
63
80
|
|
64
|
-
local_url = "mysql://#{options[:user]}:#{options[:password]}@localhost/#{options[:database]}"
|
65
|
-
remote_url = "http://#{user}:#{password}@#{options[:remote_ip]}:5000"
|
66
|
-
|
67
|
-
io.log "Running taps #{action}"
|
81
|
+
local_url = "mysql://#{options[:user]}:#{CGI.escape(options[:password])}@localhost/#{options[:database]}"
|
82
|
+
remote_url = "http://#{user}:#{CGI.escape(password)}@#{options[:remote_ip]}:5000"
|
68
83
|
|
69
84
|
::Taps::Cli.new([]).clientxfer(action.to_sym,
|
70
85
|
:database_url => local_url,
|
71
86
|
:remote_url => remote_url)
|
72
87
|
end
|
73
88
|
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class TapsError < StandardError; end
|
92
|
+
|
93
|
+
class Taps::Config
|
94
|
+
def self.puts(error)
|
95
|
+
@error = error
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.exit(num)
|
99
|
+
raise TapsError, @error
|
100
|
+
end
|
74
101
|
end
|
data/lib/webbynode.rb
CHANGED
@@ -77,7 +77,7 @@ require File.join(File.dirname(__FILE__), 'webbynode', 'commands', 'database')
|
|
77
77
|
require File.join(File.dirname(__FILE__), 'webbynode', 'application')
|
78
78
|
|
79
79
|
module Webbynode
|
80
|
-
VERSION = '1.0.5.
|
80
|
+
VERSION = '1.0.5.beta6'
|
81
81
|
end
|
82
82
|
|
83
83
|
class Array
|
@@ -93,6 +93,14 @@ class Array
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
unless Object.respond_to?(:blank?)
|
97
|
+
class Object
|
98
|
+
def blank?
|
99
|
+
respond_to?(:empty?) ? empty? : !self
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
96
104
|
class Net::HTTP
|
97
105
|
alias_method :old_initialize, :initialize
|
98
106
|
def initialize(*args)
|
@@ -6,25 +6,37 @@ describe Webbynode::Commands::ChangeDns do
|
|
6
6
|
let(:io) { double("io").as_null_object }
|
7
7
|
let(:api) { double("api").as_null_object }
|
8
8
|
let(:cmd) { Webbynode::Commands::ChangeDns.new("the.newdns.com") }
|
9
|
-
|
9
|
+
let(:pushand) { stub.as_null_object }
|
10
10
|
|
11
11
|
before(:each) do
|
12
12
|
FakeWeb.clean_registry
|
13
13
|
cmd.should_receive(:io).any_number_of_times.and_return(io)
|
14
14
|
cmd.should_receive(:git).any_number_of_times.and_return(git)
|
15
15
|
cmd.should_receive(:api).any_number_of_times.and_return(api)
|
16
|
-
|
16
|
+
cmd.stub(:pushand).and_return(pushand)
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should change pushand" do
|
20
20
|
io.should_receive(:app_name).and_return("myapp")
|
21
|
-
|
21
|
+
pushand.should_receive(:create!).with("myapp", "the.newdns.com")
|
22
22
|
git.should_receive(:parse_remote_ip).and_return("1.2.3.4")
|
23
23
|
api.should_receive(:create_record).with("the.newdns.com", "1.2.3.4")
|
24
24
|
|
25
25
|
cmd.run
|
26
26
|
end
|
27
27
|
|
28
|
+
it "gives an error message when zone exists, but is inactive" do
|
29
|
+
git.should_receive(:parse_remote_ip).and_return("1.2.3.4")
|
30
|
+
api.should_receive(:create_record).with("the.newdns.com", "1.2.3.4").and_raise(Webbynode::ApiClient::InactiveZone.new( "the.newdns.com"))
|
31
|
+
|
32
|
+
io.should_receive(:log).with("Changing DNS to the.newdns.com...", :quiet_start)
|
33
|
+
io.should_receive(:log).with("Creating DNS entry for the.newdns.com...")
|
34
|
+
io.should_receive(:log).with("Domain the.newdns.com already setup on Webbynode DNS, but it's inactive.")
|
35
|
+
io.should_receive(:log).with("Please reactivate it and try again.")
|
36
|
+
|
37
|
+
cmd.run
|
38
|
+
end
|
39
|
+
|
28
40
|
it "should give an error message if there are git changes pending" do
|
29
41
|
git.should_receive(:clean?).and_return(false)
|
30
42
|
|
@@ -6,6 +6,7 @@ describe Webbynode::Commands::Console do
|
|
6
6
|
let(:re) { double("RemoteExecutor").as_null_object }
|
7
7
|
let(:git) { double("Git").as_null_object }
|
8
8
|
let(:server) { double("Server").as_null_object }
|
9
|
+
let(:pushand) { stub.as_null_object }
|
9
10
|
|
10
11
|
subject do
|
11
12
|
Webbynode::Commands::Console.new.tap do |cmd|
|
@@ -13,6 +14,7 @@ describe Webbynode::Commands::Console do
|
|
13
14
|
cmd.stub!(:remote_executor).and_return(re)
|
14
15
|
cmd.stub!(:server).and_return(server)
|
15
16
|
cmd.stub!(:git).and_return(git)
|
17
|
+
cmd.stub(:pushand).and_return(pushand)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
@@ -2,10 +2,11 @@
|
|
2
2
|
require File.join(File.expand_path(File.dirname(__FILE__)), '../..', 'spec_helper')
|
3
3
|
|
4
4
|
describe Webbynode::Commands::Database do
|
5
|
-
let(:io)
|
6
|
-
let(:re)
|
7
|
-
let(:git)
|
8
|
-
let(:pa)
|
5
|
+
let(:io) { double("io").as_null_object }
|
6
|
+
let(:re) { double("re").as_null_object }
|
7
|
+
let(:git) { double("git").as_null_object }
|
8
|
+
let(:pa) { double("pushand").as_null_object }
|
9
|
+
let(:taps) { double("taps").as_null_object }
|
9
10
|
|
10
11
|
def prepare(*params)
|
11
12
|
Webbynode::Commands::Database.new(*params).tap do |a|
|
@@ -16,9 +17,86 @@ describe Webbynode::Commands::Database do
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
describe '#config' do
|
21
|
+
subject { prepare "config" }
|
22
|
+
|
23
|
+
it 'asks for credentials again, even if already provided' do
|
24
|
+
io.should_receive(:load_setting).with("database_name").and_return("dbname")
|
25
|
+
io.should_receive(:load_setting).with("database_user").and_return("username")
|
26
|
+
io.should_receive(:load_setting).with("database_password").and_return("dbpassword")
|
27
|
+
|
28
|
+
io.should_receive(:db_name).any_number_of_times.and_return("myapp")
|
29
|
+
|
30
|
+
subject.should_receive(:ask).with("Database name [dbname]: ").and_return("")
|
31
|
+
subject.should_receive(:ask).with(" User name [username]: ").and_return("")
|
32
|
+
subject.should_receive(:ask).with(" Password []: ").and_return("")
|
33
|
+
subject.should_receive(:ask).with("Save password (y/n)? ").and_return("y")
|
34
|
+
|
35
|
+
subject.execute
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
19
39
|
describe '#pull' do
|
20
40
|
subject { prepare "pull" }
|
21
41
|
|
42
|
+
it "installs taps and mysql when none installed" do
|
43
|
+
Webbynode::Taps.should_receive(:new).and_return(taps)
|
44
|
+
|
45
|
+
subject.stub(:ask_db_credentials)
|
46
|
+
subject.stub(:db).and_return({ :name => 'db_name' })
|
47
|
+
subject.stub(:sleep)
|
48
|
+
taps.stub(:start)
|
49
|
+
taps.should_receive(:ensure_gems!)
|
50
|
+
|
51
|
+
subject.execute
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'db failures' do
|
55
|
+
def prepare_with_error(error)
|
56
|
+
subject.stub(:ask_db_credentials)
|
57
|
+
subject.stub(:db).and_return({ :name => 'db_name' })
|
58
|
+
subject.stub(:sleep)
|
59
|
+
|
60
|
+
Webbynode::Taps.should_receive(:new).and_return(taps)
|
61
|
+
|
62
|
+
pa.should_receive(:remote_db_name).and_return('db_name')
|
63
|
+
re.should_receive(:retrieve_db_password).and_return('password')
|
64
|
+
git.should_receive(:parse_remote_ip).and_return('1.2.3.4')
|
65
|
+
|
66
|
+
taps.should_receive(:pull).and_raise(TapsError.new(error))
|
67
|
+
end
|
68
|
+
|
69
|
+
it "shows an user friendly error message cannot connect to local database" do
|
70
|
+
prepare_with_error "Failed to connect to database:
|
71
|
+
Sequel::DatabaseConnectionError -> Mysql::Error: Access denied for user 'root'@'localhost' (using password: YES)"
|
72
|
+
io.should_receive(:log).with("ERROR: Invalid MySQL credentials for your local database (Access denied for user 'root'@'localhost' (using password: YES))")
|
73
|
+
|
74
|
+
subject.execute
|
75
|
+
end
|
76
|
+
|
77
|
+
it "shows an user friendly error for URI errors" do
|
78
|
+
prepare_with_error "Failed to connect to database:
|
79
|
+
URI::InvalidURIError -> the scheme mysql does not accept registry part: root:P@ssw0rd@localhost (or bad hostname?)."
|
80
|
+
io.should_receive(:log).with("ERROR: Unexpected error - the scheme mysql does not accept registry part: root:P@ssw0rd@localhost (or bad hostname?).")
|
81
|
+
|
82
|
+
subject.execute
|
83
|
+
end
|
84
|
+
|
85
|
+
it "shows an user friendly error message when a MySQL database doesn't exist" do
|
86
|
+
prepare_with_error "Failed to connect to database:\n Sequel::DatabaseConnectionError -> Mysql::Error: Unknown database 'r3app'"
|
87
|
+
io.should_receive(:log).with("ERROR: Unknown database r3app. Create the local database and try again.")
|
88
|
+
|
89
|
+
subject.execute
|
90
|
+
end
|
91
|
+
|
92
|
+
it "shows an user friendly error message when an adapter is not present" do
|
93
|
+
prepare_with_error "Failed to connect to database:\n Sequel::AdapterNotFound -> LoadError: no such file to load -- mysql"
|
94
|
+
io.should_receive(:log).with("ERROR: Missing database adapter. You need to install mysql gem to handle your database.")
|
95
|
+
|
96
|
+
subject.execute
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
22
100
|
it "asks the local database credentials and name" do
|
23
101
|
io.should_receive(:load_setting).with("database_name").and_return(nil)
|
24
102
|
io.should_receive(:load_setting).with("database_password").and_return(nil)
|