statistrano 1.2.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.
- 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
|