statistrano 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/changelog.md +161 -0
- data/doc/config/file-permissions.md +33 -0
- data/doc/config/log-files.md +32 -0
- data/doc/config/task-definitions.md +88 -0
- data/doc/getting-started.md +96 -0
- data/doc/strategies/base.md +38 -0
- data/doc/strategies/branches.md +82 -0
- data/doc/strategies/releases.md +110 -0
- data/doc/strategies.md +17 -0
- data/lib/statistrano/config/configurable.rb +53 -0
- data/lib/statistrano/config/rake_task_with_context_creation.rb +43 -0
- data/lib/statistrano/config.rb +52 -0
- data/lib/statistrano/deployment/log_file.rb +44 -0
- data/lib/statistrano/deployment/manifest.rb +88 -0
- data/lib/statistrano/deployment/rake_tasks.rb +74 -0
- data/lib/statistrano/deployment/registerable.rb +11 -0
- data/lib/statistrano/deployment/releaser/revisions.rb +163 -0
- data/lib/statistrano/deployment/releaser/single.rb +48 -0
- data/lib/statistrano/deployment/releaser.rb +2 -0
- data/lib/statistrano/deployment/strategy/base.rb +132 -0
- data/lib/statistrano/deployment/strategy/branches/index/template.html.erb +78 -0
- data/lib/statistrano/deployment/strategy/branches/index.rb +40 -0
- data/lib/statistrano/deployment/strategy/branches/release.rb +73 -0
- data/lib/statistrano/deployment/strategy/branches.rb +198 -0
- data/lib/statistrano/deployment/strategy/check_git.rb +43 -0
- data/lib/statistrano/deployment/strategy/invoke_tasks.rb +58 -0
- data/lib/statistrano/deployment/strategy/releases.rb +76 -0
- data/lib/statistrano/deployment/strategy.rb +37 -0
- data/lib/statistrano/deployment.rb +10 -0
- data/lib/statistrano/log/default_logger.rb +105 -0
- data/lib/statistrano/log.rb +33 -0
- data/lib/statistrano/remote/file.rb +79 -0
- data/lib/statistrano/remote.rb +111 -0
- data/lib/statistrano/shell.rb +17 -0
- data/lib/statistrano/util/file_permissions.rb +34 -0
- data/lib/statistrano/util.rb +27 -0
- data/lib/statistrano/version.rb +3 -0
- data/lib/statistrano.rb +55 -0
- data/readme.md +247 -0
- data/spec/integration_tests/base_integration_spec.rb +103 -0
- data/spec/integration_tests/branches_integration_spec.rb +189 -0
- data/spec/integration_tests/releases/deploy_integration_spec.rb +116 -0
- data/spec/integration_tests/releases/list_releases_integration_spec.rb +38 -0
- data/spec/integration_tests/releases/prune_releases_integration_spec.rb +86 -0
- data/spec/integration_tests/releases/rollback_release_integration_spec.rb +46 -0
- data/spec/lib/statistrano/config/configurable_spec.rb +88 -0
- data/spec/lib/statistrano/config/rake_task_with_context_creation_spec.rb +73 -0
- data/spec/lib/statistrano/config_spec.rb +34 -0
- data/spec/lib/statistrano/deployment/log_file_spec.rb +75 -0
- data/spec/lib/statistrano/deployment/manifest_spec.rb +171 -0
- data/spec/lib/statistrano/deployment/rake_tasks_spec.rb +107 -0
- data/spec/lib/statistrano/deployment/registerable_spec.rb +19 -0
- data/spec/lib/statistrano/deployment/releaser/revisions_spec.rb +486 -0
- data/spec/lib/statistrano/deployment/releaser/single_spec.rb +59 -0
- data/spec/lib/statistrano/deployment/strategy/base_spec.rb +158 -0
- data/spec/lib/statistrano/deployment/strategy/branches_spec.rb +19 -0
- data/spec/lib/statistrano/deployment/strategy/check_git_spec.rb +39 -0
- data/spec/lib/statistrano/deployment/strategy/invoke_tasks_spec.rb +66 -0
- data/spec/lib/statistrano/deployment/strategy/releases_spec.rb +257 -0
- data/spec/lib/statistrano/deployment/strategy_spec.rb +76 -0
- data/spec/lib/statistrano/deployment_spec.rb +4 -0
- data/spec/lib/statistrano/log/default_logger_spec.rb +172 -0
- data/spec/lib/statistrano/log_spec.rb +36 -0
- data/spec/lib/statistrano/remote/file_spec.rb +166 -0
- data/spec/lib/statistrano/remote_spec.rb +226 -0
- data/spec/lib/statistrano/util/file_permissions_spec.rb +25 -0
- data/spec/lib/statistrano/util_spec.rb +23 -0
- data/spec/lib/statistrano_spec.rb +52 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/support/given.rb +39 -0
- metadata +223 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Log::DefaultLogger do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
formatter_double = instance_double "Statistrano::Log::DefaultLogger::Formatter",
|
7
|
+
output: "stubbed"
|
8
|
+
Formatter = Statistrano::Log::DefaultLogger::Formatter unless defined?(Formatter)
|
9
|
+
allow( Formatter ).to receive(:new)
|
10
|
+
.and_return( formatter_double )
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#info [& debug]" do
|
14
|
+
it "outputs to stdout" do
|
15
|
+
expect( $stdout ).to receive(:puts)
|
16
|
+
subject.info 'foo'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "defaults to a blank status" do
|
20
|
+
expect( Formatter ).to receive(:new)
|
21
|
+
.with( '', :bright, 'msg' )
|
22
|
+
|
23
|
+
subject.info 'msg'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "uses a status if given one" do
|
27
|
+
expect( Formatter ).to receive(:new)
|
28
|
+
.with( :status, :bright, 'msg' )
|
29
|
+
|
30
|
+
subject.info :status, 'msg'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "colorizes green if given :success as status" do
|
34
|
+
expect( Formatter ).to receive(:new)
|
35
|
+
.with( :success, :green, 'msg' )
|
36
|
+
|
37
|
+
subject.info :success, 'msg'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "takes multiple lines of messages" do
|
41
|
+
expect( Formatter ).to receive(:new)
|
42
|
+
.with( '', :bright, 'msg', 'msg2' )
|
43
|
+
|
44
|
+
subject.info 'msg', 'msg2'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#warn" do
|
49
|
+
it "outputs to stdout" do
|
50
|
+
expect( $stdout ).to receive(:puts)
|
51
|
+
subject.warn 'foo'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "defaults to 'warning' status" do
|
55
|
+
expect( Formatter ).to receive(:new)
|
56
|
+
.with( 'warning', :yellow, 'msg' )
|
57
|
+
|
58
|
+
subject.warn 'msg'
|
59
|
+
end
|
60
|
+
|
61
|
+
it "allows status to be overriden" do
|
62
|
+
expect( Formatter ).to receive(:new)
|
63
|
+
.with( :omg, :yellow, 'msg' )
|
64
|
+
|
65
|
+
subject.warn :omg, 'msg'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "colorizes yellow" do
|
69
|
+
expect( Formatter ).to receive(:new)
|
70
|
+
.with( 'warning', :yellow, 'msg' )
|
71
|
+
|
72
|
+
subject.warn 'msg'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "takes multiple lines of messages" do
|
76
|
+
expect( Formatter ).to receive(:new)
|
77
|
+
.with( 'warning', :yellow, 'msg', 'msg2' )
|
78
|
+
|
79
|
+
subject.warn 'msg', 'msg2'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#error [& fatal]" do
|
84
|
+
it "outputs to stderr" do
|
85
|
+
expect( $stderr ).to receive(:puts)
|
86
|
+
subject.error 'foo'
|
87
|
+
end
|
88
|
+
|
89
|
+
it "defaults to 'error' status" do
|
90
|
+
expect( Formatter ).to receive(:new)
|
91
|
+
.with( 'error', :red, 'msg' )
|
92
|
+
|
93
|
+
subject.error 'msg'
|
94
|
+
end
|
95
|
+
|
96
|
+
it "colorizes red" do
|
97
|
+
expect( Formatter ).to receive(:new)
|
98
|
+
.with( 'error', :red, 'msg' )
|
99
|
+
|
100
|
+
subject.error 'msg'
|
101
|
+
end
|
102
|
+
|
103
|
+
it "takes multiple lines of messages" do
|
104
|
+
expect( Formatter ).to receive(:new)
|
105
|
+
.with( 'error', :red, 'msg', 'msg2' )
|
106
|
+
|
107
|
+
subject.error 'msg', 'msg2'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
describe Statistrano::Log::DefaultLogger::Formatter do
|
114
|
+
|
115
|
+
describe "#initialize" do
|
116
|
+
it "sets status as a string" do
|
117
|
+
expect( described_class.new( :status, '', '' ).status ).to eq 'status'
|
118
|
+
end
|
119
|
+
|
120
|
+
it "sets the given color" do
|
121
|
+
expect( described_class.new( '', 'color', '' ).color ).to eq 'color'
|
122
|
+
end
|
123
|
+
|
124
|
+
it "sets msgs" do
|
125
|
+
expect( described_class.new( '', '', 'msg', 'msg2' ).msgs ).to match_array ['msg','msg2']
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "#output" do
|
130
|
+
it "pads messages" do
|
131
|
+
subject = described_class.new( '', :green, 'msg' )
|
132
|
+
expect( subject.output ).to match /->\s{15}msg/
|
133
|
+
end
|
134
|
+
|
135
|
+
it "pads multiple lined messages" do
|
136
|
+
subject = described_class.new( '', :green, 'msg', 'msg2' )
|
137
|
+
lines = subject.output.split("\n")
|
138
|
+
|
139
|
+
expect( lines.first ).to match /->\s{15}msg/
|
140
|
+
expect( lines.last ).to match /\s{16}msg2/
|
141
|
+
end
|
142
|
+
|
143
|
+
it "handles 'too long' status by padding message on second line to match first line" do
|
144
|
+
subject = described_class.new( 'onetwothreefourfive', :green, 'msg', 'msg2' )
|
145
|
+
lines = subject.output.split("\n")
|
146
|
+
|
147
|
+
expect( lines.first ).to match /->\sonetwothreefourfive\smsg/
|
148
|
+
expect( lines.last ).to match /\s{23}msg2/
|
149
|
+
end
|
150
|
+
|
151
|
+
it "colorizes status with given color" do
|
152
|
+
Rainbow.enabled = true
|
153
|
+
|
154
|
+
rainbow_double = double
|
155
|
+
subject = described_class.new( 'status', :green, 'msg' )
|
156
|
+
allow( Rainbow::Presenter ).to receive(:new)
|
157
|
+
.and_call_original
|
158
|
+
allow( Rainbow::Presenter ).to receive(:new)
|
159
|
+
.with('status')
|
160
|
+
.and_return(rainbow_double)
|
161
|
+
|
162
|
+
expect( rainbow_double ).to receive(:green)
|
163
|
+
.and_return('green')
|
164
|
+
subject.output
|
165
|
+
|
166
|
+
unless ENV['RAINBOW']
|
167
|
+
Rainbow.enabled = false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Log do
|
4
|
+
|
5
|
+
def clean_logger_cache
|
6
|
+
if described_class.instance_variable_get(:@_logger)
|
7
|
+
described_class.send(:remove_instance_variable, :@_logger)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
before :each do
|
12
|
+
clean_logger_cache
|
13
|
+
end
|
14
|
+
|
15
|
+
after :each do
|
16
|
+
clean_logger_cache
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "::set_logger" do
|
20
|
+
it "sets the logger" do
|
21
|
+
Statistrano::Log.set_logger 'foo'
|
22
|
+
expect( Statistrano::Log.instance_variable_get(:@_logger) ).to eq 'foo'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "::logger_instance" do
|
27
|
+
it "returns the cached logger" do
|
28
|
+
Statistrano::Log.instance_variable_set(:@_logger, 'foo')
|
29
|
+
expect( Statistrano::Log.logger_instance ).to eq 'foo'
|
30
|
+
end
|
31
|
+
it "initializes a new DefaultLogger if no logger is set" do
|
32
|
+
expect( Statistrano::Log::DefaultLogger ).to receive(:new)
|
33
|
+
Statistrano::Log.logger_instance
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Remote::File do
|
4
|
+
|
5
|
+
def stub_remote_file_to_exist
|
6
|
+
expect( @remote ).to receive(:run) # the file doesn't exist
|
7
|
+
.with("[ -f /path ] && echo \"exists\"")
|
8
|
+
.and_return( HereOrThere::Response.new("exists\n",'',true) )
|
9
|
+
end
|
10
|
+
|
11
|
+
def stub_remote_file_to_not_exist
|
12
|
+
expect( @remote ).to receive(:run) # the file doesn't exist
|
13
|
+
.with("[ -f /path ] && echo \"exists\"")
|
14
|
+
.and_return( HereOrThere::Response.new('','',true) )
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#initialize" do
|
18
|
+
it "sets the given path" do
|
19
|
+
subject = described_class.new "/path", :remote
|
20
|
+
expect( subject.path ).to eq "/path"
|
21
|
+
end
|
22
|
+
it "sets the given remote" do
|
23
|
+
subject = described_class.new "/path", :remote
|
24
|
+
expect( subject.remote ).to eq :remote
|
25
|
+
end
|
26
|
+
it "sets the given permissions" do
|
27
|
+
subject = described_class.new "/path", :remote, 660
|
28
|
+
expect( subject.permissions ).to eq 660
|
29
|
+
end
|
30
|
+
it "defaults to 644 permissions if not set" do
|
31
|
+
subject = described_class.new "/path", :remote
|
32
|
+
expect( subject.permissions ).to eq 644
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#content" do
|
37
|
+
it "returns string of file content" do
|
38
|
+
remote_double = instance_double("Statistrano::Remote")
|
39
|
+
subject = described_class.new "/path", remote_double
|
40
|
+
|
41
|
+
expect(remote_double).to receive(:run)
|
42
|
+
.with("cat /path")
|
43
|
+
.and_return(HereOrThere::Response.new("content","",true))
|
44
|
+
expect( subject.content ).to eq "content"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns an empty string if errors on remote" do
|
48
|
+
remote_double = instance_double("Statistrano::Remote")
|
49
|
+
subject = described_class.new "/path", remote_double
|
50
|
+
|
51
|
+
expect(remote_double).to receive(:run)
|
52
|
+
.with("cat /path")
|
53
|
+
.and_return(HereOrThere::Response.new("content","error",false))
|
54
|
+
expect( subject.content ).to eq ""
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#update_content!" do
|
59
|
+
before :each do
|
60
|
+
@config = double("Statistrano::Config", hostname: 'web01')
|
61
|
+
@remote = instance_double("Statistrano::Remote", config: @config )
|
62
|
+
allow( @remote ).to receive(:run)
|
63
|
+
.and_return( HereOrThere::Response.new("",'',true) )
|
64
|
+
@subject = described_class.new '/path', @remote
|
65
|
+
end
|
66
|
+
|
67
|
+
it "tests if file exists" do
|
68
|
+
expect( @remote ).to receive(:run)
|
69
|
+
.with("[ -f /path ] && echo \"exists\"")
|
70
|
+
.and_return( HereOrThere::Response.new("exists\n",'',true) )
|
71
|
+
@subject.update_content! "foooo"
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when remote file doesn't exist" do
|
75
|
+
before :each do
|
76
|
+
stub_remote_file_to_not_exist
|
77
|
+
end
|
78
|
+
|
79
|
+
it "creates the file" do
|
80
|
+
expect( @remote ).to receive(:run)
|
81
|
+
.with("touch /path " +
|
82
|
+
"&& chmod 644 /path")
|
83
|
+
.and_return( HereOrThere::Response.new("",'',true) )
|
84
|
+
|
85
|
+
@subject.update_content! "content"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "sets the content to the given content" do
|
89
|
+
expect( @remote ).to receive(:run)
|
90
|
+
.with( "echo 'content' > /path" )
|
91
|
+
.and_return( HereOrThere::Response.new('','',true) )
|
92
|
+
|
93
|
+
@subject.update_content! "content"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when remote file already existed" do
|
98
|
+
before :each do
|
99
|
+
stub_remote_file_to_exist
|
100
|
+
end
|
101
|
+
it "sets the content to the given content" do
|
102
|
+
expect( @remote ).to receive(:run)
|
103
|
+
.with( "echo 'content' > /path" )
|
104
|
+
.and_return( HereOrThere::Response.new('','',true) )
|
105
|
+
|
106
|
+
@subject.update_content! "content"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
describe "#append_content!" do
|
113
|
+
|
114
|
+
before :each do
|
115
|
+
@config = double("Statistrano::Config", hostname: 'web01')
|
116
|
+
@remote = instance_double("Statistrano::Remote", config: @config )
|
117
|
+
allow( @remote ).to receive(:run)
|
118
|
+
.and_return( HereOrThere::Response.new("",'',true) )
|
119
|
+
@subject = described_class.new '/path', @remote
|
120
|
+
end
|
121
|
+
|
122
|
+
context "when remote file doesn't exist" do
|
123
|
+
|
124
|
+
before :each do
|
125
|
+
stub_remote_file_to_not_exist
|
126
|
+
end
|
127
|
+
|
128
|
+
it "creates the file before trying to append" do
|
129
|
+
expect( @remote ).to receive(:run)
|
130
|
+
.with("touch /path " +
|
131
|
+
"&& chmod 644 /path")
|
132
|
+
|
133
|
+
@subject.append_content! "the content"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when remote file already exists" do
|
138
|
+
|
139
|
+
before :each do
|
140
|
+
stub_remote_file_to_exist
|
141
|
+
end
|
142
|
+
|
143
|
+
it "appends new content to file" do
|
144
|
+
expect( @remote ).to receive(:run)
|
145
|
+
.with("echo 'the content' >> /path")
|
146
|
+
|
147
|
+
@subject.append_content! "the content"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
describe "#destroy!" do
|
154
|
+
it "removes the file" do
|
155
|
+
config = double("Statistrano::Config", hostname: 'web01')
|
156
|
+
remote = instance_double("Statistrano::Remote", config: config )
|
157
|
+
allow( remote ).to receive(:run)
|
158
|
+
.and_return( HereOrThere::Response.new("",'',true) )
|
159
|
+
subject = described_class.new '/path', remote
|
160
|
+
|
161
|
+
expect(remote).to receive(:run).with("rm /path")
|
162
|
+
subject.destroy!
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe Statistrano::Remote do
|
5
|
+
|
6
|
+
let(:default_options) do
|
7
|
+
{
|
8
|
+
hostname: 'web01',
|
9
|
+
verbose: false,
|
10
|
+
user: nil,
|
11
|
+
passowrd: nil,
|
12
|
+
dir_permissions: 755,
|
13
|
+
file_permissions: 644,
|
14
|
+
rsync_flags: '-aqz --delete-after'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:default_config) do
|
19
|
+
config default_options
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_ssh_double
|
23
|
+
ssh_double = instance_double("HereOrThere::Remote::SSH")
|
24
|
+
allow( HereOrThere::Remote ).to receive(:session).and_return(ssh_double)
|
25
|
+
return ssh_double
|
26
|
+
end
|
27
|
+
|
28
|
+
def config options
|
29
|
+
OpenStruct.new( options )
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#initialize" do
|
33
|
+
it "assigns given config to config" do
|
34
|
+
subject = described_class.new default_config
|
35
|
+
expect( subject.config ).to eq default_config
|
36
|
+
end
|
37
|
+
|
38
|
+
it "raises an error if no hostname is given" do
|
39
|
+
expect{
|
40
|
+
described_class.new( Struct.new(:hostname).new )
|
41
|
+
}.to raise_error ArgumentError, 'a hostname is required'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#run" do
|
46
|
+
it "passes command to ssh_session#run" do
|
47
|
+
ssh_double = create_ssh_double
|
48
|
+
subject = described_class.new default_config
|
49
|
+
|
50
|
+
expect( ssh_double ).to receive(:run).with('ls')
|
51
|
+
subject.run 'ls'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "logs the command if verbose is true" do
|
55
|
+
ssh_double = create_ssh_double
|
56
|
+
subject = described_class.new config default_options.merge verbose: true
|
57
|
+
|
58
|
+
|
59
|
+
allow( ssh_double ).to receive(:run).with('ls')
|
60
|
+
expect( Statistrano::Log ).to receive(:info)
|
61
|
+
.with( :web01, "running cmd: ls")
|
62
|
+
subject.run 'ls'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#done" do
|
67
|
+
it "passes close_session command to ssh_session" do
|
68
|
+
ssh_double = create_ssh_double
|
69
|
+
subject = described_class.new default_config
|
70
|
+
|
71
|
+
expect( ssh_double ).to receive(:close_session)
|
72
|
+
subject.done
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#test_connection" do
|
77
|
+
it "runs whoami on remote" do
|
78
|
+
ssh_double = create_ssh_double
|
79
|
+
allow(ssh_double).to receive(:close_session)
|
80
|
+
subject = described_class.new default_config
|
81
|
+
|
82
|
+
expect( ssh_double ).to receive(:run).with('whoami')
|
83
|
+
.and_return( HereOrThere::Response.new("statistrano","",true))
|
84
|
+
subject.test_connection
|
85
|
+
end
|
86
|
+
it "returns true if successful" do
|
87
|
+
ssh_double = create_ssh_double
|
88
|
+
allow(ssh_double).to receive(:close_session)
|
89
|
+
subject = described_class.new default_config
|
90
|
+
|
91
|
+
expect( ssh_double ).to receive(:run).with('whoami')
|
92
|
+
.and_return( HereOrThere::Response.new("statistrano","",true))
|
93
|
+
expect( subject.test_connection ).to be_truthy
|
94
|
+
end
|
95
|
+
it "returns false if fails" do
|
96
|
+
ssh_double = create_ssh_double
|
97
|
+
allow(ssh_double).to receive(:close_session)
|
98
|
+
subject = described_class.new default_config
|
99
|
+
|
100
|
+
expect( ssh_double ).to receive(:run).with('whoami')
|
101
|
+
.and_return( HereOrThere::Response.new("","error",false))
|
102
|
+
expect( subject.test_connection ).to be_falsy
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#create_remote_dir" do
|
107
|
+
it "runs mkdir command on remote" do
|
108
|
+
ssh_double = create_ssh_double
|
109
|
+
subject = described_class.new default_config
|
110
|
+
|
111
|
+
expect( ssh_double ).to receive(:run)
|
112
|
+
.with("mkdir -p -m 755 /var/www/proj")
|
113
|
+
.and_return( HereOrThere::Response.new("","",true) )
|
114
|
+
subject.create_remote_dir "/var/www/proj"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "requires an absolute path" do
|
118
|
+
ssh_double = create_ssh_double
|
119
|
+
subject = described_class.new default_config
|
120
|
+
|
121
|
+
expect {
|
122
|
+
subject.create_remote_dir "var/www/proj"
|
123
|
+
}.to raise_error ArgumentError, "path must be absolute"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "uses the set dir_permissions" do
|
127
|
+
ssh_double = create_ssh_double
|
128
|
+
subject = described_class.new config default_options.merge dir_permissions: 644
|
129
|
+
|
130
|
+
expect( ssh_double ).to receive(:run)
|
131
|
+
.with("mkdir -p -m 644 /var/www/proj")
|
132
|
+
.and_return( HereOrThere::Response.new("","",true) )
|
133
|
+
subject.create_remote_dir "/var/www/proj"
|
134
|
+
end
|
135
|
+
|
136
|
+
context "when remote dir creation fails" do
|
137
|
+
it "logs error & exits" do
|
138
|
+
ssh_double = create_ssh_double
|
139
|
+
subject = described_class.new default_config
|
140
|
+
allow( ssh_double ).to receive(:run)
|
141
|
+
.with("mkdir -p -m 755 /var/www/proj")
|
142
|
+
.and_return( HereOrThere::Response.new("","oh noes",false) )
|
143
|
+
|
144
|
+
expect( Statistrano::Log ).to receive(:error)
|
145
|
+
.with( "Unable to create directory '/var/www/proj' on web01",
|
146
|
+
"oh noes")
|
147
|
+
expect{
|
148
|
+
subject.create_remote_dir "/var/www/proj"
|
149
|
+
}.to raise_error SystemExit
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#rsync_to_remote" do
|
155
|
+
it "runs command to rsync local to remote" do
|
156
|
+
subject = described_class.new default_config
|
157
|
+
|
158
|
+
expect( Statistrano::Shell ).to receive(:run_local)
|
159
|
+
.with("rsync -aqz --delete-after " +
|
160
|
+
"--chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r " +
|
161
|
+
"-e ssh local_path/ " +
|
162
|
+
"web01:remote_path/")
|
163
|
+
.and_return( HereOrThere::Response.new("","",true) )
|
164
|
+
|
165
|
+
subject.rsync_to_remote 'local_path', 'remote_path'
|
166
|
+
end
|
167
|
+
|
168
|
+
it "corrects for adding a trailing slash to local_path or remote_path" do
|
169
|
+
subject = described_class.new default_config
|
170
|
+
|
171
|
+
expect( Statistrano::Shell ).to receive(:run_local)
|
172
|
+
.with("rsync -aqz --delete-after " +
|
173
|
+
"--chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r " +
|
174
|
+
"-e ssh local_path/ " +
|
175
|
+
"web01:remote_path/")
|
176
|
+
.and_return( HereOrThere::Response.new("","",true) )
|
177
|
+
|
178
|
+
subject.rsync_to_remote 'local_path/', 'remote_path/'
|
179
|
+
end
|
180
|
+
|
181
|
+
it "uses the set dir_permissions & file_permissions" do
|
182
|
+
subject = described_class.new config default_options.merge dir_permissions: 644, file_permissions: 755
|
183
|
+
|
184
|
+
expect( Statistrano::Shell ).to receive(:run_local)
|
185
|
+
.with("rsync -aqz --delete-after " +
|
186
|
+
"--chmod=Du=rw,Dg=r,Do=r,Fu=rwx,Fg=rx,Fo=rx " +
|
187
|
+
"-e ssh local_path/ " +
|
188
|
+
"web01:remote_path/")
|
189
|
+
.and_return( HereOrThere::Response.new("","",true) )
|
190
|
+
|
191
|
+
subject.rsync_to_remote 'local_path/', 'remote_path/'
|
192
|
+
end
|
193
|
+
|
194
|
+
it "uses the set rsync_flags" do
|
195
|
+
subject = described_class.new config default_options.merge rsync_flags: "-aqz"
|
196
|
+
|
197
|
+
expect( Statistrano::Shell ).to receive(:run_local)
|
198
|
+
.with("rsync -aqz " +
|
199
|
+
"--chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r " +
|
200
|
+
"-e ssh local_path/ " +
|
201
|
+
"web01:remote_path/")
|
202
|
+
.and_return( HereOrThere::Response.new("","",true) )
|
203
|
+
|
204
|
+
subject.rsync_to_remote 'local_path/', 'remote_path/'
|
205
|
+
end
|
206
|
+
|
207
|
+
it "logs error if rsync command fails" do
|
208
|
+
subject = described_class.new default_config
|
209
|
+
expect( Statistrano::Shell ).to receive(:run_local)
|
210
|
+
.and_return( HereOrThere::Response.new("","",false) )
|
211
|
+
|
212
|
+
expect( Statistrano::Log ).to receive(:error)
|
213
|
+
subject.rsync_to_remote 'local_path', 'remote_path'
|
214
|
+
end
|
215
|
+
|
216
|
+
it "returns the response" do
|
217
|
+
subject = described_class.new default_config
|
218
|
+
response = HereOrThere::Response.new("woo","",true)
|
219
|
+
expect( Statistrano::Shell ).to receive(:run_local)
|
220
|
+
.and_return( response )
|
221
|
+
|
222
|
+
expect( subject.rsync_to_remote('local_path','remote_path') ).to eq response
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Util::FilePermissions do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
it "sets user, group, and others based on given perm integer" do
|
7
|
+
subject = described_class.new 644
|
8
|
+
|
9
|
+
expect( subject.user ).to eq "6"
|
10
|
+
expect( subject.group ).to eq "4"
|
11
|
+
expect( subject.others ).to eq "4"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#to_chmod" do
|
16
|
+
it "returns an object with the correct user, group, and others" do
|
17
|
+
subject = described_class.new( 644 ).to_chmod
|
18
|
+
|
19
|
+
expect( subject.user ).to eq "rw"
|
20
|
+
expect( subject.group ).to eq "r"
|
21
|
+
expect( subject.others ).to eq "r"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Statistrano::Util do
|
4
|
+
|
5
|
+
describe "::symbolize_hash_keys" do
|
6
|
+
it "symbolizes keys of hash" do
|
7
|
+
expect(
|
8
|
+
Statistrano::Util.symbolize_hash_keys( { 'foo' => 'bar' })
|
9
|
+
).to eq foo: 'bar'
|
10
|
+
end
|
11
|
+
it "symbolizes keys of nested hashes" do
|
12
|
+
expect(
|
13
|
+
Statistrano::Util.symbolize_hash_keys( { 'foo' => { 'bar' => 'baz' }})
|
14
|
+
).to eq foo: { bar: 'baz' }
|
15
|
+
end
|
16
|
+
it "symbolizes keys of hashes nested in arrays" do
|
17
|
+
expect(
|
18
|
+
Statistrano::Util.symbolize_hash_keys( { 'foo' => [{'bar'=>'baz'},{'wu'=>'tang'}]})
|
19
|
+
).to eq foo: [{bar:'baz'},{wu:'tang'}]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|