kikubari 0.0.3 → 0.0.4
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/.travis.yml +5 -0
- data/Gemfile +1 -12
- data/Gemfile.lock +36 -17
- data/README.md +69 -0
- data/Rakefile +6 -34
- data/VERSION +1 -1
- data/bin/kikubari +1 -10
- data/kikubari.gemspec +25 -43
- data/lib/configuration/deploy_configuration.rb +19 -4
- data/lib/deploy_dir.rb +8 -8
- data/lib/deploy_logger.rb +28 -24
- data/lib/deployer/deployer.rb +41 -44
- data/lib/deployer/deployer_git.rb +1 -2
- data/lib/kikubari.rb +17 -8
- data/{test → spec}/deploy_files/databases.yml +0 -0
- data/{test → spec}/deploy_files/deploy.yml +0 -0
- data/{test → spec}/deploy_files/deploy_git.yml +5 -5
- data/{test → spec}/deploy_files/deploy_git_test_file.yml +5 -5
- data/{test → spec}/deploy_files/deploy_symlink.yml +6 -5
- data/{test → spec}/deploy_files/empty.yml +0 -0
- data/{test → spec}/deploy_files/one_file_test.yml +0 -0
- data/{test → spec}/deploy_files/one_folder.yml +0 -0
- data/spec/lib/deploy_spec.rb +146 -0
- data/spec/lib/deployers/git.rb +32 -0
- data/spec/spec_helper.rb +23 -0
- metadata +88 -126
- data/README.rdoc +0 -25
- data/lib/deployer/deployer_git_symfony.rb +0 -15
- data/test/helper.rb +0 -18
- data/test/lib/deploy_spec.rb +0 -94
- data/test/lib/deployers/git.rb +0 -29
- data/test/lib/deployers/mysql_backup.rb +0 -7
- data/test/lib/deployers/symfony_git.rb +0 -29
- data/test/spec_helper.rb +0 -20
data/lib/deployer/deployer.rb
CHANGED
@@ -5,67 +5,65 @@
|
|
5
5
|
# On deployment config (<em>deploy.yml</em>) can be setted the actions to be done one the code gathering is successfull. Then tipically the system would make come backups task, link some folder and files.
|
6
6
|
#
|
7
7
|
# Author:: Jose A Pio (mailto:josetonyp@gmail.com)
|
8
|
-
# Copyright:: Copyright (c) 2011
|
8
|
+
# Copyright:: Copyright (c) 2011
|
9
9
|
# License:: Distributes under the same terms as Ruby
|
10
10
|
module Kikubari
|
11
|
-
|
12
11
|
class Deploy
|
13
|
-
|
14
12
|
class Deployer
|
15
|
-
|
13
|
+
|
16
14
|
attr_accessor :config
|
17
|
-
|
15
|
+
|
18
16
|
def initialize(config)
|
19
17
|
@config = config
|
20
18
|
@logger = Logger.new
|
21
19
|
end
|
22
|
-
|
20
|
+
|
23
21
|
##
|
24
22
|
# Create te the folder structure as is in the YAML
|
25
23
|
#
|
26
24
|
def create_structure
|
27
25
|
@config.do["folder_structure"].each do |command|
|
28
26
|
unless File.directory? command.first[1]
|
29
|
-
|
27
|
+
@logger.print "Creating Structure folder: #{command.first[1]}"
|
30
28
|
FileUtils.mkdir_p command.first[1]
|
31
29
|
end
|
32
30
|
end
|
33
31
|
self
|
34
32
|
end
|
35
|
-
|
36
|
-
|
33
|
+
|
34
|
+
|
37
35
|
##
|
38
36
|
# Create the environment folder as requested in the configuration
|
39
37
|
#
|
40
38
|
def create_environment_folder
|
41
39
|
environment = @config.environment
|
42
40
|
unless File.directory? @config.environment_folder
|
43
|
-
|
41
|
+
@logger.print "Creating Environment folder: #{ @config.environment_folder}"
|
44
42
|
FileUtils.mkdir_p @config.environment_folder
|
45
43
|
end
|
46
44
|
self
|
47
45
|
end
|
48
|
-
|
46
|
+
|
49
47
|
##
|
50
|
-
# Create the folder where you will deploy the actual version of the code based on the configuration
|
48
|
+
# Create the folder where you will deploy the actual version of the code based on the configuration
|
51
49
|
#
|
52
50
|
def create_version_folder
|
53
51
|
FileUtils.mkdir_p(@config.env_time_folder) unless File.directory? @config.env_time_folder
|
54
52
|
self
|
55
53
|
end
|
56
|
-
|
54
|
+
|
57
55
|
##
|
58
56
|
# Create the current symlink to the deploy version folder
|
59
57
|
#
|
60
58
|
def create_current_symlink_folder
|
61
|
-
destination = @config.current_deploy_folder
|
59
|
+
destination = @config.current_deploy_folder
|
62
60
|
origin = Pathname.new( @config.env_time_folder ).relative_path_from( Pathname.new( @config.current_deploy_folder.gsub(/\/[^\/]*?$/, "") ) ).to_s
|
63
61
|
FileUtils.rm_f(destination) if File.symlink?(destination)
|
64
62
|
FileUtils.ln_s origin, destination
|
65
63
|
self
|
66
64
|
end
|
67
|
-
|
68
|
-
|
65
|
+
|
66
|
+
|
69
67
|
##
|
70
68
|
# Test if selected file already exist
|
71
69
|
#
|
@@ -78,39 +76,39 @@ module Kikubari
|
|
78
76
|
end
|
79
77
|
self
|
80
78
|
end
|
81
|
-
|
79
|
+
|
82
80
|
##
|
83
81
|
# Create the Symlinked folders
|
84
82
|
#
|
85
83
|
def create_sylinked_folders
|
86
84
|
@config.do["folder_symbolic_links"].each do |folder|
|
87
|
-
|
88
|
-
raise "Folder: #{@config.env_time_folder}/#{folder[1]} already exists and the symlink can't be created" if File.directory?("#{@config.env_time_folder}/#{folder[1]}")
|
89
|
-
create_symlink( folder )
|
85
|
+
@logger.print "- linking: #{@config.env_time_folder}/#{folder[1]}"
|
86
|
+
raise "Folder: #{@config.env_time_folder}/#{folder[1]} already exists and the symlink can't be created" if File.directory?("#{@config.env_time_folder}/#{folder[1]}")
|
87
|
+
create_symlink( folder )
|
90
88
|
end
|
91
89
|
self
|
92
90
|
end
|
93
|
-
|
91
|
+
|
94
92
|
##
|
95
93
|
# Execute creation of symlinked folder
|
96
94
|
#
|
97
95
|
def create_symlink( folder )
|
98
96
|
destination = "#{@config.env_time_folder}/#{folder[1]}"
|
99
|
-
raise ArgumentError , "Origin folder #{
|
97
|
+
raise ArgumentError , "Origin folder #{@config.get_structure_folder(folder[0])} is not a valid folder" unless File.directory?("#{@config.get_structure_folder(folder[0])}")
|
100
98
|
origin = Pathname.new( "#{@config.get_structure_folder(folder[0])}" ).relative_path_from( Pathname.new( destination.gsub(/\/[^\/]*?$/, "") ) ).to_s ## Origin as a relative path from destination
|
101
99
|
FileUtils.ln_s origin, destination
|
102
100
|
end
|
103
|
-
|
101
|
+
|
104
102
|
def create_symlinked_files
|
105
|
-
|
103
|
+
@logger.print "Creating Files symbolic links"
|
106
104
|
@config.do["file_symbolic_link"].each do |folder|
|
107
105
|
destination = "#{@config.env_time_folder}/#{folder[1]}"
|
108
106
|
origin = Pathname.new( "#{@config.get_test_file(folder[0])}" ).relative_path_from(Pathname.new( destination.gsub(/\/[^\/]*?$/, "") )).to_s
|
109
107
|
FileUtils.ln_s origin , destination
|
110
108
|
end
|
111
109
|
end
|
112
|
-
|
113
|
-
|
110
|
+
|
111
|
+
|
114
112
|
##
|
115
113
|
# Create deployment structure
|
116
114
|
#
|
@@ -119,19 +117,19 @@ module Kikubari
|
|
119
117
|
create_environment_folder.create_version_folder
|
120
118
|
self
|
121
119
|
end
|
122
|
-
|
120
|
+
|
123
121
|
##
|
124
122
|
# Rotate old version folders
|
125
123
|
#
|
126
124
|
def rotate_folders
|
127
125
|
DeployDir.rotate_folders( @config.environment_folder , @config.config["history_limit"] )
|
128
126
|
end
|
129
|
-
|
130
|
-
|
127
|
+
|
128
|
+
|
131
129
|
def has_after_deploy_run_commands
|
132
130
|
@config.after.has_key?("run") && !@config.after["run"].empty?
|
133
131
|
end
|
134
|
-
|
132
|
+
|
135
133
|
##
|
136
134
|
# Run comand line script after deploy
|
137
135
|
#
|
@@ -144,12 +142,12 @@ module Kikubari
|
|
144
142
|
end
|
145
143
|
out
|
146
144
|
end
|
147
|
-
|
148
|
-
|
145
|
+
|
146
|
+
|
149
147
|
def has_before_deploy_run_commands
|
150
148
|
@config.before.has_key?("run") && !@config.before["run"].empty?
|
151
149
|
end
|
152
|
-
|
150
|
+
|
153
151
|
def before_deploy_run
|
154
152
|
return unless has_before_deploy_run_commands
|
155
153
|
out = Array.new
|
@@ -159,21 +157,21 @@ module Kikubari
|
|
159
157
|
end
|
160
158
|
out
|
161
159
|
end
|
162
|
-
|
160
|
+
|
163
161
|
def execute_shell(command)
|
164
|
-
@logger.run(command, @config.env_time_folder)
|
162
|
+
@logger.run(command, @config.env_time_folder)
|
165
163
|
temp = capture_stderr "cd #{@config.env_time_folder} ; #{command} "
|
166
164
|
@logger.result(temp[:stdout]) if temp[:stdout] != ""
|
167
165
|
@logger.error(temp[:stderr]) if temp[:stderr] != ""
|
168
166
|
temp
|
169
167
|
end
|
170
|
-
|
171
|
-
|
168
|
+
|
169
|
+
|
172
170
|
def capture_stderr ( command )
|
173
171
|
stdin, stdout, stderr = Open3.popen3( command )
|
174
172
|
({ :stdout => stdout.readlines.join(""), :stderr => stderr.readlines.join("") })
|
175
173
|
end
|
176
|
-
|
174
|
+
|
177
175
|
##
|
178
176
|
# Execute the deploy
|
179
177
|
#
|
@@ -185,18 +183,17 @@ module Kikubari
|
|
185
183
|
create_sylinked_folders if @config.do.has_key?("folder_symbolic_links") && !@config.do["folder_symbolic_links"].empty?
|
186
184
|
create_symlinked_files if @config.do.has_key?("file_symbolic_link") && !@config.do["file_symbolic_link"].empty?
|
187
185
|
create_current_symlink_folder
|
188
|
-
rotate_folders
|
186
|
+
rotate_folders
|
189
187
|
after_deploy_run
|
190
188
|
self
|
191
189
|
end
|
192
|
-
|
190
|
+
|
193
191
|
private
|
194
|
-
|
192
|
+
|
195
193
|
def do_deploy
|
196
194
|
raise "This is an abstract method, implement this method in your deployer"
|
197
|
-
|
198
195
|
end
|
199
|
-
|
196
|
+
|
200
197
|
end
|
201
198
|
end
|
202
|
-
end
|
199
|
+
end
|
@@ -15,10 +15,9 @@ module Kikubari
|
|
15
15
|
def do_deploy
|
16
16
|
branch = @config.config["branch"] || "master"
|
17
17
|
%x(git clone #{@config.config["origin"]} -b #{branch} #{@config.env_time_folder} )
|
18
|
+
FileUtils.rm_rf("#{@config.env_time_folder}/.git")
|
18
19
|
end
|
19
20
|
|
20
21
|
end
|
21
|
-
|
22
22
|
end
|
23
|
-
|
24
23
|
end
|
data/lib/kikubari.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
|
-
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
require 'git'
|
4
|
+
require 'open3'
|
5
|
+
|
6
|
+
require "configuration/deploy_configuration"
|
7
|
+
require "deployer/deployer"
|
8
|
+
require "deployer/deployer_git"
|
9
|
+
require "deployer/deployer_git_wordpress"
|
10
|
+
require "deploy_dir"
|
11
|
+
require "deploy_logger"
|
2
12
|
|
13
|
+
module Kikubari
|
3
14
|
class Deploy
|
4
15
|
|
5
16
|
attr_accessor :config
|
@@ -11,26 +22,24 @@ module Kikubari
|
|
11
22
|
end
|
12
23
|
|
13
24
|
def deploy
|
14
|
-
|
15
|
-
deployer.create_deploy_structure.deploy
|
25
|
+
get_deployer( @config ).create_deploy_structure.deploy
|
16
26
|
end
|
17
27
|
|
18
28
|
def rollback
|
19
|
-
|
29
|
+
@logger.print "rollingback"
|
20
30
|
end
|
21
31
|
|
22
32
|
def change( version )
|
23
|
-
|
33
|
+
@logger.print "changing to version #{version}"
|
24
34
|
end
|
25
35
|
|
26
36
|
private
|
27
37
|
|
28
38
|
def get_deployer config
|
29
|
-
deployer_class
|
30
|
-
eval(deployer_class).new config
|
39
|
+
eval(deployer_class).new(config)
|
31
40
|
end
|
32
41
|
|
33
42
|
|
34
43
|
end
|
35
44
|
|
36
|
-
end
|
45
|
+
end
|
File without changes
|
File without changes
|
@@ -1,20 +1,20 @@
|
|
1
1
|
## Configurations Parameters
|
2
2
|
config:
|
3
3
|
system: git
|
4
|
-
origin: "git@github.com:josetonyp/
|
4
|
+
origin: "git@github.com:josetonyp/elements.git"
|
5
5
|
branch: master
|
6
6
|
history_limit: 10
|
7
|
-
|
7
|
+
|
8
8
|
## Task actions for deployers
|
9
|
-
## At versión 1 deployers should know the task order
|
9
|
+
## At versión 1 deployers should know the task order
|
10
10
|
do:
|
11
11
|
|
12
12
|
# Folder structure defining the backup and mantainance folder behind the deployment process
|
13
13
|
folder_structure:
|
14
14
|
cache: 'cache/#{environment}'
|
15
15
|
log: 'log/#{environment}'
|
16
|
-
|
16
|
+
|
17
17
|
# Folder links from project folder and matainance folders
|
18
18
|
folder_symbolic_links:
|
19
19
|
cache: cache
|
20
|
-
log: log
|
20
|
+
log: log
|
@@ -1,19 +1,19 @@
|
|
1
1
|
## Configurations Parameters
|
2
2
|
config:
|
3
3
|
system: git
|
4
|
-
origin: "git@github.com:josetonyp/
|
4
|
+
origin: "git@github.com:josetonyp/elements.git"
|
5
5
|
branch: master
|
6
6
|
history_limit: 10
|
7
|
-
|
7
|
+
|
8
8
|
## Task actions for deployers
|
9
|
-
## At versión 1 deployers should know the task order
|
9
|
+
## At versión 1 deployers should know the task order
|
10
10
|
do:
|
11
11
|
|
12
12
|
# Folder structure defining the backup and mantainance folder behind the deployment process
|
13
13
|
folder_structure:
|
14
14
|
cache: 'cache/#{environment}'
|
15
15
|
log: 'log/#{environment}'
|
16
|
-
|
16
|
+
|
17
17
|
# Folder links from project folder and matainance folders
|
18
18
|
folder_symbolic_links:
|
19
19
|
cache: cache
|
@@ -25,4 +25,4 @@ do:
|
|
25
25
|
|
26
26
|
# Links to be build from tested files. Only tested files can be converted in symlinks to the project
|
27
27
|
file_symbolic_link:
|
28
|
-
test: 'test/test.yml'
|
28
|
+
test: 'test/test.yml'
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# Deploy example sheet for a Symfony 1.4 and MySQL project
|
2
2
|
#
|
3
3
|
# Author:: Jose A Pio (mailto:josetonyp@gmail.com)
|
4
|
-
# Copyright:: Copyright (c) 2011
|
4
|
+
# Copyright:: Copyright (c) 2011
|
5
5
|
# License:: Distributes under the same terms as Ruby
|
6
6
|
#
|
7
7
|
|
8
8
|
## Configurations Parameters
|
9
9
|
config:
|
10
|
-
|
10
|
+
|
11
11
|
## Task actions for deployers
|
12
|
-
## At versión 1 deployers should know the task order
|
12
|
+
## At versión 1 deployers should know the task order
|
13
13
|
do:
|
14
14
|
|
15
15
|
# Folder structure defining the backup and mantainance folder behind the deployment process
|
@@ -21,7 +21,8 @@ do:
|
|
21
21
|
folder_symbolic_links:
|
22
22
|
#name: #destination_name
|
23
23
|
cache: cache
|
24
|
-
|
24
|
+
config: config
|
25
|
+
|
25
26
|
# Files to be tested before deployment. This files must exists or deployment will rise an exception
|
26
27
|
# named_file: origin
|
27
28
|
test_files:
|
@@ -34,4 +35,4 @@ do:
|
|
34
35
|
|
35
36
|
after:
|
36
37
|
run:
|
37
|
-
- 'mkdir new_folder'
|
38
|
+
- 'mkdir new_folder'
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kikubari::Deploy::Deployer do
|
4
|
+
|
5
|
+
let(:config) do
|
6
|
+
Kikubari::Deploy::Configuration.new(
|
7
|
+
"#{RSpec.configuration.deploy_files}/deploy_symlink.yml",
|
8
|
+
deploy_folder: RSpec.configuration.target_folder,
|
9
|
+
debug: false,
|
10
|
+
dry_run: false,
|
11
|
+
environment: 'production',
|
12
|
+
rollback: false)
|
13
|
+
end
|
14
|
+
|
15
|
+
subject(:subject) { described_class.new(config) }
|
16
|
+
|
17
|
+
before :all do
|
18
|
+
clear_target_project
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'Folder Structure' do
|
22
|
+
|
23
|
+
it "creates an environment folder to host the structure" do
|
24
|
+
expect(subject.create_environment_folder).to satisfy do |deployer|
|
25
|
+
File.directory?(deployer.config.environment_folder)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "creates a target version folder with a the current time stamp as name" do
|
30
|
+
expect(subject.create_version_folder).to satisfy do |deployer|
|
31
|
+
File.directory?(deployer.config.env_time_folder)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "createa a symlink 'current' to the actual target version folder" do
|
36
|
+
expect(subject.create_version_folder.create_current_symlink_folder).to satisfy do |deployer|
|
37
|
+
File.symlink?(deployer.config.current_deploy_folder)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Giving a folder structure like:
|
42
|
+
# From file: spec/deploy_files/deploy_symlink.yml
|
43
|
+
#
|
44
|
+
# folder_structure:
|
45
|
+
# cache: 'cache/#{environment}'
|
46
|
+
# config: 'config/#{environment}'
|
47
|
+
#
|
48
|
+
# Example:
|
49
|
+
# project:
|
50
|
+
# cache
|
51
|
+
# [environment]
|
52
|
+
# config
|
53
|
+
# [environment]
|
54
|
+
# [environment]
|
55
|
+
# [version_folder]
|
56
|
+
# cache: Symlink to cache/[environment]
|
57
|
+
# config: Symlink to config/[environment]
|
58
|
+
# current: Symlink to [version_folder]
|
59
|
+
#
|
60
|
+
it "creates the cache and condig folder inside" do
|
61
|
+
subject.tap do |deployer|
|
62
|
+
deployer.create_environment_folder
|
63
|
+
deployer.create_version_folder
|
64
|
+
deployer.create_current_symlink_folder
|
65
|
+
|
66
|
+
expect(deployer.create_structure).to satisfy do
|
67
|
+
File.directory?("#{deployer.config.deploy_folder}/cache/#{deployer.config.environment}") &&
|
68
|
+
File.directory?("#{deployer.config.deploy_folder}/config/#{deployer.config.environment}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "creates a symlink to inside the version folder pointing to the corresponding folder inside the structure" do
|
74
|
+
subject.tap do |deployer|
|
75
|
+
deployer.create_environment_folder
|
76
|
+
deployer.create_version_folder
|
77
|
+
deployer.create_structure
|
78
|
+
|
79
|
+
expect(deployer.create_sylinked_folders).to satisfy do
|
80
|
+
File.symlink?( "#{deployer.config.env_time_folder}/cache") &&
|
81
|
+
File.symlink?( "#{deployer.config.env_time_folder}/config")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should not create the symlinked folder is folder already exist" do
|
87
|
+
subject.create_environment_folder.create_version_folder.create_current_symlink_folder
|
88
|
+
subject.create_structure
|
89
|
+
FileUtils.mkdir_p "#{config.env_time_folder}/cache"
|
90
|
+
expect {
|
91
|
+
subject.create_sylinked_folders
|
92
|
+
}.to raise_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'File linking' do
|
97
|
+
it "verifies a file in the folder and raise an error" do
|
98
|
+
subject.create_environment_folder.create_version_folder.create_current_symlink_folder
|
99
|
+
expect{subject.test_files}.to raise_error
|
100
|
+
end
|
101
|
+
|
102
|
+
it "verifies a file in the folder" do
|
103
|
+
subject.create_environment_folder.create_version_folder.create_current_symlink_folder
|
104
|
+
expect{subject.test_files}.to raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
it "creates a symlink file from tested files" do
|
108
|
+
subject.create_deploy_structure
|
109
|
+
## Faking the config folder that should come with the repository
|
110
|
+
FileUtils.mkdir_p "#{config.env_time_folder}/config"
|
111
|
+
`echo "DB data...." >> #{config.deploy_folder}/config/#{config.environment}/databases.yml`
|
112
|
+
subject.create_symlinked_files.should satisfy do |deployer|
|
113
|
+
File.symlink?( "#{config.env_time_folder}/config/databases.yml")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'Execution' do
|
119
|
+
it "should execute the after run tasks" do
|
120
|
+
subject.create_deploy_structure
|
121
|
+
FileUtils.mkdir_p "#{config.env_time_folder}/config"
|
122
|
+
`echo "DB data..." >> #{config.deploy_folder}/config/#{config.environment}/databases.yml`
|
123
|
+
subject.after_deploy_run.should satisfy do |deployer|
|
124
|
+
File.directory?("#{config.env_time_folder}/new_folder")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should capture STDERR messages in a variable is command is not valid" do
|
129
|
+
subject.create_deploy_structure
|
130
|
+
subject.config.after['run'] = [ 'This is not a command' ]
|
131
|
+
out = subject.after_deploy_run
|
132
|
+
out.count.should == 1
|
133
|
+
out[0][:stdout].should == ""
|
134
|
+
out[0][:stderr].should_not == ""
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not capture STDERR messages in a variable if command is valid" do
|
138
|
+
subject.create_deploy_structure
|
139
|
+
subject.config.after['run'] = [ 'ls -lah' ]
|
140
|
+
out = subject.after_deploy_run
|
141
|
+
out.count.should == 1
|
142
|
+
out[0][:stdout].should_not == ""
|
143
|
+
out[0][:stderr].should == ""
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|