engineyard 1.4.0 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/engineyard/cli.rb +4 -3
- data/lib/engineyard/cli/ui.rb +2 -2
- data/lib/engineyard/collection/abstract.rb +17 -3
- data/lib/engineyard/model/app.rb +1 -1
- data/lib/engineyard/model/environment.rb +1 -1
- data/lib/engineyard/version.rb +1 -1
- data/spec/engineyard/collection/apps_spec.rb +1 -1
- data/spec/engineyard/collection/environments_spec.rb +1 -1
- data/spec/engineyard/model/environment_spec.rb +6 -12
- data/spec/engineyard/model/instance_spec.rb +0 -5
- data/spec/engineyard/repo_spec.rb +8 -5
- data/spec/engineyard/resolver_spec.rb +4 -11
- data/spec/ey/deploy_spec.rb +2 -2
- data/spec/ey/list_environments_spec.rb +1 -1
- data/spec/ey/logs_spec.rb +1 -1
- data/spec/ey/rebuild_spec.rb +1 -1
- data/spec/ey/recipes/apply_spec.rb +2 -2
- data/spec/ey/recipes/download_spec.rb +3 -3
- data/spec/ey/recipes/upload_spec.rb +3 -3
- data/spec/ey/rollback_spec.rb +2 -2
- data/spec/ey/ssh_spec.rb +25 -27
- data/spec/ey/web/disable_spec.rb +2 -2
- data/spec/ey/web/enable_spec.rb +2 -2
- data/spec/spec_helper.rb +8 -29
- data/spec/support/fake_awsm.rb +51 -0
- data/spec/support/helpers.rb +170 -183
- data/spec/support/matchers.rb +44 -0
- data/spec/support/shared_behavior.rb +6 -34
- metadata +19 -18
- data/spec/support/git_repo.rb +0 -36
data/spec/ey/web/disable_spec.rb
CHANGED
@@ -16,6 +16,6 @@ describe "ey web disable" do
|
|
16
16
|
@ssh_commands.should have_command_like(/engineyard-serverside.*deploy enable_maintenance_page.*--app #{scenario[:application]}/)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
include_examples "it takes an environment name and an app name and an account name"
|
20
|
+
include_examples "it invokes engineyard-serverside"
|
21
21
|
end
|
data/spec/ey/web/enable_spec.rb
CHANGED
@@ -16,8 +16,8 @@ describe "ey web enable" do
|
|
16
16
|
@ssh_commands.should have_command_like(/engineyard-serverside.*deploy disable_maintenance_page.*--app #{scenario[:application]}/)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
include_examples "it takes an environment name and an app name and an account name"
|
20
|
+
include_examples "it invokes engineyard-serverside"
|
21
21
|
|
22
22
|
it "fails when given a bad option" do
|
23
23
|
ey %w[web enable --lots --of --bogus --options], :expect_failure => true
|
data/spec/spec_helper.rb
CHANGED
@@ -35,18 +35,20 @@ require 'engineyard'
|
|
35
35
|
EY::Error
|
36
36
|
|
37
37
|
# Spec stuff
|
38
|
-
require '
|
38
|
+
require 'rspec'
|
39
39
|
require 'tmpdir'
|
40
40
|
require 'yaml'
|
41
41
|
require 'pp'
|
42
42
|
support = Dir[File.join(EY_ROOT,'/spec/support/*.rb')]
|
43
43
|
support.each{|helper| require helper }
|
44
44
|
|
45
|
-
|
46
|
-
config.include
|
47
|
-
config.include
|
48
|
-
|
49
|
-
config.extend
|
45
|
+
RSpec.configure do |config|
|
46
|
+
config.include SpecHelpers
|
47
|
+
config.include SpecHelpers::IntegrationHelpers
|
48
|
+
|
49
|
+
config.extend SpecHelpers::GitRepoHelpers
|
50
|
+
config.extend SpecHelpers::Given
|
51
|
+
config.extend SpecHelpers::Fixtures
|
50
52
|
|
51
53
|
config.before(:all) do
|
52
54
|
FakeWeb.allow_net_connect = false
|
@@ -62,21 +64,6 @@ Spec::Runner.configure do |config|
|
|
62
64
|
end
|
63
65
|
end
|
64
66
|
|
65
|
-
Spec::Matchers.define :have_command_like do |regex|
|
66
|
-
match do |command_list|
|
67
|
-
@found = command_list.find{|c| c =~ regex }
|
68
|
-
!!@found
|
69
|
-
end
|
70
|
-
|
71
|
-
failure_message_for_should do |command_list|
|
72
|
-
"Didn't find a command matching #{regex} in commands:\n\n" + command_list.join("\n\n")
|
73
|
-
end
|
74
|
-
|
75
|
-
failure_message_for_should_not do |command_list|
|
76
|
-
"Found unwanted command:\n\n#{@found}\n\n(matches regex #{regex})"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
67
|
EY.define_git_repo("default") do |git_dir|
|
81
68
|
system("echo 'source :gemcutter' > Gemfile")
|
82
69
|
system("git add Gemfile")
|
@@ -111,11 +98,3 @@ shared_examples_for "integration" do
|
|
111
98
|
File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
|
112
99
|
end
|
113
100
|
end
|
114
|
-
|
115
|
-
shared_examples_for "it has an api" do
|
116
|
-
before(:all) do
|
117
|
-
@api = EY::API.new('asdf')
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module EY
|
2
|
+
class << self
|
3
|
+
def fake_awsm
|
4
|
+
@fake_awsm ||= load_fake_awsm
|
5
|
+
end
|
6
|
+
alias_method :start_fake_awsm, :fake_awsm
|
7
|
+
|
8
|
+
def define_git_repo(name, &setup)
|
9
|
+
git_repo_setup[name] ||= setup
|
10
|
+
end
|
11
|
+
|
12
|
+
def refresh_git_repo(name)
|
13
|
+
git_repo_dir_cache.delete name
|
14
|
+
end
|
15
|
+
|
16
|
+
def git_repo_dir(name)
|
17
|
+
return git_repo_dir_cache[name] if git_repo_dir_cache.has_key?(name)
|
18
|
+
raise ArgumentError, "No definition for git repo #{name}" unless git_repo_setup[name]
|
19
|
+
|
20
|
+
git_dir = Pathname.new("/tmp/engineyard_test_repo_#{Time.now.tv_sec}_#{Time.now.tv_usec}_#{$$}")
|
21
|
+
git_dir.mkdir
|
22
|
+
Dir.chdir(git_dir) do
|
23
|
+
system("git init -q")
|
24
|
+
system('git config user.email ey@spec.test')
|
25
|
+
system('git config user.name "EY Specs"')
|
26
|
+
system("git remote add testremote user@git.host:path/to/repo.git")
|
27
|
+
git_repo_setup[name].call(git_dir)
|
28
|
+
end
|
29
|
+
git_repo_dir_cache[name] = git_dir
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def load_fake_awsm
|
35
|
+
config_ru = File.join(EY_ROOT, "spec/support/fake_awsm.ru")
|
36
|
+
unless system("ruby -c '#{config_ru}' > /dev/null")
|
37
|
+
raise SyntaxError, "There is a syntax error in fake_awsm.ru! fix it!"
|
38
|
+
end
|
39
|
+
@server = RealWeb.start_server_in_fork(config_ru)
|
40
|
+
"http://localhost:#{@server.port}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def git_repo_setup
|
44
|
+
@git_repo_setup ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
def git_repo_dir_cache
|
48
|
+
@git_repo_dir_cache ||= {}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/spec/support/helpers.rb
CHANGED
@@ -5,241 +5,228 @@ require 'rest_client'
|
|
5
5
|
require 'open4'
|
6
6
|
require 'stringio'
|
7
7
|
|
8
|
-
module
|
9
|
-
module
|
10
|
-
|
11
|
-
|
12
|
-
@stdout, @stderr = stdout, stderr
|
13
|
-
end
|
14
|
-
|
15
|
-
def message
|
16
|
-
"Exited with an unexpected exit code\n---STDOUT---\n#{@stdout}\n---STDERR---\n#{@stderr}\n"
|
17
|
-
end
|
8
|
+
module SpecHelpers
|
9
|
+
module Given
|
10
|
+
def given(name)
|
11
|
+
include_examples name
|
18
12
|
end
|
19
|
-
|
20
|
-
ZeroExitStatus = Class.new(UnexpectedExit)
|
13
|
+
end
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
capture_stdout_into(out) do
|
26
|
-
with_env('DEBUG' => 'true') do
|
27
|
-
EY::CLI.start(args)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
ensure
|
32
|
-
@err, @out = err.string, out.string
|
33
|
-
@raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
|
15
|
+
module Fixtures
|
16
|
+
def fixture_recipes_tgz
|
17
|
+
File.expand_path('../fixture_recipes.tgz', __FILE__)
|
34
18
|
end
|
35
19
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
rescue SystemExit => exit_status
|
41
|
-
# SystemExit typically indicates a bogus command, which we
|
42
|
-
# here in expected-to-fail land are entirely happy with.
|
43
|
-
nil
|
44
|
-
rescue EY::Error => e
|
45
|
-
more_err, more_out = StringIO.new, StringIO.new
|
46
|
-
|
47
|
-
capture_stderr_into(more_err) do
|
48
|
-
capture_stdout_into(more_out) do
|
49
|
-
EY.ui.print_exception(e)
|
50
|
-
end
|
51
|
-
end
|
20
|
+
def link_recipes_tgz(git_dir)
|
21
|
+
system("ln -s #{fixture_recipes_tgz} #{git_dir.join('recipes.tgz')}")
|
22
|
+
end
|
23
|
+
end
|
52
24
|
|
53
|
-
|
54
|
-
|
25
|
+
module IntegrationHelpers
|
26
|
+
def run_ey(command_options, ey_options={})
|
27
|
+
if respond_to?(:extra_ey_options) # needed for ssh tests
|
28
|
+
ey_options.merge!(extra_ey_options)
|
55
29
|
end
|
56
|
-
end
|
57
30
|
|
58
|
-
|
59
|
-
$stderr = stream
|
60
|
-
yield
|
61
|
-
ensure
|
62
|
-
$stderr = STDERR
|
31
|
+
ey(command_to_run(command_options), ey_options)
|
63
32
|
end
|
64
33
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
34
|
+
def make_scenario(hash)
|
35
|
+
# since nil will silently turn to empty string when interpolated,
|
36
|
+
# and there's a lot of string matching involved in integration
|
37
|
+
# testing, it would be nice to have early notification of typos.
|
38
|
+
scenario = Hash.new { |h,k| raise "Tried to get key #{k.inspect}, but it's missing!" }
|
39
|
+
scenario.merge!(hash)
|
70
40
|
end
|
41
|
+
end
|
71
42
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
ey_env['DEBUG'] = options[:debug] ? "true" : nil
|
79
|
-
end
|
43
|
+
module GitRepoHelpers
|
44
|
+
def define_git_repo(name, &setup)
|
45
|
+
# EY's ivars don't get cleared between examples, so we can keep
|
46
|
+
# a git repo around longer (and thus make our tests faster)
|
47
|
+
FakeFS.without { EY.define_git_repo(name, &setup) }
|
48
|
+
end
|
80
49
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
f.chmod(0755)
|
88
|
-
end
|
50
|
+
def use_git_repo(repo_name)
|
51
|
+
before(:all) do
|
52
|
+
FakeFS.without do
|
53
|
+
@_original_wd ||= []
|
54
|
+
@_original_wd << Dir.getwd
|
55
|
+
Dir.chdir(EY.git_repo_dir(repo_name))
|
89
56
|
end
|
57
|
+
end
|
90
58
|
|
91
|
-
|
59
|
+
after(:all) do
|
60
|
+
FakeFS.without { Dir.chdir(@_original_wd.pop) }
|
92
61
|
end
|
62
|
+
end
|
63
|
+
end
|
93
64
|
|
94
|
-
|
65
|
+
class UnexpectedExit < StandardError
|
66
|
+
def initialize(stdout, stderr)
|
67
|
+
super "Exited with an unexpected exit code\n---STDOUT---\n#{stdout}\n---STDERR---\n#{stderr}\n"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
NonzeroExitStatus = Class.new(UnexpectedExit)
|
71
|
+
ZeroExitStatus = Class.new(UnexpectedExit)
|
95
72
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
@out = stdout.read
|
100
|
-
@err = stderr.read
|
101
|
-
end
|
73
|
+
def ey_api
|
74
|
+
@api ||= EY::API.new('asdf')
|
75
|
+
end
|
102
76
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
77
|
+
def fast_ey(args)
|
78
|
+
err, out = StringIO.new, StringIO.new
|
79
|
+
capture_stderr_into(err) do
|
80
|
+
capture_stdout_into(out) do
|
81
|
+
with_env('DEBUG' => 'true') do
|
82
|
+
EY::CLI.start(args)
|
107
83
|
end
|
108
84
|
end
|
109
|
-
|
110
|
-
@raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
|
111
|
-
|
112
|
-
puts @err unless @err.empty? || hide_err
|
113
|
-
@out
|
114
85
|
end
|
86
|
+
ensure
|
87
|
+
@err, @out = err.string, out.string
|
88
|
+
@raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
|
89
|
+
end
|
115
90
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
# Its arguments have been double-escaped: one layer is to get
|
132
|
-
# them through our local shell and into ssh, and the other
|
133
|
-
# layer is to get them through the remote system's shell.
|
134
|
-
#
|
135
|
-
# Strip off one layer by running it through the shell.
|
136
|
-
just_the_remote_command = ssh_prefix_removed.gsub(/>\s*\/dev\/null.*$/, '')
|
137
|
-
`echo #{just_the_remote_command}`.strip
|
91
|
+
def fast_failing_ey(*args)
|
92
|
+
begin
|
93
|
+
fast_ey(*args)
|
94
|
+
raise ZeroExitStatus.new(@out, @err)
|
95
|
+
rescue SystemExit => exit_status
|
96
|
+
# SystemExit typically indicates a bogus command, which we
|
97
|
+
# here in expected-to-fail land are entirely happy with.
|
98
|
+
nil
|
99
|
+
rescue EY::Error => e
|
100
|
+
more_err, more_out = StringIO.new, StringIO.new
|
101
|
+
|
102
|
+
capture_stderr_into(more_err) do
|
103
|
+
capture_stdout_into(more_out) do
|
104
|
+
EY.ui.print_exception(e)
|
105
|
+
end
|
138
106
|
end
|
139
107
|
|
140
|
-
|
108
|
+
@err << more_err.string
|
109
|
+
@out << more_out.string
|
141
110
|
end
|
111
|
+
end
|
142
112
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
113
|
+
def capture_stderr_into(stream)
|
114
|
+
$stderr = stream
|
115
|
+
yield
|
116
|
+
ensure
|
117
|
+
$stderr = STDERR
|
118
|
+
end
|
147
119
|
|
148
|
-
|
149
|
-
|
150
|
-
|
120
|
+
def capture_stdout_into(stream)
|
121
|
+
$stdout = stream
|
122
|
+
yield
|
123
|
+
ensure
|
124
|
+
$stdout = STDOUT
|
125
|
+
end
|
126
|
+
|
127
|
+
def ey(args = [], options = {}, &block)
|
128
|
+
hide_err = options.has_key?(:hide_err) ? options[:hide_err] : options[:expect_failure]
|
129
|
+
path_prepends = options[:prepend_to_path]
|
151
130
|
|
152
|
-
|
153
|
-
|
131
|
+
ey_env = {'DEBUG' => 'true'}
|
132
|
+
if options.has_key?(:debug)
|
133
|
+
ey_env['DEBUG'] = options[:debug] ? "true" : nil
|
154
134
|
end
|
155
135
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
136
|
+
if path_prepends
|
137
|
+
tempdir = File.join(Dir.tmpdir, "ey_test_cmds_#{Time.now.tv_sec}#{Time.now.tv_usec}_#{$$}")
|
138
|
+
Dir.mkdir(tempdir)
|
139
|
+
path_prepends.each do |name, contents|
|
140
|
+
File.open(File.join(tempdir, name), 'w') do |f|
|
141
|
+
f.write(contents)
|
142
|
+
f.chmod(0755)
|
162
143
|
end
|
163
|
-
ENV[k] = v
|
164
144
|
end
|
165
145
|
|
166
|
-
|
146
|
+
ey_env['PATH'] = tempdir + ':' + ENV['PATH']
|
147
|
+
end
|
167
148
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
149
|
+
eybin = File.expand_path('../bundled_ey', __FILE__)
|
150
|
+
|
151
|
+
with_env(ey_env) do
|
152
|
+
exit_status = Open4::open4("#{eybin} #{Escape.shell_command(args)}") do |pid, stdin, stdout, stderr|
|
153
|
+
block.call(stdin) if block
|
154
|
+
@out = stdout.read
|
155
|
+
@err = stderr.read
|
156
|
+
end
|
157
|
+
|
158
|
+
if !exit_status.success? && !options[:expect_failure]
|
159
|
+
raise NonzeroExitStatus.new(@out, @err)
|
160
|
+
elsif exit_status.success? && options[:expect_failure]
|
161
|
+
raise ZeroExitStatus.new(@out, @err)
|
174
162
|
end
|
175
|
-
retval
|
176
163
|
end
|
177
164
|
|
165
|
+
@raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
|
166
|
+
|
167
|
+
puts @err unless @err.empty? || hide_err
|
168
|
+
@out
|
178
169
|
end
|
179
|
-
end
|
180
170
|
|
181
|
-
|
182
|
-
|
183
|
-
|
171
|
+
def extract_ssh_commands(output)
|
172
|
+
raw_ssh_commands = @out.split(/\n/).find_all do |line|
|
173
|
+
line =~ /^bash -lc/ || line =~ /^ssh/
|
174
|
+
end
|
184
175
|
|
185
|
-
|
186
|
-
|
187
|
-
|
176
|
+
ssh_commands = raw_ssh_commands.map do |cmd|
|
177
|
+
# Strip off everything up to and including user@host, leaving
|
178
|
+
# just the command that the remote system would run
|
179
|
+
#
|
180
|
+
# XXX: this is a really icky icky.
|
181
|
+
# engineyard gem was written as if shelling out to run serverside
|
182
|
+
# and running an ssh command will always be the same. This is a nasty
|
183
|
+
# hack to get it working with Net::SSH for now so we can repair 1.9.2.
|
184
|
+
ssh_prefix_removed = cmd.gsub(/^bash -lc /, '').gsub(/^ssh .*?\w+@\S*\s*/, '')
|
188
185
|
|
186
|
+
# Its arguments have been double-escaped: one layer is to get
|
187
|
+
# them through our local shell and into ssh, and the other
|
188
|
+
# layer is to get them through the remote system's shell.
|
189
|
+
#
|
190
|
+
# Strip off one layer by running it through the shell.
|
191
|
+
just_the_remote_command = ssh_prefix_removed.gsub(/>\s*\/dev\/null.*$/, '')
|
192
|
+
`echo #{just_the_remote_command}`.strip
|
189
193
|
end
|
190
194
|
|
191
|
-
|
192
|
-
|
193
|
-
File.expand_path('../fixture_recipes.tgz', __FILE__)
|
194
|
-
end
|
195
|
+
[raw_ssh_commands, ssh_commands]
|
196
|
+
end
|
195
197
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
end
|
198
|
+
def api_scenario(scenario, remote = "user@git.host:path/to/repo.git")
|
199
|
+
response = ::RestClient.put(EY.fake_awsm + '/scenario', {"scenario" => scenario, "remote" => remote}, {})
|
200
|
+
raise "Setting scenario failed: #{response.inspect}" unless response.code == 200
|
200
201
|
end
|
201
|
-
end
|
202
202
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
@fake_awsm ||= begin
|
207
|
-
config_ru = File.join(EY_ROOT, "spec/support/fake_awsm.ru")
|
208
|
-
unless system("ruby -c '#{config_ru}' > /dev/null")
|
209
|
-
raise SyntaxError, "There is a syntax error in fake_awsm.ru! fix it!"
|
210
|
-
end
|
211
|
-
@server = RealWeb.start_server_in_fork(config_ru)
|
212
|
-
"http://localhost:#{@server.port}"
|
213
|
-
end
|
214
|
-
end
|
215
|
-
alias_method :start_fake_awsm, :fake_awsm
|
203
|
+
def read_yaml(file="ey.yml")
|
204
|
+
YAML.load_file(File.expand_path(file))
|
205
|
+
end
|
216
206
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
@git_repo_setup[name] = setup
|
221
|
-
end
|
207
|
+
def write_yaml(data, file = "ey.yml")
|
208
|
+
File.open(file, "w"){|f| YAML.dump(data, f) }
|
209
|
+
end
|
222
210
|
|
223
|
-
|
224
|
-
|
225
|
-
|
211
|
+
def with_env(new_env_vars)
|
212
|
+
raise ArgumentError, "with_env takes a block" unless block_given?
|
213
|
+
old_env_vars = {}
|
214
|
+
new_env_vars.each do |k, v|
|
215
|
+
if ENV.has_key?(k)
|
216
|
+
old_env_vars[k] = ENV[k]
|
217
|
+
end
|
218
|
+
ENV[k] = v
|
226
219
|
end
|
227
220
|
|
228
|
-
|
229
|
-
@git_repo_dir_cache ||= {}
|
230
|
-
return @git_repo_dir_cache[name] if @git_repo_dir_cache.has_key?(name)
|
231
|
-
raise ArgumentError, "No definition for git repo #{name}" unless @git_repo_setup[name]
|
221
|
+
retval = yield
|
232
222
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
system('git config user.name "EY Specs"')
|
239
|
-
system("git remote add testremote user@git.host:path/to/repo.git")
|
240
|
-
@git_repo_setup[name].call(git_dir)
|
223
|
+
new_env_vars.keys.each do |k|
|
224
|
+
if old_env_vars.has_key?(k)
|
225
|
+
ENV[k] = old_env_vars[k]
|
226
|
+
else
|
227
|
+
ENV.delete(k)
|
241
228
|
end
|
242
|
-
@git_repo_dir_cache[name] = git_dir
|
243
229
|
end
|
230
|
+
retval
|
244
231
|
end
|
245
232
|
end
|