heroku_hatchet 5.0.0 → 7.0.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 +4 -4
- data/.circleci/config.yml +69 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +32 -1
- data/Gemfile +0 -1
- data/README.md +772 -205
- data/bin/hatchet +11 -4
- data/etc/ci_setup.rb +21 -15
- data/etc/setup_heroku.sh +0 -2
- data/hatchet.gemspec +4 -5
- data/hatchet.json +6 -2
- data/hatchet.lock +12 -8
- data/lib/hatchet.rb +1 -2
- data/lib/hatchet/api_rate_limit.rb +13 -24
- data/lib/hatchet/app.rb +159 -53
- data/lib/hatchet/config.rb +1 -1
- data/lib/hatchet/git_app.rb +27 -1
- data/lib/hatchet/reaper.rb +159 -56
- data/lib/hatchet/reaper/app_age.rb +49 -0
- data/lib/hatchet/reaper/reaper_throttle.rb +55 -0
- data/lib/hatchet/shell_throttle.rb +71 -0
- data/lib/hatchet/test_run.rb +16 -9
- data/lib/hatchet/version.rb +1 -1
- data/{test → repo_fixtures}/different-folder-for-checked-in-repos/default_ruby/Gemfile +0 -0
- data/spec/hatchet/allow_failure_git_spec.rb +40 -0
- data/spec/hatchet/app_spec.rb +226 -0
- data/spec/hatchet/ci_spec.rb +67 -0
- data/spec/hatchet/config_spec.rb +34 -0
- data/spec/hatchet/edit_repo_spec.rb +17 -0
- data/spec/hatchet/git_spec.rb +9 -0
- data/spec/hatchet/heroku_api_spec.rb +30 -0
- data/spec/hatchet/local_repo_spec.rb +26 -0
- data/spec/hatchet/lock_spec.rb +30 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/unit/reaper_spec.rb +153 -0
- data/spec/unit/shell_throttle.rb +28 -0
- metadata +57 -86
- data/.travis.yml +0 -16
- data/test/fixtures/buildpacks/null-buildpack/bin/compile +0 -4
- data/test/fixtures/buildpacks/null-buildpack/bin/detect +0 -5
- data/test/fixtures/buildpacks/null-buildpack/bin/release +0 -3
- data/test/fixtures/buildpacks/null-buildpack/hatchet.json +0 -4
- data/test/fixtures/buildpacks/null-buildpack/readme.md +0 -41
- data/test/hatchet/allow_failure_git_test.rb +0 -16
- data/test/hatchet/app_test.rb +0 -96
- data/test/hatchet/ci_four_test.rb +0 -19
- data/test/hatchet/ci_test.rb +0 -11
- data/test/hatchet/ci_three_test.rb +0 -9
- data/test/hatchet/ci_too_test.rb +0 -19
- data/test/hatchet/config_test.rb +0 -51
- data/test/hatchet/edit_repo_test.rb +0 -20
- data/test/hatchet/git_test.rb +0 -16
- data/test/hatchet/heroku_api_test.rb +0 -30
- data/test/hatchet/labs_test.rb +0 -20
- data/test/hatchet/local_repo_test.rb +0 -26
- data/test/hatchet/lock_test.rb +0 -9
- data/test/hatchet/multi_cmd_runner_test.rb +0 -30
- data/test/test_helper.rb +0 -28
data/lib/hatchet/test_run.rb
CHANGED
@@ -181,10 +181,11 @@ module Hatchet
|
|
181
181
|
|
182
182
|
source_put_url = @app.create_source
|
183
183
|
Hatchet::RETRIES.times.retry do
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
184
|
+
PlatformAPI.rate_throttle.call do
|
185
|
+
Excon.put(source_put_url,
|
186
|
+
expects: [200],
|
187
|
+
body: File.read('slug.tgz'))
|
188
|
+
end
|
188
189
|
end
|
189
190
|
end
|
190
191
|
return @app.source_get_url
|
@@ -192,8 +193,11 @@ module Hatchet
|
|
192
193
|
|
193
194
|
private
|
194
195
|
def get_contents_or_whatever(url)
|
195
|
-
|
196
|
-
|
196
|
+
response = PlatformAPI.rate_throttle.call do
|
197
|
+
Excon.get(url, read_timeout: @pause)
|
198
|
+
end
|
199
|
+
|
200
|
+
return response.body
|
197
201
|
rescue Excon::Error::Timeout
|
198
202
|
""
|
199
203
|
end
|
@@ -214,11 +218,14 @@ module Hatchet
|
|
214
218
|
"Content-Type" => "application/json"
|
215
219
|
}.merge(options[:headers] || {})
|
216
220
|
options[:body] = JSON.generate(options[:body]) if options[:body]
|
221
|
+
options[:expects] << 429 if options[:expects]
|
217
222
|
|
218
223
|
Hatchet::RETRIES.times.retry do
|
219
|
-
|
220
|
-
|
221
|
-
|
224
|
+
PlatformAPI.rate_throttle.call do
|
225
|
+
connection = Excon.new("https://api.heroku.com")
|
226
|
+
|
227
|
+
connection.request(options)
|
228
|
+
end
|
222
229
|
end
|
223
230
|
end
|
224
231
|
end
|
data/lib/hatchet/version.rb
CHANGED
File without changes
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require("spec_helper")
|
2
|
+
|
3
|
+
describe "AllowFailureGitTest" do
|
4
|
+
describe "release failures" do
|
5
|
+
let(:release_fail_proc) {
|
6
|
+
Proc.new do
|
7
|
+
File.open("Procfile", "w+") do |f|
|
8
|
+
f.write <<~EOM
|
9
|
+
release: echo "failing on release" && exit 1
|
10
|
+
EOM
|
11
|
+
end
|
12
|
+
end
|
13
|
+
}
|
14
|
+
|
15
|
+
it "is marked as a failure if the release fails" do
|
16
|
+
expect {
|
17
|
+
Hatchet::GitApp.new("default_ruby", before_deploy: release_fail_proc).deploy {}
|
18
|
+
}.to(raise_error(Hatchet::App::FailedReleaseError))
|
19
|
+
end
|
20
|
+
|
21
|
+
it "works when failure is allowed" do
|
22
|
+
Hatchet::GitApp.new("default_ruby", before_deploy: release_fail_proc, allow_failure: true).deploy do |app|
|
23
|
+
expect(app.output).to match("failing on release")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "allowed failure" do
|
29
|
+
Hatchet::GitApp.new("no_lockfile", allow_failure: true).deploy do |app|
|
30
|
+
expect(app.deployed?).to be_falsey
|
31
|
+
expect(app.output).to match("Gemfile.lock required")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "failure with no flag" do
|
36
|
+
expect {
|
37
|
+
Hatchet::GitApp.new("no_lockfile").deploy {}
|
38
|
+
}.to(raise_error(Hatchet::App::FailedDeploy))
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require("spec_helper")
|
2
|
+
|
3
|
+
describe "AppTest" do
|
4
|
+
it "rate throttles `git push` " do
|
5
|
+
app = Hatchet::GitApp.new("default_ruby")
|
6
|
+
def app.git_push_heroku_yall
|
7
|
+
@_git_push_heroku_yall_call_count ||= 0
|
8
|
+
@_git_push_heroku_yall_call_count += 1
|
9
|
+
if @_git_push_heroku_yall_call_count >= 2
|
10
|
+
"Success"
|
11
|
+
else
|
12
|
+
raise Hatchet::App::FailedDeployError.new(self, "message", output: "Your account reached the API rate limit Please wait a few minutes before making new requests")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def app.sleep_called?; @sleep_called; end
|
17
|
+
|
18
|
+
def app.what_is_git_push_heroku_yall_call_count; @_git_push_heroku_yall_call_count; end
|
19
|
+
app.push_without_retry!
|
20
|
+
|
21
|
+
expect(app.what_is_git_push_heroku_yall_call_count).to be(2)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "calls reaper if cannot create an app" do
|
25
|
+
app = Hatchet::App.new("default_ruby", buildpacks: [:default])
|
26
|
+
def app.heroku_api_create_app(*args); raise StandardError.new("made you look"); end
|
27
|
+
|
28
|
+
reaper = app.reaper
|
29
|
+
|
30
|
+
def reaper.cycle(app_exception_message: ); @app_exception_message = app_exception_message; end
|
31
|
+
def reaper.recorded_app_exception_message; @app_exception_message; end
|
32
|
+
|
33
|
+
expect {
|
34
|
+
app.create_app
|
35
|
+
}.to raise_error("made you look")
|
36
|
+
|
37
|
+
expect(reaper.recorded_app_exception_message).to match("made you look")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "app with default" do
|
41
|
+
app = Hatchet::App.new("default_ruby", buildpacks: [:default])
|
42
|
+
expect(app.buildpacks.first).to match("https://github.com/heroku/heroku-buildpack-ruby")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "create app with stack" do
|
46
|
+
stack = "heroku-16"
|
47
|
+
app = Hatchet::App.new("default_ruby", stack: stack)
|
48
|
+
app.create_app
|
49
|
+
expect(app.platform_api.app.info(app.name)["build_stack"]["name"]).to eq(stack)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "marks itself 'finished' when done in block mode" do
|
53
|
+
app = Hatchet::Runner.new("default_ruby")
|
54
|
+
|
55
|
+
def app.push_with_retry!; nil; end
|
56
|
+
app.deploy do |app|
|
57
|
+
expect(app.platform_api.app.info(app.name)["maintenance"]).to be_falsey
|
58
|
+
end
|
59
|
+
|
60
|
+
# After the app is updated, there's no guarantee it will still exist
|
61
|
+
# so we cannot rely on an api call to determine maintenance mode
|
62
|
+
app_update_info = app.instance_variable_get(:"@app_update_info")
|
63
|
+
expect(app_update_info["name"]).to eq(app.name)
|
64
|
+
expect(app_update_info["maintenance"]).to be_truthy
|
65
|
+
end
|
66
|
+
|
67
|
+
it "marks itself 'finished' when done in non-block mode" do
|
68
|
+
app = Hatchet::Runner.new("default_ruby")
|
69
|
+
|
70
|
+
def app.push_with_retry!; nil; end
|
71
|
+
app.deploy
|
72
|
+
expect(app.platform_api.app.info(app.name)["maintenance"]).to be_falsey
|
73
|
+
|
74
|
+
app.teardown!
|
75
|
+
|
76
|
+
# After the app is updated, there's no guarantee it will still exist
|
77
|
+
# so we cannot rely on an api call to determine maintenance mode
|
78
|
+
app_update_info = app.instance_variable_get(:"@app_update_info")
|
79
|
+
expect(app_update_info["name"]).to eq(app.name)
|
80
|
+
expect(app_update_info["maintenance"]).to be_truthy
|
81
|
+
end
|
82
|
+
|
83
|
+
it "before deploy" do
|
84
|
+
@called = false
|
85
|
+
@dir = false
|
86
|
+
app = Hatchet::App.new("default_ruby")
|
87
|
+
def app.push_with_retry!
|
88
|
+
# do nothing
|
89
|
+
end
|
90
|
+
app.before_deploy do
|
91
|
+
@called = true
|
92
|
+
@dir = Dir.pwd
|
93
|
+
end
|
94
|
+
app.deploy do
|
95
|
+
expect(@called).to eq(true)
|
96
|
+
expect(@dir).to eq(Dir.pwd)
|
97
|
+
end
|
98
|
+
expect(@dir).to_not eq(Dir.pwd)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "auto commits code" do
|
102
|
+
string = "foo#{SecureRandom.hex}"
|
103
|
+
app = Hatchet::App.new("default_ruby")
|
104
|
+
def app.push_with_retry!
|
105
|
+
# do nothing
|
106
|
+
end
|
107
|
+
app.before_deploy do |app|
|
108
|
+
expect(app.send(:needs_commit?)).to eq(false)
|
109
|
+
`echo "#{string}" > Gemfile`
|
110
|
+
expect(app.send(:needs_commit?)).to eq(true)
|
111
|
+
end
|
112
|
+
app.deploy do
|
113
|
+
expect(File.read("Gemfile").chomp).to eq(string)
|
114
|
+
expect(app.send(:needs_commit?)).to eq(false)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
it "nested in directory" do
|
119
|
+
string = "foo#{SecureRandom.hex}"
|
120
|
+
app = Hatchet::App.new("default_ruby")
|
121
|
+
def app.push_with_retry!
|
122
|
+
# do nothing
|
123
|
+
end
|
124
|
+
app.in_directory do
|
125
|
+
`echo "#{string}" > Gemfile`
|
126
|
+
dir = Dir.pwd
|
127
|
+
app.deploy do
|
128
|
+
expect(File.read("Gemfile").chomp).to eq(string)
|
129
|
+
expect(dir).to eq(Dir.pwd)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "run" do
|
135
|
+
skip("Must set HATCHET_EXPENSIVE_MODE") unless ENV["HATCHET_EXPENSIVE_MODE"]
|
136
|
+
|
137
|
+
app = Hatchet::GitApp.new("default_ruby", run_multi: true)
|
138
|
+
app.deploy do
|
139
|
+
expect(app.run("ls -a Gemfile 'foo bar #baz'")).to match(/ls: cannot access 'foo bar #baz': No such file or directory\s+Gemfile/)
|
140
|
+
expect((0 != $?.exitstatus)).to be_truthy
|
141
|
+
|
142
|
+
app.run("ls erpderp", heroku: ({ "exit-code" => (Hatchet::App::SkipDefaultOption) }))
|
143
|
+
expect((0 == $?.exitstatus)).to be_truthy
|
144
|
+
|
145
|
+
app.run("ls erpderp", heroku: ({ "no-tty" => nil }))
|
146
|
+
expect((0 != $?.exitstatus)).to be_truthy
|
147
|
+
|
148
|
+
expect(app.run("echo \\$HELLO \\$NAME", raw: true, heroku: ({ "env" => "HELLO=ohai;NAME=world" }))).to match(/ohai world/)
|
149
|
+
|
150
|
+
expect(app.run("echo \\$HELLO \\$NAME", raw: true, heroku: ({ "env" => "" }))).to_not match(/ohai world/)
|
151
|
+
|
152
|
+
random_name = SecureRandom.hex
|
153
|
+
expect(app.run("mkdir foo; touch foo/#{random_name}; ls foo/")).to match(/#{random_name}/)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class AtomicCount
|
158
|
+
attr_reader :value
|
159
|
+
|
160
|
+
def initialize(value)
|
161
|
+
@value = value
|
162
|
+
@mutex = Mutex.new
|
163
|
+
end
|
164
|
+
|
165
|
+
# In MRI the `+=` is not atomic, it is two seperate virtual machine
|
166
|
+
# instructions. To protect against race conditions, we can lock with a mutex
|
167
|
+
def add(val)
|
168
|
+
@mutex.synchronize do
|
169
|
+
@value += val
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
it "run multi" do
|
175
|
+
skip("Must set HATCHET_EXPENSIVE_MODE") unless ENV["HATCHET_EXPENSIVE_MODE"]
|
176
|
+
|
177
|
+
@run_count = AtomicCount.new(0)
|
178
|
+
app = Hatchet::GitApp.new("default_ruby", run_multi: true)
|
179
|
+
app.deploy do
|
180
|
+
app.run_multi("ls") { |out| expect(out).to include("Gemfile"); @run_count.add(1) }
|
181
|
+
app.run_multi("blerg -v") { |_, status| expect(status.success?).to be_falsey; @run_count.add(1) }
|
182
|
+
app.run_multi("ruby -v") do |out, status|
|
183
|
+
expect(out).to include("ruby")
|
184
|
+
expect(status.success?).to be_truthy
|
185
|
+
|
186
|
+
@run_count.add(1)
|
187
|
+
end
|
188
|
+
|
189
|
+
expect(app.platform_api.formation.list(app.name).detect {|ps| ps["type"] == "web"}["size"].downcase).to_not eq("free")
|
190
|
+
end
|
191
|
+
|
192
|
+
# After the deploy block exits `teardown!` is called
|
193
|
+
# this ensures all `run_multi` commands have exited and the dyno should be scaled down
|
194
|
+
expect(@run_count.value).to eq(3)
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "running concurrent tests in different examples works" do
|
198
|
+
# This is not a great pattern if we're running tests via a parallel runner
|
199
|
+
#
|
200
|
+
# For example this will be guaranteed to be called, not just once, but at least once for every process
|
201
|
+
# that needs to run a test. In the best case it will only fire once, in the worst case it will fire N times
|
202
|
+
# if there are N tests. It is effectively the same as a `before(:each)`
|
203
|
+
#
|
204
|
+
# Documented here: https://github.com/grosser/parallel_split_test/pull/22/files
|
205
|
+
before(:all) do
|
206
|
+
skip("Must set HATCHET_EXPENSIVE_MODE") unless ENV["HATCHET_EXPENSIVE_MODE"]
|
207
|
+
|
208
|
+
@app = Hatchet::GitApp.new("default_ruby", run_multi: true)
|
209
|
+
@app.deploy
|
210
|
+
end
|
211
|
+
|
212
|
+
after(:all) do
|
213
|
+
@app.teardown! if @app
|
214
|
+
end
|
215
|
+
|
216
|
+
it "test one" do
|
217
|
+
expect(@app.run("ls")).to include("Gemfile")
|
218
|
+
expect(@app.platform_api.formation.list(@app.name).detect {|ps| ps["type"] == "web"}["size"].downcase).to_not eq("free")
|
219
|
+
end
|
220
|
+
|
221
|
+
it "test two" do
|
222
|
+
expect(@app.run("ruby -v")).to include("ruby")
|
223
|
+
expect(@app.platform_api.formation.list(@app.name).detect {|ps| ps["type"] == "web"}["size"].downcase).to_not eq("free")
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "CIFourTest" do
|
4
|
+
it "error with bad app" do
|
5
|
+
string = SecureRandom.hex
|
6
|
+
|
7
|
+
app = Hatchet::GitApp.new("default_ruby")
|
8
|
+
app.run_ci do |test_run|
|
9
|
+
expect(test_run.output).to_not match(string)
|
10
|
+
expect(test_run.output).to match("Installing rake")
|
11
|
+
|
12
|
+
run!("echo 'puts \"#{string}\"' >> Rakefile")
|
13
|
+
test_run.run_again
|
14
|
+
|
15
|
+
expect(test_run.output).to match(string)
|
16
|
+
expect(test_run.output).to match("Using rake")
|
17
|
+
expect(test_run.output).to_not match("Installing rake")
|
18
|
+
|
19
|
+
expect(app.platform_api.app.info(app.name)["maintenance"]).to be_falsey
|
20
|
+
end
|
21
|
+
|
22
|
+
# After the app is updated, there's no guarantee it will still exist
|
23
|
+
# so we cannot rely on an api call to determine maintenance mode
|
24
|
+
app_update_info = app.instance_variable_get(:"@app_update_info")
|
25
|
+
expect(app_update_info["name"]).to eq(app.name)
|
26
|
+
expect(app_update_info["maintenance"]).to be_truthy
|
27
|
+
end
|
28
|
+
|
29
|
+
it "error with bad app" do
|
30
|
+
expect {
|
31
|
+
Hatchet::GitApp.new("rails5_ci_fails_no_database").run_ci { }
|
32
|
+
}.to raise_error(/PG::ConnectionBad: could not connect to server/)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "error with bad app" do
|
36
|
+
@before_deploy_called = false
|
37
|
+
@before_deploy_dir_pwd = nil
|
38
|
+
|
39
|
+
before_deploy = -> do
|
40
|
+
@before_deploy_called = true
|
41
|
+
@before_deploy_dir_pwd = Dir.pwd
|
42
|
+
end
|
43
|
+
|
44
|
+
Hatchet::GitApp.new("rails5_ci_fails_no_database", allow_failure: true, before_deploy: before_deploy).run_ci do |test_run|
|
45
|
+
expect(test_run.status).to eq(:errored)
|
46
|
+
expect(@before_deploy_dir_pwd).to eq(Dir.pwd)
|
47
|
+
expect(@before_deploy_called).to be_truthy
|
48
|
+
end
|
49
|
+
|
50
|
+
expect(@before_deploy_dir_pwd).to_not eq(Dir.pwd)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "ci create app with stack" do
|
54
|
+
app = Hatchet::GitApp.new("rails5_ruby_schema_format")
|
55
|
+
app.run_ci do |test_run|
|
56
|
+
expect(test_run.output).to match("Ruby buildpack tests completed successfully")
|
57
|
+
expect(test_run.status).to eq(:succeeded)
|
58
|
+
expect(app.pipeline_id).to_not be_nil
|
59
|
+
|
60
|
+
api_rate_limit = app.api_rate_limit.call
|
61
|
+
couplings = api_rate_limit.pipeline_coupling.list_by_pipeline(app.pipeline_id)
|
62
|
+
coupled_app = api_rate_limit.app.info(couplings.first["app"]["id"])
|
63
|
+
expect(coupled_app["name"]).to eq(app.name)
|
64
|
+
end
|
65
|
+
expect(app.pipeline_id).to be_nil
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require("spec_helper")
|
2
|
+
describe "ConfigTest" do
|
3
|
+
before { @config = Hatchet::Config.new }
|
4
|
+
|
5
|
+
it("config path for name") do
|
6
|
+
expect(@config.path_for_name("rails3_mri_193")).to(eq("repo_fixtures/repos/rails3/rails3_mri_193"))
|
7
|
+
end
|
8
|
+
|
9
|
+
it("config dirs") do
|
10
|
+
{ "repo_fixtures/repos/bundler/no_lockfile" => "https://github.com/sharpstone/no_lockfile.git", "repo_fixtures/repos/default/default_ruby" => "https://github.com/sharpstone/default_ruby.git", "repo_fixtures/repos/rails2/rails2blog" => "https://github.com/sharpstone/rails2blog.git", "repo_fixtures/repos/rails3/rails3_mri_193" => "https://github.com/sharpstone/rails3_mri_193.git" }.each do |key, value|
|
11
|
+
assert_include(key, value, @config.dirs)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it("config repos") do
|
16
|
+
{ "default_ruby" => "repo_fixtures/repos/default/default_ruby", "no_lockfile" => "repo_fixtures/repos/bundler/no_lockfile", "rails2blog" => "repo_fixtures/repos/rails2/rails2blog", "rails3_mri_193" => "repo_fixtures/repos/rails3/rails3_mri_193" }.each do |key, value|
|
17
|
+
assert_include(key, value, @config.repos)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it("no internal config raises no errors") do
|
22
|
+
@config.send(:set_internal_config!, {})
|
23
|
+
expect(@config.repo_directory_path).to(eq("./repos"))
|
24
|
+
end
|
25
|
+
|
26
|
+
it("github shortcuts") do
|
27
|
+
@config.send(:init_config!, "foo" => (["schneems/sextant"]))
|
28
|
+
expect(@config.dirs["./repos/foo/sextant"]).to(eq("https://github.com/schneems/sextant.git"))
|
29
|
+
end
|
30
|
+
|
31
|
+
private def assert_include(key, value, actual)
|
32
|
+
expect(actual[key]).to eq(value), "Expected #{actual.inspect} to include #{{ key => value }} but it did not"
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require("spec_helper")
|
2
|
+
describe "EditRepoTest" do
|
3
|
+
it "can deploy git app" do
|
4
|
+
Hatchet::GitApp.new("default_ruby").in_directory do |app|
|
5
|
+
`touch foo`
|
6
|
+
expect($?.success?).to(eq(true))
|
7
|
+
|
8
|
+
`git add .; git commit -m foo`
|
9
|
+
expect($?.success?).to(eq(true))
|
10
|
+
expect(`ls`).to(match("foo"))
|
11
|
+
end
|
12
|
+
|
13
|
+
Hatchet::GitApp.new("default_ruby").in_directory do |app|
|
14
|
+
expect(`ls`).to_not match(/foo/)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|